重新分配内存后指针指向错误的方向

Pointer points to wrong direction after reallocating memory

在第一次调用 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;
}

这些陈述

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

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

避免这种情况的选项是:

  1. malloc() 每个 BakeType 分别。因此,列表不是实际的 BakeType,而是指向 BakeType 的指针。然后只有保存指针的数组会被移动。请注意,malloc()ed 块有开销。所以如果你的 BakeType 真的只是一个 char*,直接去掉 BakeType 和 return 和 char*。如果您需要更多字段,可能没问题。

  2. 而不是returning一个BakeType*,returnbaketypelistcounter -1,即索引,而用bakeTypeList[theIndex]代替得到一个指针,当你真正需要它的时候。这当然只有在您只希望添加到列表中并且从不删除时才有效,因为如果您删除较低的索引,所有较高的索引都会改变。

正如其他人所提到的,您对 name 的分配是错误的。它 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 内存块,所以你的变量只包含内存块的地址。因此,将一个字符串分配给另一个字符串不会将一个字符串复制到另一个字符串,而只是引用另一个字符串。