【问题标题】:A dynamic 2d char array动态二维字符数组
【发布时间】:2021-10-08 16:01:15
【问题描述】:

我对动态二维字符数组的 C 代码有疑问:malloc 缓冲区溢出。程序的思路是初始化一个全局的二维字符数组,程序运行时,输入一些单词,保存到那个二维字符数组中。我不熟悉 realloc 函数。这里有什么问题?

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
char **array_history;
int count = 0;
#define MAX_LINE_CHARS 1024
int main (void){

    array_history =  malloc(sizeof(char *));
    while (1) {
        char line[MAX_LINE_CHARS];
        if (fgets(line, MAX_LINE_CHARS, stdin) == NULL)
            break;

        array_history = realloc(array_history, sizeof(char*)*(count + 1));
        int len_size = strlen(line) + 1;

        array_history[count] = malloc(len_size*sizeof(char));
        for (int i = 0; line[i] != '\0'; i++) {
            array_history[count][i] = line[i];
            // printf("%c", line[i]);
        }
        // printf("%s", array_history[0]);
        // for (int i = 0; history[i] != NULL; i++) {
        //     printf("%s\n", history[i]);
        // }
        count++;
    }

    for (int i = 0; array_history[i] != NULL; i++) {
        printf("%s", array_history[i]);
    }

    return 0;
}

【问题讨论】:

  • array_history[i] != NULL 你认为这个哨兵NULL 会来自哪里?通过mallocrealloc 获得的内存不需要初始化。由你决定。您也没有任何关于 NULL 值的内存。你只为你读入的行分配内存。
  • for (int i = 0; array_history[i] != NULL; i++),这一步我要打印array_history
  • 我知道,但你为什么认为会有一个数组元素持有NULL 指针?如果没有这样的数组元素,您的代码将愉快地遍历所有可以访问的内存并访问不允许访问的位置。
  • 另外:你不应该使用这种模式:array_history = realloc(array_history, ...。如果出现错误realloc 将返回NULL,并且您无法再访问之前拥有的内存位置。这包括无法释放该内存的方法。在分配给您传递给realloc的指针之前,请始终使用一些临时变量并检查NULL
  • 您也未能终止您的字符串:for (int i = 0; line[i] != '\0'; i++) 这不会复制0 字节。你为什么不为此目的使用strcpystrdup 或类似名称?

标签: arrays c dynamic


【解决方案1】:

您的代码中有一些错误。 您未能终止您的字符串,并且您未能添加打印字符串时使用的标记值。

固定版本可能如下所示: (您应该为 malloc 等添加更多错误检查。)

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

#define MAX_LINE_CHARS 1024

int main (void){

    char **array_history;
    int count = 0;
    array_history = malloc(sizeof(char *)*(count+1));
    // TODO: Check for NULL
    array_history[0] = NULL;  // Terminate the array.

    while (1) {
        char line[MAX_LINE_CHARS];
        if (fgets(line, MAX_LINE_CHARS, stdin) == NULL)
            break;

        void *temp_ptr = realloc(array_history, sizeof(char*)*(count + 2));
        // TODO: Check for NULL
        array_history = temp_ptr;

        int len_size = strlen(line) + 1;
        array_history[count] = malloc(len_size*sizeof(char));
        array_history[count + 1] = NULL;  // Add sentinel for your array

        int i;
        for (i = 0; line[i] != '\0'; i++) {
            array_history[count][i] = line[i];
            // printf("%c", line[i]);
        }
        array_history[count][i]=0; // Terminate the new string.
        // Or simply use strcpy(array_history[count],line);
        
        // printf("%s", array_history[0]);
        // for (int i = 0; history[i] != NULL; i++) {
        //     printf("%s\n", history[i]);
        // }
        count++;
    }

    // Instead of terminating NULL value you could just use condition `i<count`
    for (int i = 0; array_history[i] != NULL; i++) {
        printf("%s", array_history[i]);
    }

    return 0;
}

【讨论】:

  • 感谢您的帮助!我明白你的意思,我忘了NULL也需要占用。
  • 不光是占用内存,还要把NULL赋给最后一个数组元素。
猜你喜欢
  • 1970-01-01
  • 2011-02-06
  • 2014-11-13
  • 2018-05-17
  • 1970-01-01
  • 1970-01-01
  • 2017-03-11
  • 1970-01-01
相关资源
最近更新 更多