" fruits.txt"是一个以数字开头的文本文件,比如n,后跟n个fruits的名称。我想将这n个名称存储到一个字符串数组中,但是在尝试声明该数组时,我得到了" Segmentation故障(核心转储)错误。
#include<stdio.h>
#include<stdlib.h>
int main()
{
FILE *fp;
int count;
fp = fopen("fruits.txt", "r");
if(fp == NULL)
{
printf("Can't open file!!");
exit(0);
}
fscanf(fp, "%d", &count);
printf("%d\n", count);
char *fruits[count]; // This line is giving Segmentation fault.
fclose(fp);
return 0;
}
答案 0 :(得分:1)
根据您在阅读水果名称时提供存储(内存)的方式,您有两个选项(2)使用鲜为人知的'm'
字段修饰符('a'
对于较旧的实现,所以如果你正在使用windoze,请阅读文档以做出决定(或者只是尝试两者并看看哪个有效)。
您的代码存在的直接问题是使用fopen
文件模式调用了"w"
。只有当fruits.txt
已经过时时才会有效,因为"w"
模式不会创建文件(如果它不存在)。正确的模式是"w+"
(或"a"
或"a+"
,其中任何一个也会创建一个不存在的文件)。只需将模式更改为"w+"
,即可将水果信息写入新创建的fruits.txt
。
在某些MS编译器上使用VLA(可变长度数组)的问题可能会出现问题。您只需要查看您的版本和更改日志或文档(或者只是尝试阅读错误或警告。更糟糕的情况是,您可以使用指针指向类型,或者一个足够大小的静态数组。鉴于你使用fscanf
,这种方法将在下面继续。具体来说:
char *fruits[count]; /* here you delare an array of pointers to type char */
/* utilizing a variable length array. some MS compiler */
/* version do not handle VLA's, VS13/VS15 should be ok */
for (i = 0; i < count; i++) /* read & allocate for each array element */
if (fscanf (fp, " %ms", &fruits[i]) != 1) { /* m allocates, a for ms */
fprintf (stderr, "error: read/allocation for fruits[%d] failed.\n", i);
exit (EXIT_FAILURE);
}
(注意" %ms"
上面使用的格式字符串,它注意到接受分配块的指针必须是指向<{1}}的指针指针 - 分配/文件指针的地址,例如char *
)
代码的其余部分应该非常熟悉,除非现在代码中的所有输入和其他关键点都已经验证,方法是检查由任何函数提供的&fruits[i]
以确保没有错误条件存在直到那一点,并且没有一个是由有问题的操作引起的。这是您对代码操作有信心的唯一方法。养成这个习惯。
把它放在一起,你可以想出以下内容。
return
代码的基本编译字符串(在#include <stdio.h>
#include <stdlib.h>
int main (void) {
int count, i;
FILE *fp;
if (!(fp = fopen ("fruits.txt", "w+"))) { /* "w+" required to create file */
fprintf (stderr, "error: file open failed 'fruits.txt'.\n");
exit (EXIT_FAILURE);
}
fputs ("4 Apple Banana mango berry", fp); /* write string to fruits.txt */
fclose(fp);
if (!(fp = fopen ("fruits.txt", "r"))) { /* validate file open for reading */
fprintf (stderr, "error: file open failed 'fruits.txt'.\n");
exit (EXIT_FAILURE);
}
if (fscanf (fp, " %d", &count) != 1) { /* read all fruir from fruits.txt */
fprintf (stderr, "error: in read of value from 'fruits.txt'.\n");
exit (EXIT_FAILURE);
}
printf ("\n Quantity read from 'fruits.txt' is '%d'.\n\n", count);
char *fruits[count]; /* here you delare an array of pointers to type char */
/* utilizing a variable length array. some MS compiler */
/* version do not handle VLA's, VS13/VS15 should be ok */
for (i = 0; i < count; i++) /* read & allocate for each array element */
if (fscanf (fp, " %ms", &fruits[i]) != 1) { /* m allocates, a for ms */
fprintf (stderr, "error: read/allocation for fruits[%d] failed.\n", i);
exit (EXIT_FAILURE);
}
fclose(fp); /* close file for the last time */
for (i = 0; i < count; i++) /* output array */
printf (" fruit[%d] : %s\n", i, fruits[i]);
for (i = 0; i < count; i++) /* free allocated memory */
free (fruits[i]);
return 0;
}
中)和abc.c
中的可执行文件可能是:
bin/abc
示例使用/输出
$ gcc -Wall -Wextra -o bin/abc abc.c -std=gnu11
在任何动态分配内存的代码中,对于分配的任何内存块,您都有2个职责:(1)始终保留指向起始地址的指针内存块,(2)当不再需要时,它可以释放。
必须使用内存错误检查程序,以确保您没有在已分配的内存块之外/之外写入,尝试读取或基于未初始化的值跳转,最后确认您已拥有释放了你分配的所有内存。对于Linux $ ./bin/abc
Quantity read from 'fruits.txt' is '4'.
fruit[0] : Apple
fruit[1] : Banana
fruit[2] : mango
fruit[3] : berry
是正常的选择。
valgrind
始终确认释放所有堆块 - 不可能泄漏并且同样重要错误摘要:0个上下文中的0个错误。 (虽然注意:某些操作系统没有提供足够的记忆排除文件(排除系统和操作系统内存不被报告为正在使用的文件),这将导致$ valgrind ./bin/abc
==30980== Memcheck, a memory error detector
==30980== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==30980== Using Valgrind-3.10.1 and LibVEX; rerun with -h for copyright info
==30980== Command: ./bin/abc
==30980==
Quantity read from 'fruits.txt' is '4'.
fruit[0] : Apple
fruit[1] : Banana
fruit[2] : mango
fruit[3] : berry
==30980==
==30980== HEAP SUMMARY:
==30980== in use at exit: 0 bytes in 0 blocks
==30980== total heap usage: 10 allocs, 10 frees, 1,561 bytes allocated
==30980==
==30980== All heap blocks were freed -- no leaks are possible
==30980==
==30980== For counts of detected and suppressed errors, rerun with: -v
==30980== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 1 from 1)
报告有些记忆尚未被释放(尽管事实上你完成了自己的工作,并且释放了你分配并在你控制之下的障碍。
为了解决一个简单的问题需要付出很多,而且我们甚至没有谈到读取文件的首选方式本来就是{{1}一次阅读和整行}或POSIX valgrind
,然后解析来自读取行的各个水果,或标记化行fgets
。花时间消化cocde并自己回答你必须查找的两个编译器问题(1)支持getline
的VLA和(2)strtok
或{{1}你的编译器使用它来分配。
答案 1 :(得分:0)
使用fscanf
时,您必须始终检查返回值。只有当函数返回一个成功的值时(请阅读fscanf
文档),程序才能继续。
答案 2 :(得分:0)
我尝试过以下代码并找到了工作。 这里的区别首先是我创建了文件并填充了其中的内容。
如果我没有填写文件中的内容,那么我会得到分段错误(不是在所有编译器上)。 所以在你的情况下,似乎fscanf()正在阅读一些垃圾并返回一些大垃圾号码。 正如其他人也建议的那样,请检查fscanf返回的内容。如果它返回-1,表示文件中没有找到任何内容。
Component.onCompleted: {
listView.currentIndex = -1;
}
这打印4没有错误/错误。