realloc() 没有调整指针数组的大小

realloc() is not resizing the array of pointers

这个程序的主要思想是读取数据并从缓冲区中提取文件和文件夹名称。有效负载数据可能如下所示:cached_folder\test1_file。函数 get_folder_file_name 提取文件夹和文件名,因为我们不知道数据的长度,因此根据需要使用 realloc() 函数扩展缓冲区是合理的,因为它在内存有限的设备上 运行 (嵌入式)。

这是代码:

typedef struct command_packet
{
    uint32_t trigger_mode;
    uint32_t command_status;
    uint8_t payload_data[];
}COMMAND_PACKET;

//This function is called in main whenever there is incoming packet from TCP which has payload, command status and mode.
int32_t Analyse_stream(COMMAND_PACKET *pcommand, int32_t payload_data_length)
{
    char *file_name = (char *)malloc(sizeof(char));
    char *folder_name = (char *)malloc(sizeof(char));
    int file_name_len= 0;
    int folder_len = 0;
    uint16_t status;

    
    if ((status = get_folder_file_name(pcommand->payload_data, payload_data_length, file_name,folder_name, &file_name_len, &folder_len )) != SUCCESS)
    {
        free(file_name);
        free(folder_name);
        return status;
    }

   printf("File Name = %s\n", file_name);
   printf("Folder = %s\n", folder_name);

   free(file_name);
   file_name = NULL;

   free(folder_name);
   folder_name = NULL;
}

//This function is called in stored_byte_stream to extract the folder and file name.
int32_t get_folder_file_name(uint8_t *payload_data, int32_t payload_data_len, char *file_name, char *folder_name, int32_t *file_name_len, int32_t *folder_len )
{
    int i = 0;
    int k=0;
    // Check until null character to get the file name
    // For alignment with u16, single null char is added at the end of the file name for
    // a file name with strlen as odd and two null chars for a file name with even strlen
    do{
        if(payload_data[i] == '/')
        {
          if(i > 0)
              k = i+1;
        }
        i++;
    }while((*(payload_data + i) != '[=10=]') && (i < payload_data_len));

    if(k == 0)
    {
        return FOLDER_NAME_IS_EMPTY;
    }

    if (i == payload_data_len)
    {
        // Null char search completed till the end of the payload len, No filename found
        return FILE_NAME_NOT_FOUND;
    }

    if (i == 1)
    {
        // File Name strlen = 0; implies that the file name was not provided
        return FILE_NAME_IS_EMPTY;
    }

    *folder_len = k+1;
    *file_name_len= i-k+1;
    
    folder_name = realloc(folder_name, sizeof(char) *(*folder_len));
    strncpy(folder_name, (char *)payload_data, *folder_len -1);
    

    file_name = realloc(file_name, sizeof(char) *(*file_name_len));
    strncpy(file_name, (char *)payload_data + k, *file_name_len);

    return SUCCESS;
 }

所以,我面临的问题是每当 file_name_len 或 folder_len 的大小超过 13 时,它什么都不打印。函数 get_folder_file_name return 的空文件名或文件夹名以超过 13 者为准。但是在同一函数中 folder_name & file name 也有正确的数据,但是当它们 return 如果其中任何一个超过 13 个长度,则缓冲区为空。如果我在 char *file_name = (char *)malloc(15);char *folder_name = (char *)malloc(15); 之类的初始化中分配固定内存,然后执行 realloc() ,问题就会得到解决。我做错了什么?

realloc 返回的指针不一定仍然指向与传递的相同的地址。

Analyse_stream中,一旦您调用reallocfile_namefolder_name可能不再指向相关地址。它们不会得到更新,因为在 get_folder_file_name 中你只更新这些变量的本地副本,而不是调用方的那些。

您基本上有一个更复杂的常见问题解答错误版本:

尽管整个程序看起来不必要地缓慢和复杂 - 为什么您不能静态分配固定大小(如 256 字节)并跳过所有缓慢的重新分配调用?

与您的问题无关,请注意 strncpy 是一个危险的函数,绝不能用于任何目的。参见 Is strcpy dangerous and what should be used instead?

您的代码中的问题不在于您如何在 get_folder_file_name 中分配字符串,而是您在该函数中所做的更改在 Analyse_stream 中不可见。该函数中的 file_namefile_folder 仍然是您首先分配的 1 字节块。

(当您在没有分配的情况下尝试打印这些字符串时,您可能会遇到分段违规,并且您觉得需要先分配虚拟字符串。这不是必需的;所有正确的分配都在 get_folder_file_name.)

函数分配或 re-allocate 内存是很常见的,因此有几种习惯用法。

一个非常常见的是 return 分配的数据:

char *get_file_name(..., uint32_t *length)
{
    char *result;

    // determine string s of length l somehow

    result = malloc(l + 1);
    if (result == NULL) return NULL;

    *length = l;
    strcpy(result, s);

    return result;
}

并像这样使用它:

uint32_t len;
char *fn = get_file_name(..., &len);

// use fn if not NULL

free(fn);

在您的例子中,您有两个字符串,因此这可能不切实际。您还可以传入指向每个字符串的指针,以便该函数可以通过它修改字符串,就像您已经对长度所做的一样:

int get_ffn(..., char **file, char **folder)
{
    // determine strings s1 and s2 of lengths l1 and l2 somehow

    *file = malloc(l1 + 1);
    *folder = malloc(l2 + 1);

    if (*file == NULL || *folder == NULL) {
        free(*file);
        free(*folder);
        return MEMORY_ERROR;
    }

    strcpy(*file, s1);
    strcpy(*folder, s2);

    return OK;
}

然后在 Analyse_stream 中调用它:

char *file;
char *folder;
int error = get_ffn(..., &file, &folder);

如果error == OK,字符串现在有相关数据,使用后必须free

有很多要传递的指示。您可以通过创建结构使界面更简单:

struct path {
    char *folder;
    char *file;
};

int get_path(struct path *path, ...)
{
     // ...

     path->file = malloc(l1 + 1);
     path->folder = malloc(l2 + 1);

     return OK;
}

并这样称呼它:

struct path path;

if (get_path(&path, ...) == OK) ...

但是完成后,您必须 free 结构中的字符串,就像上面的其他示例一样。

如果您知道有效负载的大小相当小并且适合堆栈,则可以不进行动态分配并创建两个由另一个函数填充的字符串:

char file[PAYLOAD_MAX];
char folder[PAYLOAD_MAX];

if (fill_in_ff(..., file, folder) == OK) ...

然后该函数仅将这些 char 数组作为参数,这些数组将“衰减”为指针:

int fill_in_ff(..., char *file, char *folder)
{
    // ... find out lengths ...
    // ... no allocation ...

    memcpy(file, s1, l1);
    memcpy(file, s2, l2);

    s1[l1] = '[=17=]';
    s2[l2] = '[=17=]';

    return OK;
}