无法分配指针linux接收的内存
我有一个函数,通过指针接收将存储的位置。 这个地方可以有不同的其他类似结构。该函数必须读取一个文件。 这个文件存储了一个我需要阅读的结构。
typedef struct user_manage_t{ short int user_id; char permission; long int other_id; long int check; }user_manage_t; typedef struct holder_t{ user_manage_t *user_manage; user_manage_t *user_manage_backup; //(...)and a lot of stuff }holder_t; holder_t holder; int db_read_from_file(user_manage_t *prt){ DEBUG_PRINT("READ_FROM file started"); FILE *fd_read; char buffer[480]; int read, bytesRead=0; int num; const struct user_manage_t *header; fd_read = fopen("/home/user/user_list","r+b"); if (fd_read == NULL) { printf("Error"); } else { DEBUG_PRINT("Its open!!!"); } do { read=fread(buffer, 2, 90, fd_read); bytesRead=bytesRead+read; DEBUG_PRINT("Number of bytes lidos read=%d",bytesRead); }while(read!=0); //(bytesRead < 480); header = (struct user_manage_t *) (buffer); fclose(fd_read); if ( NULL == ( prt = calloc( 10, sizeof(user_manage_t))))//aloca { DEBUG_PRINT("MAJOR_ERROR: couldnt allocate mem to users"); return -1; } else { memcpy( (struct user_manage_t *) &prt, &buffer, 90); DEBUG_PRINT("Users copied to main list"); for ( short int i=0;i<4 ; i++ ) { DEBUG_PRINT("i= %hd",i); DEBUG_PRINT("User id: %d",holder.user_manage[i].user_id ); DEBUG_PRINT("Permission: %d",holder.user_manage[i].permission); DEBUG_PRINT("other_ID:%ld",holder.user_manage[i].other_id); DEBUG_PRINT("Check_value:%ld", holder.user_manage[i].check); } return 1; } } main(){ db_read_from_file((struct user_manage_t *) &holer.user_manage); db_read_from_file((struct user_manage_t *) &holder.user_manage_backup); }
当我运行代码时,我得到了SEGFAULT,valgrind告诉我这个,
线程2:
== 2746 ==读取大小2无效
== 2746 ==在0x80523B4:db_read_from_file(code.c:3069)
== 2746 == by 0x20303333:???
== 2746 ==地址0x0没有堆叠,malloc’d或(最近)免费
这是“DEBUG_PRINT(”用户ID:%d“,holder.user_manage [i] .user_id);” 所以看起来我好像不是把它存放在正确的地方。 你能帮我吗?
优先级Nr 1
在看了你的代码之后,我怀疑你和你一样投射,因为你不断得到关于“不兼容的[指针]类型”等的编译器警告。 这些警告存在的原因是:存在问题,可能存在错误来源。 不要嘘声,不要忽视它: 修复它!
是的,有时这些演员阵容是必需的,有时编译器会在你知道你在做什么时抱怨你的代码。 在这种情况下,您可以添加一个强制转换,但不要将这些强制转换视为编译器 – gags:它们是告诉编译器您知道自己在做什么的方法。 你刚刚疯狂地让编译器闭嘴。 那很糟。
下一个
在main
的db_read_from_file
调用中,您将指针传递给指向函数的空指针。 这意味着您仍然必须分配内存来实际存储和存储该数据,或者您必须将holder
重新定义为:
struct { user_manage_t user_manage;//not pointers, actual structs user_manage_t user_manage_backup; } holder;
如果你把它们作为指针,只需在main中分配holder
所有成员:
holder.user_manage = malloc(sizeof *holder.user_manage);//and so on //preferably, though: if (NULL == (holder.user_manage_backup = malloc(sizeof *holder.user_manage_backup)) exit (EXIT_FAILURE);//error
大的那个
如上所述:
memcpy( (struct user_manage_t *) &prt, &buffer, 90);
你正在传递&prt
,其中包括: prt
地址。 这个变量本身已经是一个指针,指针的内存地址也是一个指针。 指向指针的指针(双重间接,尽可能避免……)。 现在好像这还不够:看看你传递给你的函数:
db_read_from_file(&holder.user_manage);
请记住, holder.user_manage
已经是一个指针,您正在向指针传递指针! 这是双重间接。 然后,您将指向此指针的指针传递给指向memcpy
的指针!! 是的,你可能需要再读一遍这句话。 但简而言之:您正在将指针传递给指针,指向结构的指针,其中最后一位(指向结构的指针)也可能只是一个空指针!
所以你有这个:
memcpy(void ***, char *, 90);//where the prt is void ***, and **prt could be NULL
把memcpy想象成一个函数,基本上这样做:
void * memcpy( void *target, const void *src, size_t nr_of_bytes) { char *dest = target; char *from = src;//use char, as it is guaranteed to be 1 byte in size int i; while(nr_of_bytes--) *dest++ = *from++;//copy byte to destination, move pointer 1 byte return dest;//return destination }
请注意,目标正在解除引用( *dest++
)。 如果你将一个指针传递给一个指针( &prt
),并取消引用它,你最终会得到一个指针,对吧? 这就是你写的=> *(&prt) == prt
!
演员表以及你使用它的方式表明你相信你正在写入任何prt
所指向的内容,而实际上你正在尝试向prt
指向的指针写入90个字节。 它指向prt
,而prt
又指向指针。 只有在第三次入侵之后,我们才发现结构……这只是疯了。
无论如何,指针的大小在32位系统上是4个字节,在64位上是8个字节。 你正在复制90个字节,所以你可能最终在内存中你不应该搞乱。
用以下代码替换您的代码:
memcpy(*prt, buffer, sizeof *prt);//copy max the sizeof whatever prt is pointing to
并将db_read_from_file
函数更改为:
int db_read_from_file(user_manage_t **prt)//pointer to pointer!
请记住,每当你想要改变某些prt
指向的结构(第二级)时,你必须取消引用它,以获得一个常规指针。 例如,分配内存:
if ( NULL == ( prt = calloc( 10, sizeof(user_manage_t))))//aloca
必须成为:
if ( NULL == ( *prt = calloc( 10, sizeof(user_manage_t))))//aloca
但是,这在许多方面仍然是错误的。 你真正需要的是realloc
,因为prt
可能已经指向已分配的内存:
*prt = realloc(*prt, 10*sizeof **prt); if (*prt == NULL) //ERROR
它更干净,更安全。
还要检查你的函数是否没有被传递空指针,消除不必要的强制转换(它们是混乱的),并且总是检查函数的返回值!
这是最终的代码,以防有些人遇到类似的情况:
typedef struct user_manage_t{ short int user_id; char permission; long int other_id; long int check;
} user_manage_t;
typedef struct holder_t {
user_manage_t *user_manage; user_manage_t *user_manage_backup; pthread_mutex_t check_mutex; pthread_mutex_t backup_mutex; //(...)and a lot of stuff
} holder_t;
holder_t持有人;
int db_read_from_file(user_manage_t ** prt,pthread_mutex_t mtx){
DEBUG_PRINT("READ_FROM file started"); FILE *fd_read; char buffer[480]; int read, bytesRead=0; int num; const struct user_manage_t *header; fd_read = fopen("/home/user/user_list","r+b"); if (fd_read == NULL) { printf("Error"); } else { DEBUG_PRINT("Its open!!!"); } do { read=fread(buffer, 1, 480, fd_read); bytesRead=bytesRead+read; DEBUG_PRINT("Number of bytes lidos read=%d",read); }while(read!=0); //(bytesRead < 480); header = (struct user_manage_t *) (buffer); fclose(fd_read); if ( NULL != prt ) { status = pthread_mutex_trylock (&mtx); if (status != 0)//compor isto { DEBUG_PRINT("ERROR with lock"); return -1; } else { num = bytesRead / sizeof(user_manage_t); DEBUG_PRINT("prt is not null and num=%d",num); //should add an if to check if num >0 //if ( NULL == ( *prt = calloc( num, sizeof(user_manage_t))))//aloca if ( NULL == ( *prt = malloc(bytesRead))) { DEBUG_PRINT("MAJOR_ERROR: couldnt allocate mem to users"); status = pthread_mutex_unlock(&mtx); return -1; } else { //memcpy( *prt, header, sizeof(**prt)); memcpy( *prt, header, bytesRead); DEBUG_PRINT("Users copied to main list"); status = pthread_mutex_unlock(&mtx); for ( short int i=0;i<4 ; i++ ) { DEBUG_PRINT("i= %hd",i); DEBUG_PRINT("User id: %d",holder.user_manage[i].user_id ); DEBUG_PRINT("Permission: %d",holder.user_manage[i].permission); DEBUG_PRINT("other_ID:%ld",holder.user_manage[i].other_id); DEBUG_PRINT("Check_value:%ld", holder.user_manage[i].check); } return 1; } } } if ( NULL == prt ) { DEBUG_PRINT("Pointer is null!"); return 0; }
}
主要(){
db_read_from_file(&holer.user_manage, holder.check_mutex); db_read_from_file(&holder.user_manage_backup, holder.backup_mutex);
}
我不确定我是否正在检查null prt,但其余的工作正常。 我做了一个小改动是“完美”只是缺少的东西是发送文件名作为函数的输入。它看起来像互斥锁100%肯定工作。