【问题标题】:fscanf() code does not always crash memory, but sometimesfscanf() 代码并不总是崩溃内存,但有时
【发布时间】:2015-11-08 08:14:21
【问题描述】:

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

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

它经常压碎诸如“核心转储”之类的东西,但按我的预期工作。

但是,当我输入高于 9 时,它永远不会崩溃...

test 9
test 10
...

是什么导致这段代码崩溃?

【问题讨论】:

  • 仅供参考:如果您的代码实际上破坏了某些东西,那么您需要担心的事情更多。你想要的词是 crash ;)
  • 我很抱歉暗恋,我的意思是崩溃,
  • @alexparkjw 那你为什么不修呢?

标签: c pointers malloc scanf coredump


【解决方案1】:

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

【讨论】:

  • 是的,它是一个未初始化的指针数组。这些字符串可以写入内存中的任何位置。
  • 对我来说很难理解。你能不能告诉我“怎么做”? ,请~!
【解决方案2】:
#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] 分配内存。

【讨论】:

  • C 中没有 new。即使是 C++,您也不想 free() 使用 new 分配的内容,而是使用 delete
  • 好的,正如你决定使用 C 语言一样,malloc() 的强制转换没用了。
【解决方案3】:

问题是,您只为指针分配了空间,而没有为字符串本身分配空间。如果您正在为 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有关详细信息的页面...)并且您不会因为为较短的字符串分配太多空间而浪费任何内存。缺点是 a 说明符不是由 C 标准定义的,因此它会降低您的代码在 GNU 和 POSIX 平台上的可移植性,并可能导致您的老师拒绝它(如果是课程作业),以防万一。

【讨论】:

    猜你喜欢
    • 2016-04-13
    • 1970-01-01
    • 2012-03-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-18
    相关资源
    最近更新 更多