我正在练习K和R C编程书中的乐趣。该程序用于从用户输入的一组行中查找最长的行,然后将其打印出来。
This is a test
This is another long test
this is another long testthis is another long test
它对前两个输入运行正常,但对于较大的字符串(第三个输入)
则失败Error in `./longest': realloc(): invalid next size: 0x000000000246e010 ***
Error in `./longest': malloc(): memory corruption (fast): 0x000000000246e030 ***
我一直试图调试这个2天(橡皮鸭调试),但逻辑似乎很好。 GDB指向_getline函数中的realloc调用,并在顶部显示glibc.so内存分配调用的大量回溯。
这是我写的(部分,部分内容直接来自本书): -
#include <stdio.h>
#include <stdlib.h>
int MAXLINE = 10;
int INCREMENT = 10;
char* line = NULL, *longest = NULL;
void _memcleanup(){
free(line);
free(longest);
}
void copy(char longest[], char line[]){
int i=0;
char* temp = realloc(longest,(MAXLINE)*sizeof(char));
if(temp == NULL){
printf("%s","Unable to allocate memory");
_memcleanup();
exit(1);
}
longest = temp;
while((longest[i] = line[i]) != '\0'){
++i;
}
}
int _getline(char s[]){
int i,c;
for(i=0; ((c=getchar())!=EOF && c!='\n'); i++){
if(i == MAXLINE - 1){
char* temp = realloc(s,(MAXLINE + INCREMENT)*sizeof(char));
if(temp == NULL){
printf("%s","Unable to allocate memory");
_memcleanup();
exit(1);
}
s= temp;
MAXLINE += INCREMENT;
}
s[i] = c;
}
if(c == '\n'){
s[i++] = c;
}
s[i]= '\0';
return i;
}
int main(){
int max=0, len;
line = malloc(MAXLINE*sizeof(char));
longest = malloc(MAXLINE*sizeof(char));
while((len = _getline(line)) > 0){
printf("%d%d", len, MAXLINE);
if(len > max){
max = len;
copy(longest, line);
}
}
if(max>0){
printf("%s",longest);
}
_memcleanup();
return 0;
}
答案 0 :(得分:5)
您在复制的地址上重新分配(因为参数) C中的参数是每次原始值的副本;如果是 指针指向同一位置,但地址本身被复制。
realloc
调整与地址相关的缓冲区大小,到目前为止一切正常
但它可以重新定位整个事物并分配一个全新的地址,
在函数返回main后,这个新地址(如果它发生)将丢失。
使用双指针:
传递char **s
代替char *s
(== char s[]
)作为形式参数,
将&xyz
整数xyz
作为实际值传递,并在函数内传递
使用*xyz
和**xyz
(或(*xyz)[index]
)获取地址和值。
其他事项:
全局变量很丑(当命名与参数相同时会令人困惑),
乘以sizeof(char)
是无稽之谈,因为它每次都是1,
大写字母应该用于#define
而不是变量。
答案 1 :(得分:3)
单独使用双指针,不是解决问题的方法。你有2个主要问题。您可以通过输入字符串作为字符串来查看它们,并且会在您传递第20个字符时发现问题。 (例如01234567890123456789
)
您已全局声明line
和longest
。因此,虽然您可以重写_getline (char **s)
,但您也可以使用line
(包括_getline
)在memcpy
末尾更新string.h
。例如:
memcpy (line, s, (size_t)i);
return i;
}
这可以解决您的_getline
问题。问题二是相当直接的。您在longest
中不会终止copy
。 (您选择与全局变量同名的参数也会带来挑战)包括以下修复副本:
++i;
}
longest[i] = '\0';
}
如果你同时包含这两项修改,那么我相信你会发现你的日常工作。然后,您可以重新_getline (char **s)
并传递&line
作为另一项练习。例如,您可以将_getline
重写为:
int
_getline (char **s) {
int i, c;
for (i = 0; ((c = getchar ()) != EOF && c != '\n'); i++) {
if (i == MAXLINE - 1) {
char *temp = realloc (*s, (MAXLINE + INCREMENT) * sizeof (char));
if (temp == NULL) {
printf ("%s", "Unable to allocate memory");
_memcleanup ();
exit (1);
}
*s = temp;
MAXLINE += INCREMENT;
}
(*s)[i] = c;
}
if (c == '\n') {
(*s)[i++] = c;
}
(*s)[i] = '\0';
return i;
}
然后将您的通话修改为:
while ((len = _getline (&line)) > 0) {