gpt4 book ai didi

C func 为任意长的行动态分配mem;通过单元测试,原地崩溃

转载 作者:行者123 更新时间:2023-11-30 15:17:59 25 4
gpt4 key购买 nike

我有一个函数 dgets,其唯一目的是从 stdin 获取任意长度的字符串。这是我用于单元测试的文件的全文:

#include <stdio.h>
#include <stdlib.h>

int dgets(char** lnptr, int lastIndex)
/*
RETRIEVE A LINE OF ARBITRARY LENGTH FROM STDIN
*/
{
char c;
int i = 0;

while( (c = getchar()) && c != EOF && c != '\n' ) {
if( i >= lastIndex-1 ) {
lastIndex *= 2;
*lnptr = (char*)realloc(*lnptr, lastIndex);
}

*(*lnptr + i) = c;
++i;
}

if( c == '\n' ) {
*(*lnptr + i) = c;
*lnptr = (char*)realloc(*lnptr, i+1);
*(*lnptr + i+1) = '\0';
}

return i;
}

int main()
{
char* line;

line = (char*)calloc(10, sizeof(char));

while( dgets(&line, 10)) {
printf("****************\n%s****************\n", line);
free(line);
line = (char*)calloc(10, sizeof(char));
}

return 0;
}

该程序的执行完全符合预期,错误或错误为零。这很好,因为我想在更大的程序中使用它。将 dgets 的代码复制并粘贴到较大的程序中,并使用 -Wall 成功编译后(1 个警告,gcc 未报告任何错误),运行较大的程序导致段错误(核心转储)

使用 gdb 检查 corefile 会产生以下结果:

$ coredumpctl gdb 14527
PID: 14527 (a.out)
UID: 1000 (demiurge)
GID: 1000 (demiurge)
Signal: 11 (SEGV)
Timestamp: Wed 2015-08-05 15:48:28 CDT (1min 58s ago)
Command Line: ./a.out
Executable: /home/demiurge/learning_c/KR_exercises/chapter_1/a.out
Control Group: /user.slice/user-1000.slice/session-c1.scope
Unit: session-c1.scope
Slice: user-1000.slice
Session: c1
Owner UID: 1000 (demiurge)
Boot ID: 629b0a58691c4ec488bd0b84276df9d4
Machine ID: 4c9566d65e864c6da8e41bfaf8ed2cb4
Hostname: exmachina
Coredump: /var/lib/systemd/coredump/core.a\x2eout.1000.629b0a58691c4ec488bd0b84276df9d4.14527.1438807708000000.lz4
Message: Process 14527 (a.out) of user 1000 dumped core.

Core was generated by `./a.out'.
Program terminated with signal SIGSEGV, Segmentation fault.
#0 0x00007f253e36cd80 in _int_realloc () from /usr/lib/libc.so.6
(gdb) bt
#0 0x00007f253e36cd80 in _int_realloc () from /usr/lib/libc.so.6
#1 0x00007f253e36e0f0 in realloc () from /usr/lib/libc.so.6
#2 0x0000000000400753 in dgets (lnptr=0x7ffeaf001050, lastIndex=40) at ./1.13.c:41
#3 0x00000000004009a2 in main () at ./1.13.c:107
(gdb) frame 3
#3 0x00000000004009a2 in main () at ./1.13.c:107
107 while( dgets(&line, SIZE) ) {
(gdb) frame 2
#2 0x0000000000400753 in dgets (lnptr=0x7ffeaf001050, lastIndex=40) at ./1.13.c:41
41 *lnptr = (char*)realloc(*lnptr, lastIndex);

使用 gdb 进行进一步检查,确认段错误发生在 dgets 中第一次调用 realloc 的第二次迭代中。所以我的问题是:为什么 reallocdgets 通过单元测试后触发段错误?

帮助我理解,仁慈仁慈的StackOverlords!

附录:

好的,这是在调用 dgets 之前运行的代码:

int main()
{
char* line;
int* lengths;
int longest;

line = (char*)calloc(SIZE, sizeof(char));
lengths = (int*)calloc(SIZE, sizeof(int));

//get a line from stdin
while( dgets(&line, SIZE) ) {

//count how many words are of length n
longest = countWordLengths(line, &lengths);

//do a little housekeeping
free((void*)line);
line = (char*)calloc(SIZE, sizeof(char));
if( line == NULL ) { return 1; }
}

.
.some other stuff happens here, but the code never gets this far.
.
}

最佳答案

好的,这适用于所有收到错误消息的新手,除了段错误之外,还提到了有关 malloc/realloc/calloc 和无效的新/旧地址的信息:

<强> Get and use Valgrind 它是一个免费的开源堆分析器,可以向您显示代码中堆损坏的位置,进而提供有关这些堆损坏发生的位置和方式的一些见解。

在这个特殊情况下,我的代码中发生了多次堆损坏,主要是因为传递给 realloc 的参数不正确。我想做的是调整保存整数的内存块的大小,如下所示:

*lnptr = (int*) realloc(*lnptr, newSize * sizeof(int));

但我最初写的是这样的:

*lnptr = (int*) realloc(*lnptr, newSize);

看到realloc中的第二个参数了吗?这导致的问题是 *lnptr 最终只有 newSize 字节宽,如果我只需要存储 newSize char 那就没问题了如果我想存储 newSize ints,那就太糟糕了。

吸取的教训;仔细阅读友好的手册。并且,如果您要动态分配内存,请使用 Valgrind。

关于C func 为任意长的行动态分配mem;通过单元测试,原地崩溃,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31843147/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com