Valgrind сообщает о SIGSEGV и использовании неинициализированного значения - PullRequest
0 голосов
/ 30 июня 2018

Редактировать: все ошибки valgrind устраняются путем инициализации i.


Я работаю со строками; чтение строк из файла, разделение их с помощью strsep(), преобразование их в int с использованием atol(). Мой код компилируется на gcc и выполняется без ошибок, но при проверке с помощью valgrind я получаю ошибку, упомянутую в заголовке.

Я пытаюсь заполнить двумерный массив grid[20][20] значениями int из текстового файла. Текстовый файл содержит строки чисел, разделенных пробелами, что-то вроде 20 81 65 07 54 72 13 28 66 95 00 20 00 84 06 30 85 43 15 73\n

Мой код (за исключением всех файловых операций ввода-вывода) приведен ниже. (Обратите внимание, что я правильно обрабатываю файл: проверяю результат fopen, закрывая fclose).

Обновленный код

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define STR_LEN     20
#define NUM_LINES   20
#define MAX_SIZE    100

int main(void){
    char input_str[MAX_SIZE];   //string to hold lines read from file
    char * str_array[STR_LEN];  //array of strings to split the lines into
    int grid[20][20];
    char * token, *str, *tofree;
    int line;
    for (line = 0; line < NUM_LINES; ++line){   //for every line in the file 

        if (fgets(input_str, MAX_SIZE, fp)!=NULL){  //read the file's line into input_str
            tofree = str = strdup(input_str);   //set str to copy of input_string, and tofree to point to beginning of str's memory, to free later

            int i = 0;
            while ((token = strsep(&str, " "))){    //split str on " ", keeping everything in between in token
                str_array[i] = token;   //add token to str_array
                ++i;
            }
            for (i = 0; i < STR_LEN; ++i){
                grid[line][i] = atol(str_array[i]); //convert strings to int and store in num_array     
                printf("grid[%d][%d]: %d\n", line, i, grid[line][i]);

            }
            free(tofree);   //free str by freeing tofree, as tofree points to str's memory
        }
    }
    printf("%d", grid[0][0]);
    return 0;
}

Я компилирую этот код с gcc -Wall -g -c myfile.c. Он компилируется и работает нормально, без ошибок. Проверка значений с использованием printf() сразу после того, как значения были переданы в grid, показывает все правильные значения. Однако , последний printf() в коде показывает, что grid[0][0] содержит мусор, хотя это было правильно ранее. Фактически все элементы в grid[0] были повреждены.

Запуск Valgrind с valgrind --leak-check=full --track-origins=yes --dsymutil=yes --show-leak-kinds=all ./productGrid.elf дает мне

$ valgrind --leak-check=full --track-origins=yes --dsymutil=yes --show-leak-kinds=all ./productGrid.elf

==2252== Command: ./productGrid.elf
==2252== 
==2252== Use of uninitialised value of size 4
==2252==    at 0x106EC: main (in /home/jesse/C/Proj. Euler/productGrid.elf)
==2252==  Uninitialised value was created by a stack allocation
==2252==    at 0x10656: main (in /home/jesse/C/Proj. Euler/productGrid.elf)
==2252== 
==2252== Invalid write of size 4
==2252==    at 0x106EC: main (in /home/jesse/C/Proj. Euler/productGrid.elf)
==2252==  Address 0x7e2b6c38 is not stack'd, malloc'd or (recently) free'd
==2252== 
==2252== 
==2252== Process terminating with default action of signal 11 (SIGSEGV)
==2252==  Access not within mapped region at address 0x7E2B6C38
==2252==    at 0x106EC: main (in /home/jesse/C/Proj. Euler/productGrid.elf)
==2252==  If you believe this happened as a result of a stack
==2252==  overflow in your program's main thread (unlikely but
==2252==  possible), you can try to increase the size of the
==2252==  main thread stack using the --main-stacksize= flag.
==2252==  The main thread stack size used in this run was 8388608.
==2252== 
==2252== HEAP SUMMARY:
==2252==     in use at exit: 413 bytes in 2 blocks
==2252==   total heap usage: 3 allocs, 1 frees, 4,509 bytes allocated
==2252== 
==2252== 61 bytes in 1 blocks are still reachable in loss record 1 of 2
==2252==    at 0x483E380: malloc (vg_replace_malloc.c:299)
==2252==    by 0x48E188B: strdup (strdup.c:42)
==2252==    by 0x106C9: main (in /home/jesse/C/Proj. Euler/productGrid.elf)
==2252== 
==2252== 352 bytes in 1 blocks are still reachable in loss record 2 of 2
==2252==    at 0x483E380: malloc (vg_replace_malloc.c:299)
==2252==    by 0x48D11F3: __fopen_internal (iofopen.c:69)
==2252==    by 0x10681: main (in /home/jesse/C/Proj. Euler/productGrid.elf)
==2252== 
==2252== LEAK SUMMARY:
==2252==    definitely lost: 0 bytes in 0 blocks
==2252==    indirectly lost: 0 bytes in 0 blocks
==2252==      possibly lost: 0 bytes in 0 blocks
==2252==    still reachable: 413 bytes in 2 blocks
==2252==         suppressed: 0 bytes in 0 blocks
==2252== 
==2252== For counts of detected and suppressed errors, rerun with: -v
==2252== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 6 from 3)
Segmentation fault

Есть идеи, что я делаю не так?

Ответы [ 3 ]

0 голосов
/ 30 июня 2018

Я не могу комментировать, поэтому я публикую новый ответ. Как сказал @alk, i он неинициализирован, и если вы просто инициализируете его в определении, время не будет работать. Используйте for(;;), так как вам нужно назначение.

Обновите ваш код, если у вас все еще есть проблемы.

0 голосов
/ 30 июня 2018

Вы должны инициализировать i в начале.

Также об этом куске кода:

while ((token = strsep(&str, " "))){
    str_array[i] = token;   //add token to str_array
    ++i;
 }

for (i = 0; i < STR_LEN; ++i){
     grid[line][i] = atol(str_array[i]);
     printf("grid[%d][%d]: %d\n", line, i, grid[line][i]);
}

почему вы считаете i, если собираетесь обнулить его ниже? Возможно, вам следует использовать другой счетчик и цикл до этого, а не STR_LEN.

Надеюсь, это поможет.

0 голосов
/ 30 июня 2018

i используется здесь без инициализации:

  str_array[i] = token; 
  ++i;

Примечание:

Если вы компилируете с символами (опция -g для GCC), тогда Valgrind аннотирует свою регистрацию ссылками на исходные строки.

...