我有一个函数,通过指针接收将存储的位置。这个地方可以有不同的其他类似结构。该功能必须读取一个文件。这个文件存储了一个我需要阅读的结构。
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不是堆栈&#39; d,malloc&d; d或(最近)免费&#39;
这是&#34; DEBUG_PRINT(&#34;用户ID:%d&#34;,holder.user_manage [i] .user_id);&#34;所以看起来我好像不把它存放在正确的地方。 你可以帮帮我吗?
答案 0 :(得分:2)
优先级Nr 1
在仔细查看你的代码后,我怀疑你和你一样多投射,因为你不断收到有关&#34;不兼容[指针]类型&#34; 的编译器警告类似。这些警告存在的原因是:存在问题,可能是存在错误的来源。不要慌起来,不要忽视它:修复它!
是的,有时这些演员表是必需的,有时编译器会在你知道你在做什么时抱怨你的代码。在这种情况下,您可以添加一个演员,但不要将这些演员视为编译器 - gags:它们是告诉编译器您知道自己在做什么的方法。你刚刚疯狂地让编译器闭嘴。那太糟糕了。
下一步
在db_read_from_file
来自main
的{{1}}调用中,您将指向指向函数的空指针。这意味着您仍然必须分配内存以实际存储并存储该数据,或者您必须将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
),并取消引用它,你最终得到一个指针,对吧?这就是你要写的东西=&gt; *(&prt) == prt
!
演员阵容以及你使用它的方式表明你相信你正在写任何prt
所指向的内容,而实际上你正在尝试将90个字节写入任何指针{{1指向。并且它指向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
它更干净,更安全。
同时检查你的函数是否没有传递空指针,消除不必要的强制转换(它们混乱),并且总是检查函数的返回值!
答案 1 :(得分:0)
这是最终的代码,以防有些人遇到类似的情况:
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 holder;
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;
}
}
的main(){
db_read_from_file(&holer.user_manage, holder.check_mutex);
db_read_from_file(&holder.user_manage_backup, holder.backup_mutex);
}
我不确定我是否正在检查null prt,但剩下的工作正常。 我做了一些小改动,以完美的#34;只是缺少的东西是发送文件名作为函数的输入。看起来互斥锁正在100%肯定。