C ++ Почему этот переданный по ссылке массив генерирует ошибку времени выполнения?

StackOverflow https://stackoverflow.com/questions/469892

  •  19-08-2019
  •  | 
  •  

Вопрос

void pushSynonyms (string synline,  char  matrizSinonimos [1024][1024]){


             stringstream synstream(synline);

             vector<int> synsAux;


             int num;

             while (synstream >> num) {synsAux.push_back(num);}


             int index=0;
             while (index<(synsAux.size()-1)){

                   int primerSinonimo=synsAux[index];
                   int segundoSinonimo=synsAux[++index];
                   matrizSinonimos[primerSinonimo][segundoSinonimo]='S';
                   matrizSinonimos [segundoSinonimo][primerSinonimo]='S';

                   }

           } 

и звонок ..

char matrizSinonimos[1024][1024];
     pushSynonyms("1 7", matrizSinonimos)

Мне важно передать matrizSinonimos по ссылке.

Редактировать: забрал & amp; от &matrizSinonimos.

Изменить: ошибка во время выполнения:

An unhandled win32 exception occurred in program.exe [2488]![alt text][1]
Это было полезно?

Решение

Что с этим не так

Код, который у вас есть - я не могу найти ошибку. Единственная проблема, которую я замечаю, заключается в том, что если вы вообще не предоставите номер, то эта часть причинит вред:

(synsAux.size()-1)

Это вычтет один из 0u. Это обернется, потому что size() возвращает целочисленный тип без знака. В итоге вы получите очень большое значение, где-то около 2 ^ 16 или 2 ^ 32. Вы должны изменить целое условие while на

while ((index+1) < synsAux.size())

Вы можете попытаться найти ошибку вокруг стороны вызова. Часто бывает, что где-то до этого происходит переполнение буфера или повреждение кучи, и в результате этого происходит сбой программы на более позднем этапе программы.

Аргументы и параметры в нем

Что касается массива и того, как он передается, я думаю, вы все делаете правильно. Хотя вы все равно передаете массив по значению. Может быть, вы уже знаете это, но я повторю это. Вы действительно передаете указатель на первый элемент этого массива:

char matrizSinonimos[1024][1024];

2d массив - это массив массивов. Первый элемент этого массива - это массив, а указатель на него - указатель на массив. В этом случае это

char (*)[1024]

Несмотря на то, что в списке параметров вы сказали, что вы принимаете массив массивов, компилятор, как всегда, корректирует это и делает его указателем на первый элемент такого массива. Таким образом, в действительности у вашей функции есть прототип, после того как компилятор выполнит корректировку типов аргументов:

void pushSynonyms (string synline,  char (*matrizSinonimos)[1024]);

Несмотря на то, что это часто предлагается, Вы не можете передать этот массив как char** , потому что вызываемой функции необходим размер внутреннего измерения, чтобы правильно адресовать подразмеры с правильными смещениями. Работая с matrizSinonimos[0][1] в вызываемой функции, а затем записывая что-то вроде <=>, он попытается интерпретировать первые символы sizeof (char **) этого массива как указатель и попытается разыменовать случайную ячейку памяти затем делаю это во второй раз, если между ними не произойдет сбой. Не делай этого . Также не имеет значения, какой размер вы записали во внешнем измерении этого массива. Это рационализировало прочь. Теперь не очень важно передавать массив по ссылке. Но если вы хотите, вы должны изменить всю вещь на

void pushSynonyms (string synline,  char (&matrizSinonimos)[1024][1024]);

Передача по ссылке не передает указатель на первый элемент: все размеры всех измерений сохраняются, и передается сам объект массива, а не значение.

Другие советы

Массивы передаются как указатели - нет необходимости передавать их по ссылке. Если вы объявите свою функцию следующим образом:

void pushSynonyms(string synline, char matrizSinonimos[][1024]);

Ваши изменения в массиве сохранятся - массивы никогда не передаются по значению.

Исключение, вероятно, 0xC00000FD или переполнение стека!

Проблема в том, что вы создаете массив размером 1 МБ в стеке, который, вероятно, слишком велик.

попробуйте объявить его как

void pushSynonyms (const string & synline,  char  *matrizSinonimos[1024] )

Я верю, что сделаю то, что ты хочешь сделать. То, как вы это делаете, как уже говорили другие, создает в стек массив размером 1 МБ. Кроме того, изменение синхронизации с string на const string & исключает добавление полной копии строки в стек.

Кроме того, я бы использовал какой-то класс для инкапсуляции matrizSinonimos. Что-то вроде:

class ms
{
    char m_martix[1024][1024];
    public:
    pushSynonyms( const string & synline );
}

тогда вам вообще не нужно его пропускать.

Я в растерянности из-за того, что не так с кодом выше, но если вы не можете заставить работать синтаксис массива, вы всегда можете сделать это:

void pushSynonyms (string synline,  char  *matrizSinonimos, int rowsize, int colsize )
{
   // the code below is equivalent to 
   // char c = matrizSinonimos[a][b];
   char c = matrizSinonimos( a*rowsize + b );
   // you could also Assert( a < rowsize && b < colsize );
}

pushSynonyms( "1 7", matrizSinonimos, 1024, 1024 );

Вы также можете заменить размер строки и объединение на #define SYNONYM_ARRAY_DIMENSION 1024, если он известен во время компиляции, что ускорит этап умножения.

( изменить 1 ) я забыл ответить на ваш фактический вопрос. Что ж: после того, как вы исправили код для правильной передачи массива (больше нет неправильного косвенного обращения), мне кажется наиболее вероятным, что вы не правильно проверили свои входные данные. Вы читаете из потока, сохраняете его в вектор, но никогда не проверяли, действительно ли все полученные числа находятся в правильном диапазоне. ( конец редактирования 1 )

Первая : Использование сырых массивов может оказаться не тем, что вы на самом деле хотите. Есть std::vector или boost::array. Последний - это массив фиксированного размера во время компиляции, такой как raw-массив, но он предоставляет определения типов и методы коллекции C ++, что удобно для универсального (читай: шаблонизированного) кода.

И при использовании этих классов может быть меньше путаницы в отношении безопасности типов, передачи по ссылке, по значению или передачи указателя.

Второй : Массивы передаются как указатели, сам указатель передается по значению.

Третий : Вы должны размещать такие большие объекты в куче. Затраты на выделение кучи в таком случае незначительны, и это уменьшит вероятность исчерпания стекового пространства.

Четвертое

void someFunction(int array[10][10]);

действительно есть:

( изменить 2 ) благодаря комментариям:

void someFunction (int ** array);

void someFunction(int (*array)[10]);

Надеюсь, я не облажался в другом месте .... ( конец редактирования 2 )

Информация о типе для массива 10x10 теряется. Чтобы получить то, что вы, вероятно, имели в виду, вам нужно написать:

void someFunction(int (&array)[10][10]);

Таким образом, компилятор может проверить, что на стороне вызывающей стороны массив на самом деле является массивом 10x10. Затем вы можете вызвать функцию следующим образом:

int main() {
  int array[10][10] = { 0 };
  someFunction(array);
  return 0;
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top