0

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

无论哪种方式,程序都编译得很好,但是当我运行它时,它很快就显示出分段错误,我几乎可以肯定原因是我对内存的处理不当。在我尝试用 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;
}

这是主要功能:

/*MAIN*/
int main(){
int linesnum = readlinesnum();
char **lines = linelist(linesnum);
char ***matrix = createmat(linesnum, lines);
char input;
fstruct ignore;
ignore.len = 0;
while (1){
    scanf("%c", &input);
    if (input == 'f'){
        ignore = f(ignore);
    }
    else if (input == 's'){
        s(lines, linesnum);
    }
    else if (input == 'l'){
        l(matrix, lines, linesnum, ignore);
    }
    else if (input == 'w'){
        w(matrix, lines, linesnum, ignore);
    }
    else if (input == 'h'){
        h(matrix, linesnum);
    }
    else if (input == -1){
        break;
    }
}
freememory(matrix, lines);
return 0;
}

readlinesnum 函数似乎工作正常,所以当我真正开始创建带有行的列表时,事情并不顺利。我很想了解他们不这样做的确切原因,因为我认为我在其余代码中肯定遇到的任何其他问题也与此问题有关。

谢谢你。

4

3 回答 3

1

这条线是你麻烦的根源:

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

它不仅应该是\n而不是/n(这是次要的),而且您正在将当前值传递input给未初始化的scanf时间。input那不好。对于整数等,您至少要先获取它的地址,然后再将其提供给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改为使用。您需要实现的算法是:

  1. 跟踪到目前为止我们已经阅读了多少。那将被初始化为零。
  2. 跟踪当前分配的缓冲区大小。将其初始化为合理的值。
  3. 分配一些该大小的内存。(不要忘记检查错误。)
  4. 调用fgets,将其传递&allocated_memory[read_so_far]给缓冲区和amount_allocated - read_so_far长度。该文件可能应该stdin执行您之前正在执行的操作,但它可以是任何可读文件。(同样,不要忘记检查错误。)
  5. 更新到目前为止我们已经阅读了多少。
  6. 检查我们是否阅读了整行。因为fgets如果有一个换行符将保留换行符,如果我们已经读取了整行并且我们不在文件的末尾,则将存在换行符,如果在结尾之前有换行符,我们已经读取了整行字符串或我们已到达文件结尾。
  7. 如果我们还没有读完整行,则将缓冲区的当前分配大小和缓冲区加倍realloc。不要忘记检查错误。然后转到第 4 步。
  8. 如果我们到达这里,我们已经读完了这条线。可选realloc的缓冲区,以便它完全适合字符串而不会浪费空间。

实现起来并不那么有趣,但它是一个有用的东西,所以你可能想把它包装在一个函数中。这有点痛苦,但如果你使用 C,也许你应该习惯它。

于 2013-05-12T01:30:06.980 回答
0

对于初学者,您的linelist函数有许多非常严重的错误。

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

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

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

简而言之,您需要在分配内存等方面做好功课。我还建议您通过使用Valgrind运行代码来调试代码。

于 2013-05-12T01:18:47.487 回答
0

在您的函数中linelist,这一行:

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

正在读取未分配的内存,这似乎是您的直接问题,main尽管您正在做正确的事情。您显然没有做正确的事情,calloc但我不清楚您从代码示例中尝试做什么,所以不确定那里有什么正确的解决方案。尽管假设您正在尝试创建 2D 数组,但这个先前的线程应该会有所帮助。

于 2013-05-12T01:18:56.780 回答