2015-11-08 3 views
3

=========================fscanf (код) не всегда сбой памяти, но иногда

код (имя файла теста .c)

#include<stdio.h> 
#include<stdlib.h> 
#include<string.h> 
int main(int argc, char * argv[]) { 
    int i=0, num=atoi(argv[1]); 
    char **arr=(char**)malloc(num*sizeof(char*)); 
    FILE *fp = fopen("test.txt","r"); 
    if(arr == NULL) { printf("out of memory\n"); exit(1); } 
    if(fp == NULL) { printf("cannot open the file \n"); exit(1); } 

    for(i=0; i< num; i++) fscanf(fp,"%s", arr+i); // HERE 
    printf("%s\n", arr+num-1); 

    fclose(fp); 
    free(arr); 
    return 0; 
} 

========

test.txt

watermelon 
grape 
strawberries 
orange 
peach 
banana 
mango 
cherry 
pineapple 
apple 
blueberry 
raspberry 
pear 
melon 
greengrapes 
tangerine 
kiwifruit 
pomegranate 
plum 
nectarine 

========

Вопрос

когда я excuted ниже в несколько раз

test 1 
test 2 
... 
... 
test 7 
test 8 

он крушит часто что-то вроде «дамп», но работает, как я ожидал.

Однако, когда я типа выше, чем 9, он никогда не раздавить ...

test 9 
test 10 
... 

enter image description here

что делает этот сбой кода?

+4

FYI: Если ваш код действительно раздавил что-то, вам будет намного больше беспокоиться. Слово, которое вы хотите, - _crash_;) – szczurcio

+0

Я сожалею о раздавлении, я имел в виду авария, –

+0

@alexparkjw Тогда почему вы не исправились? –

ответ

1
#include<stdio.h> 
#include<stdlib.h> 
#include<string.h> 

int main(int argc, const char * argv[]) 
{ 
    int i = 0, num = atoi(argv[1]); 
    char** arr = (char**)malloc(num * sizeof(char*)); 
    for (int j = 0; j < num; j++) { 
     arr[j] = (char*)malloc(100 * sizeof(char)); 
    } 
    FILE* fp = fopen("test.txt", "r"); 
    if (arr == NULL) { 
     printf("out of memory\n"); 
     exit(1); 
    } 
    if (fp == NULL) { 
     printf("cannot open the file\n"); 
     exit(1); 
    } 

    for (; i < num; i++) { 
     fscanf(fp, "%s", arr[i]); 
     printf("%s\n", arr[i]); 
    } 
    for (int k = 0; k < num; k++) { 
     free(arr[i]); 
    } 
    free(arr); 
    return 0; 
} 

для fscanf(fp, "%s", arr[i]);, вам нужно Alloc память для каждого arr[i].

+1

В C. нет 'new'. И даже это был C++, вы не хотите' free() 'то, что было выделено с помощью' new', но используйте 'delete'. – alk

+0

Хорошо, как вы решили для C, литье 'malloc()' стало бесполезным. – alk

+0

Спасибо, так много, проблема решена. –

4

fscanf пытается записать данные в *arr[i], которые вы не выделили. Вы выделили только arr[i] (который вы также не инициализировали).

+0

Да, это массив неинициализированных указателей. Эти строки могут быть записаны в любом месте в памяти. –

+0

трудно понять для меня. Можете ли вы хотя бы сказать мне «как?» , Пожалуйста ~! –

1

Проблема в том, что вы выделили место для указателей, но не для самих строк. Вот как альтернатива других ответов, если вы программируете для совместимой платформы POSIX.1-2008 или с новым достаточно Glibc (например, недавно Linux, вероятно, также MinGW):

Вы можете использовать a спецификатор для %s преобразование (далее в scanf man page), что приводит к scanf выделить память для строки (который абонент отвечает вызова free() на), так что для вашего кода:

// No need to cast return value of malloc or calloc. 
// Optional: switched to calloc, which has overhead of zeroing memory, 
// but also makes immediate segfault more likely on some bugs. 
char **arr = calloc(num, sizeof(char*)); 
//... 
for(i=0; i < num; i++) { 
    int status = fscanf(fp,"%ms", arr[i]); 
    assert(status==1); // really simple error checking added 
} 

И как было сказано, когда сделано, вы следует освободить выделенную память:

for(i=0; i < num; i++) { 
    free(arr[i]); 
} 
free(arr); 

Выгода, вам не нужно беспокоиться о переполнении буфера (если файл больше, чем доступная виртуальная память, то вы будете в беде, хотя, если вы не добавите предел a спецификатора, читать man page для деталей ...), и вы не теряете память, имея слишком много места для коротких строк. Недостатком является то, что спецификатор a не определяется стандартом C, поэтому он снизит переносимость вашего кода на платформах GNU и POSIX и может привести к тому, что ваш учитель отклонит его (если это курсовая работа), в случае, если это имеет значение.