c指针和内存管理中的分段错误(内核转储)

c指针和内存管理中的分段错误(内核转储),c,list,pointers,memory-management,C,List,Pointers,Memory Management,我正在为大学做一个特定的项目,包括阅读输入文本,并根据几个命令生成特定的输出。评分的重点是效率,所以动态内存分配是一条路,但我对它的了解还真的很不稳定 不管怎样,程序编译得很好,但当我运行它时,它很快显示出一个分段错误,我几乎可以肯定原因是我对内存的处理不当。在我尝试用gdc诊断后,我得到了以下结果: (gdb) run proj Starting program: /home/dusk/Documents/proj proj warning: no loadable sections foun

我正在为大学做一个特定的项目,包括阅读输入文本,并根据几个命令生成特定的输出。评分的重点是效率,所以动态内存分配是一条路,但我对它的了解还真的很不稳定

不管怎样,程序编译得很好,但当我运行它时,它很快显示出一个分段错误,我几乎可以肯定原因是我对内存的处理不当。在我尝试用gdc诊断后,我得到了以下结果:

(gdb) run proj
Starting program: /home/dusk/Documents/proj proj
warning: no loadable sections found in added symbol-file system-supplied DSO at 0x7ffff7ffa000
5
hello, I'm me

Program received signal SIGSEGV, Segmentation fault.
0x00007ffff7a681c3 in _IO_vfscanf () from /lib/x86_64-linux-gnu/libc.so.6
(gdb) where
#0  0x00007ffff7a681c3 in _IO_vfscanf () from /lib/x86_64-linux-gnu/libc.so.6
#1  0x00007ffff7a70a22 in __isoc99_scanf ()
from /lib/x86_64-linux-gnu/libc.so.6
#2  0x00000000004009a4 in linelist (n=5) at proj.c:79
#3  0x000000000040134b in main () at proj.c:226
显然,问题(嗯…第一个问题)在linelist函数中,如下所示:

/* Creates a list of strings (each being a line of the input)
implemented with pointers */

char **linelist(int n)
{
char **list;
list = calloc(n, MAX_STR*sizeof(char));
char *input;
int i;

for (i = 0; i < n; i++){
scanf("%s/n", input);
list[i] = input;
}
return list;
}
readlinesnum函数似乎工作得很好,所以当我真正开始创建包含行的列表时,事情就不顺利了。我很想了解他们不这样做的确切原因,因为我认为我在代码的其余部分中肯定遇到的任何其他问题也与这个问题有关


谢谢。

首先,您的
行列表
函数有许多非常严重的错误

首先,您正在调用
calloc
,但没有分配足够的空间。您需要的是一个字符数组*(指针,长度为4或8字节),但您正在分配一个字符数组。简而言之,将
sizeof(char)
替换为
sizeof(char*)

然后,您需要为正在读取的每个字符串分配空间

最后,您正在
scanf
语句中写入未分配的内存


简而言之,您需要完成分配内存等方面的作业。我还建议您通过在函数
行列表中使用来调试代码。

此行:

scanf("%s/n", input);

正在
main
中读取未分配的内存,这似乎是您的直接问题,尽管您正在做正确的事情。显然,您在使用
calloc
时没有做正确的事情,但我不清楚您在代码示例中尝试做什么,因此不确定有什么正确的解决方案。虽然假设您正在尝试创建2D阵列,但这应该会有所帮助。

这一行是您的问题的根源:

scanf("%s/n", input);
它不仅应该是
\n
而不是
/n
(这是次要的),而且当
输入
未初始化时,您正在将
输入
的当前值传递给
扫描
。那不好。对于整数等,在将其发送给
scanf
之前,您至少要先获取其地址:

scanf("%d", &my_number);
但是,这在这里不适用:对于
%s
,它尝试将数据存储到您提供给它的内存中。您正在给它一个未初始化的指针,它可能会崩溃,并且在任何情况下都不会执行您希望它执行的操作

你需要自己为它分配内存。例如,如果要读取最多200个字符的行,可以执行以下操作:

char my_array[201];  /* don't forget to save space for the null byte */
scanf("%200s", my_array);
然后你限制了线的长度,这是不好的。显然,我们需要另一种解决办法

scanf
,您可能很快就会发现,它不是这份工作的好工具。我们将使用
fgets
。您需要实现的算法是:

  • 记录到目前为止我们读了多少。这将被初始化为零
  • 跟踪当前分配的缓冲区大小。将其初始化为合理的值
  • 分配一些这样大小的内存。(别忘了检查错误。)
  • 调用
    fgets
    ,为缓冲区传递
    &分配的内存[read\u so\u far]
    ,为长度传递
    分配的数量-read\u so\u far
    。该文件可能应该是
    stdin
    ,以执行您之前所做的操作,但它可以是任何可读文件。(同样,不要忘记检查错误。)
  • 更新到目前为止我们阅读的内容
  • 看看我们是否读了整行。因为
    fgets
    将保留换行符(如果有),并且如果我们读取了整行且不在文件末尾,则将存在一个换行符,因此如果字符串末尾之前有一个换行符或我们到达了文件末尾,则我们将读取整行符
  • 如果我们没有读取整行,则将当前分配的缓冲区大小加倍,并
    realloc
    缓冲区。别忘了检查错误。然后转到步骤4
  • 如果我们到了这里,我们已经看完了。可选地
    realloc
    缓冲区,使其完全适合字符串,而不会浪费空间

  • 实现它并不是那么有趣,但它是一个有用的东西,所以您可能希望将其封装在函数中。这是一种痛苦,但是如果你使用C,也许你应该习惯它。

    linelist
    this
    scanf(“%s/n”,输入)正在写入未分配的内存。什么样的效率-空间还是时间?时间效率通常建议不要使用动态记忆。。。我的想法是,我对它将读取的字符串的大小有一个限制,它被定义为常量
    MAX\u STR
    。因此,将其乘以
    sizeof(char)
    ,将得到字符串的最大大小。假设我想要一个大小为
    n
    的数组,这就是它应该做的。我错了吗?也。我将尝试Valgrind,非常感谢您提供了有用的答案。以上所有内容都是正确的,但这将适用于包含所有字符串的单个字符数组。相反,您可能希望拥有一个字符数组(基于“char**”声明)。如果希望linelist可用作向量,则需要首先分配一个指针数组,然后将这些指针初始化为大小适当的缓冲区。我试图通过读取不同的输入行来创建字符串列表:每行是列表中的一个条目
    n
    是以前从输入中读取的行数
    MAX_STR
    是最大值
    char my_array[201];  /* don't forget to save space for the null byte */
    scanf("%200s", my_array);