C ++ Почему этот переданный по ссылке массив генерирует ошибку времени выполнения? - PullRequest
0 голосов
/ 22 января 2009
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 по ссылке.

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

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

An unhandled win32 exception occurred in program.exe [2488]![alt text][1]

Ответы [ 6 ]

5 голосов
/ 22 января 2009

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

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

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

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

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

4 голосов
/ 22 января 2009

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

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

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

3 голосов
/ 22 января 2009

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

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

0 голосов
/ 22 января 2009

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

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, если он известен во время компиляции, что ускорит этап умножения.

0 голосов
/ 22 января 2009

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

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 );
}

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

0 голосов
/ 22 января 2009

( edit 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;
}
...