fscanf()代码并不总是崩溃内存,但有时

时间:2015-11-08 08:14:21

标签: c pointers malloc scanf coredump

=========================

代码(文件名为test.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

======

问题

当我多次出手时

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

它经常粉碎像#&#34;核心转储&#34;但按照我的预期工作。

然而,当我输入高于9时,它永远不会粉碎......

test 9
test 10
...

enter image description here

是什么让这段代码崩溃了?

3 个答案:

答案 0 :(得分:4)

fscanf正在尝试将数据写入您尚未分配的*arr[i]。您只分配了arr[i](您没有初始化)。

答案 1 :(得分: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]);,您需要为每个arr[i]分配内存。

答案 2 :(得分: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说明符添加限制,请阅读有关详细信息的手册页...)并且您不会因为为较短的字符串分配太多空间而浪费任何内存。缺点是a说明符不是由C标准定义的,因此它会降低代码到GNU和POSIX平台的可移植性,并且可能导致您的教师拒绝它(如果它是课程作业),以防万一