【问题标题】:Failing to alloc memory received by a pointer linux无法分配指针linux接收到的内存
【发布时间】:2014-06-19 13:49:02
【问题描述】:

我有一个函数,它通过指针接收存储位置。这个地方可以有不同的其他类似结构。函数必须读取文件。该文件存储了一个结构,我需要阅读它。

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== 由 0x20303333: ???
==2746== 地址 0x0 没有被堆栈、malloc 或(最近)释放

这是 "DEBUG_PRINT("User id: %d",holder.user_manage[i].user_id );" 的行所以显然看起来我没有将它存储在正确的位置。 你能帮帮我吗?

【问题讨论】:

  • 不确定这是否是您的确切问题的原因,但在 memcpy( (struct user_manage_t *) &amp;prt, &amp;buffer, 90); 中,您将 90 个字节复制到存储 prt 指针变量的位置,而不是它指向的位置。
  • 我相信某事有道理,看起来大错特错。
  • sth 是对的,memcpy 必须破坏内存,除非您的指针大小恰好是 90 字节......也许考虑检查 prt 是否也有 NULL 指针?
  • 如果我错了请纠正我,但我认为我分配了 10x sizeof(user_manage_t) 有 12 个字节,所以总共 120 个字节
  • @EliasVanOotegem:按照您在 Stack Overflow 上看到的内容,这似乎是演员阵容最常见的用例;)

标签: c pointers struct calloc


【解决方案1】:

优先级 1
在多看你的代码之后,我怀疑你的转换和你一样多,因为你不断收到关于“不兼容的 [pointer] types” 之类的编译器警告。这些警告的存在是有原因的:存在问题,可能是那里的错误来源。不要闭嘴,不要忽视它:修复它!

是的,有时这些转换是必需的,有时编译器会在您知道自己在做什么时抱怨您的代码。在这种情况下,您可以添加强制转换,但不要将这些强制转换视为编译器噱头:它们是告诉编译器您知道自己在做什么的方式。你刚刚疯狂地让编译器闭嘴。这很糟糕。

下一个
在来自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); 

您正在传递&amp;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++)。如果你将一个指针传递给一个指针(&amp;prt),然后取消引用它,你最终会得到一个指针,对吧?这就是您要写的内容 => *(&amp;prt) == prt!

演员表和你使用它的方式表明你相信你正在写任何prt指向的东西,而实际上你正试图向prt指向的任何指针写入90个字节。它指向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

它更清洁、更安全。

还要检查您的函数是否没有传递空指针,取消不必要的强制转换(它们很混乱),并始终检查函数的返回值!

【讨论】:

  • 感谢您的帮助:) 但是我仍然有一个问题/问题,在此代码中我将大小指定为 10x12bytes,但是当我启动程序时这会发生变化,而且我不知道预先设置大小,并且还有其他线程可能会使用此函数,我更愿意在函数内部执行 malloc。我已经更改了代码以检查 nullprt
  • @Kxp:如果你想在函数内部分配内存,那么你可能需要2级间接,或者在最后返回分配的内存......
  • 哦……那是我害怕的事情。你知道任何可以帮助我理解如何做到这一点的网站吗?非常感谢:)
  • @Kxp:Nips,你已经有了三个!间接级别...这简直是邪恶的!
  • @Kxp:只是好奇:你添加这些转换是因为编译器警告吗?? -- 你不知道它是怎么工作的,但是你使用了多个线程??基本的内存管理就是这样:它是基本的。只需 google 一些关于内存管理的 tuts,或搜索 “learn C the hard way”,这是一本免费的在线书籍
【解决方案2】:

这是最终代码,以防有人遇到类似情况:

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;
}

}

main(){

    db_read_from_file(&holer.user_manage, holder.check_mutex);  
    db_read_from_file(&holder.user_manage_backup, holder.backup_mutex);

}

我不确定我是否很好地检查了 null prt,但其余的工作正常。 我做了一些小改动以使其“完美”,唯一缺少的是发送文件名作为函数的输入。看起来互斥锁可以 100% 肯定地工作。

【讨论】:

  • memcpy(*prt, buffer, sizeof(*prt)); 错误; sizeof(*prt) 是指向结构体的指针 的大小,而不是结构体的大小;请改用sizeof(**prt)
  • 是的,那部分是错误的,但是 sizeof(**prt) 只给了我 12 个字节,这是 num=1 时 1 个结构的大小,但是当 num=3 时它仍然给出=12,它应该是这样的吗?我怎样才能拥有分配空间的总空间?
  • 您的最新编辑(使用bytesRead)是正确的方法。 sizeof 在编译时评估;它可以获得单个结构的大小(因为它是在编译时定义的),但不是结构的数量(因为它是在运行时确定的)。
猜你喜欢
  • 2020-06-14
  • 2020-09-22
  • 1970-01-01
  • 2021-06-22
  • 2015-04-21
  • 1970-01-01
  • 1970-01-01
  • 2022-09-24
  • 2016-02-21
相关资源
最近更新 更多