【问题标题】:Pointer points to wrong direction after reallocating memory重新分配内存后指针指向错误的方向
【发布时间】:2019-12-04 18:58:12
【问题描述】:

在第一次调用addBakeType() 后,它正确地将新的 BakeType 对象指针添加到数组,但在第二次调用它之后,它似乎在realloc() 期间更改了数组的地址,因此指向数组中前一个元素的指针正在获取搞砸了,指向错误的记忆。任何想法如何处理它?

typedef struct BakeryType {
    char *name;
} BakeType;

BakeType *bakeTypeList=NULL;
int baketypelistcounter=0;


BakeType* addBakeType(char *str){
    baketypelistcounter++;
    bakeTypeList = realloc(bakeTypeList, baketypelistcounter * sizeof (BakeType));
    BakeType *newBakeType = bakeTypeList + baketypelistcounter - 1;
    newBakeType->name=malloc(10* sizeof(char));

    newBakeType->name=str;
    return newBakeType;
}

【问题讨论】:

  • 你不能。使用索引号作为参考,相对于数组的开头而不是指针。
  • 您需要在存储结构时对字符串进行strdup,或者在手动为其分配内存时对其进行strcpy(正如您所做的那样,尽管您应该根据字符串长度分配正确的内存量,而不是固定数量的 10 个字节)

标签: c arrays malloc realloc


【解决方案1】:

这些陈述

newBakeType->name=malloc(10* sizeof(char));

newBakeType->name=str;

导致内存泄漏。

首先指针newBakeType->name指向分配的内存,然后被指针str的值覆盖。

您应该使用标准的 C 函数 strcpy 或 strncpy 作为示例

strcpy( newBakeType->name, str );

但在此调用之前,您必须分配正确大小的内存,例如

newBakeType->name = malloc( strlen( str ) + 1 );

这是一个演示程序。

#include <stdio.h>
#include <stdlib.h>
#include<string.h>

typedef struct BakeryType {
    char *name;
} BakeType;

BakeType *bakeTypeList=NULL;
int baketypelistcounter=0;


BakeType* addBakeType( const char *str ){
    BakeType *newBakeType = NULL;

    BakeType *tmp = realloc(bakeTypeList, ( baketypelistcounter + 1 ) * sizeof (BakeType));

    if ( tmp != NULL )
    {
        baketypelistcounter++;
        bakeTypeList = tmp;

        newBakeType = bakeTypeList + baketypelistcounter - 1;

        newBakeType->name=malloc( strlen( str ) + 1 );

        if ( newBakeType->name != NULL )
        {
            strcpy( newBakeType->name, str );
        }

    }

    return newBakeType;
}

int main(void) 
{
    BakeType  *lastBakeType =  addBakeType( "A" );

    puts( lastBakeType->name );

    lastBakeType =  addBakeType( "B" );

    puts( lastBakeType->name );

    for ( const BakeType *current = bakeTypeList; 
          current != bakeTypeList + baketypelistcounter;
          ++current )
    {
        puts( current->name );
    }

    return 0;
}

它的输出是

A
B
A
B

【讨论】:

    【解决方案2】:

    你不能那样做。当你重新分配内存块并使内存块变大时,如果内存块后面有另一个内存块,则可能需要移动内存块,防止它增长。

    避免这种情况的选择是:

    1. malloc() 每个 BakeType 单独。因此,列表不是实际的 BakeType,而是指向 BakeType 的指针。然后只有保存指针的数组将被移动。请注意,malloc()ed 块存在开销。因此,如果您的 BakeType 真的只是一个 char*,只需去掉 BakeType 并直接返回 char*。如果您期望更多字段,那可能没问题。

    2. 不要返回BakeType*,而是返回baketypelistcounter -1,即索引,并在您真正需要时使用bakeTypeList[theIndex] 来获取指针。当然,这仅适用于您只希望添加到列表中而从不删除的情况,因为如果您删除较低的索引,所有较高的索引都会改变。

    正如其他人所提到的,您对名称的分配是错误的。它malloc()s 10 个字节,然后用字符串常量的地址覆盖指针。您的代码的正确版本是:

    int strByteCount = strlen(str) + 1;
    newBakeType->name = malloc(strByteCount * sizeof(char));
    memcpy(newBakeType->name, str, strByteCount);
    

    或者更短

    newBakeType->name = strdup(str);
    

    因为 C 中的字符串只是 malloc()ed 内存块,所以你的变量只包含内存块的地址。因此,将一个字符串分配给另一个字符串不会将一个字符串复制到另一个字符串,而只是引用另一个字符串。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-01-29
      • 2020-09-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-03-19
      • 2018-05-16
      • 2021-12-26
      相关资源
      最近更新 更多