在下面的代码中,我尝试查找存储在包含给定字符串的文件中的数据名称,然后打印在函数外部找到的名称。文件中的数据以|数据的名称|数据的字节数|数据|的形式存储。该函数接收文件的文件描述符作为参数,我们试图在文件名称中找到的字符串和一个结构,该结构包含一个表,其中将存储找到的名称 (** findNames) 以及该表的大小桌子 。 我遇到的问题是,当函数 realloc 用于增加表的大小时,已经存储在那里的指针消失了。
结构:
typedef struct{
int size ;
char **findNames ;
}findReturn;
功能:
int find(int *fd,char *namepart,findReturn *findResults){
int i = 2 ;
int j = 0;
int dataSize ;
int filesize ;
char name[255];
char **temp ;
errno = 0 ;
if(*fd == -1){
return MISSING_DB ;
}
filesize = lseek(*fd,0,SEEK_END);
lseek(*fd,2,SEEK_SET);
while(i < filesize){
read(*fd,name + j,1);
i++ ;
if(name[j] == '\0'){
if(stringFinder(namepart,name) == SUCCESS){
(findResults->size)++;
temp = (char **)realloc(findResults->findNames,findResults->size);
if(temp != NULL){
findResults->findNames = temp ;
findResults->findNames[findResults->size - 1] =
(char*)malloc(strlen(name) * sizeof(char) + 1);
strcpy(findResults->findNames[findResults->size - 1],name);
}
else{
(findResults->size)--;
}
}
read(*fd,&dataSize,sizeof(int));
i += sizeof(int) ;
i += dataSize ;
lseek(*fd,i,SEEK_SET);
j = 0;
}
else{
j++ ;
}
}
if(errno != 0){
return FAIL ;
}
return SUCCESS ;
}
主要用途:
case 'f':{
scanf(" %s", namepart);
returnValue = find(&databaseFd,namepart,&findResults) ;
if(findResults.findNames != NULL){
printf("\n##\n");
for(i=0; i < findResults.size; i++){
printf("%s\n", findResults.findNames[i]);
}
}
else if(returnValue == MISSING_DB){
fprintf(stderr,"No open db file.\n");
}
else if(returnValue == FAIL){
perror("\nUnexpected Error");
return 42 ;
}
break ;
这是一个例子:
我启动了程序,通过main调用了find函数 给出一个我希望函数找到的字符串
f ile
正在使用的文件里面写了:
00000000: 4442 6669 6c65 3100 0d00 0000 4865 6c6c DBfile1.....Hell
00000010: 6f0a 576f 726c 6421 0a66 696c 6532 000d o.World!.file2..
00000020: 0000 0048 656c 6c6f 0a57 6f72 6c64 210a ...Hello.World!.
如果文件成功保存了名称,那么它应该打印在最终输出中:
##
file1
file2
但是我得到了分段错误:
==4234==ERROR: AddressSanitizer: SEGV on unknown address 0x00000000be30 (pc 0x000100faae10 bp 0x00016f22f220 sp 0x00016f22e960 T0)
==4234==The signal is caused by a UNKNOWN memory access.
#0 0x100faae10 in __sanitizer::internal_strlen(char const*)+0x4 (libclang_rt.asan_osx_dynamic.dylib:arm64e+0x56e10)
#1 0x100f72034 in wrap_printf+0x8c (libclang_rt.asan_osx_dynamic.dylib:arm64e+0x1e034)
#2 0x100bd3360 in main project3.c:57
#3 0x193ce7f24 (<unknown module>)
执行期间(通过调试器):
名字保存在正确的位置
(lldb) p findResults->findNames[0]
(char *) $2 = 0x0000000102300710 "file1"
重新分配后:
在临时指针中
(lldb) p temp[0]
(char *) $5 = 0x000000000000be10 ""
然后在主桌上
(lldb) p findResults->findNames[0]
(char *) $6 = 0x000000000000be10 ""
一个显而易见的问题是
realloc
调用重新分配 findResults->findNames
正在分配错误大小的内存。它为每个元素分配一个字节,但分配的是元素数乘以每个元素的大小。每个元素的大小可以表示为sizeof(char *)
或sizeof(*findResults->findNames)
或sizeof(findResults->findNames[0])
。 realloc
返回一个 void *
。无需将结果转换为 C 中不同的指针类型。
temp = realloc(findResults->findNames,findResults->size*sizeof(*findResults->findNames));
如果
findResults->findNames
指向代码中其他地方malloc
分配的内存,那也需要是正确的大小。
尽管代码正确地检查了
realloc
调用是否成功,但它没有检查后续的 malloc
调用。如果 findResults->size
和 realloc
调用都成功,我建议只增加 malloc
:
if(stringFinder(namepart,name) == SUCCESS){
temp = realloc(findResults->findNames,
(findResults->size + 1) * sizeof(char*));
if(temp != NULL){
findResults->findNames = temp ;
findResults->findNames[findResults->size] =
malloc(strlen(name) + 1);
if (findResults->findNames[findResults->size] != NULL){
strcpy(findResults->findNames[findResults->size],name);
findResults->size++;
}
}
}