【问题标题】:Allocating memory dynamically to a 2-d array of strings将内存动态分配给二维字符串数组
【发布时间】:2013-11-05 04:48:21
【问题描述】:
int ReadNames(char ***Names, int *r,int *c)    
{
int i, j, k;
char name[100];
printf("Number of Rows: ");
scanf("%d", r);

printf("Number of Columns: ");
scanf("%d", c);

Names=(char ***)malloc(sizeof(char **)*(*r));
for(i=0;i<(*r);i++)
*(Names+i)=(char **)malloc(sizeof(char *)*(*c));

for(i=0;i<(*r);i++)
for(j=0;j<(*c);j++)
{
fflush(stdin);
gets(name);
strcpy(*(*(Names+i)+j),name);
}
return 1;
}

我正在尝试将内存分配给二维字符串数组。稍后我想按行和按列对它们进行排序,但是在分配内存时,程序没有响应。我的代码中有什么我正在做的事情吗?

在main函数中readname被称为

    ReadNames(&p,&r,&c)

其中 r 和 c 是编号。行数和列数。

【问题讨论】:

  • the program is not responding - 在调试器中运行它或粘贴一些 printfs 以查看它卡在哪里。
  • @John3136 在复制它被卡住的字符串时......即在“strcpy(*(*(Names+i)+j),name);”行中
  • 请缩进。你不关心其他人,至少可以让他们免于阅读未缩进代码的痛苦吗?哎呀..说真的,要问多少钱?
  • 抱歉压痕不好...下次不会发生
  • 始终检查输入的值并从您调用的函数返回值,以消除错误源并在声明变量时初始化所有变量。

标签: c memory dynamic multidimensional-array dynamic-memory-allocation


【解决方案1】:

你需要:

*Names = (char **)malloc(sizeof(char **) * (*r));

以及随之而来的变化。

您传递一个三指针是为了能够返回一个双指针。您正在做的是丢失有关在何处存储双指针的信息。

被删除的评论有些道理;还有一个失误。二维字符串数组意味着您在基本数据中具有三个级别的指针。而且你需要第四级指针才能传递给函数。

另外,使用gets() 会导致灾难。不要永远(如从不,如从不)使用gets()函数。甚至在玩具程序中也没有。它会让你养成坏习惯。第一个 Internet 蠕虫通过使用gets() 的程序传播(谷歌搜索'morris internet worm')。

在 Unix 和其他基于 POSIX 的系统上,使用 fflush(stdin) 会导致未定义的行为。在 Windows 上,行为由 Mi​​crosoft 定义。如果您在 Windows 上运行,那么您可以;如果不是,你不是。


我认为Three-Star Programming 很糟糕!

这可能不是我这样做的方式,但它是将您编写的内容直接转换为有效的内容,以及一个测试它并释放所有分配内存的main() 程序。它假定strdup() 可用;如果没有,写起来很简单。

样本输出:

Number of Rows: 2
Number of Columns: 3
R0C0: Row 1, Column 1.
R0C1: Ambidextrous Armless Individual.
R0C2: Data for the third column of the first row.
R1C0: Row 2, Column 1.
R1C1: Row 2, Column 2.
R1C2: Given that the number of rows is 2 and the number of columns is 3, this should be the last input!
Rows = 2, cols = 3.
[0,0] = <<Row 1, Column 1.>>
[0,1] = <<Ambidextrous Armless Individual.>>
[0,2] = <<Data for the third column of the first row.>>
[1,0] = <<Row 2, Column 1.>>
[1,1] = <<Row 2, Column 2.>>
[1,2] = <<Given that the number of rows is 2 and the number of columns is 3, this should be the last input!>>

有效的 4 星代码:

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

static void ReadNames(char ****Names, int *rows, int *cols)
{
    char name[100];
    printf("Number of Rows: ");
    scanf("%d", rows);

    printf("Number of Columns: ");
    scanf("%d", cols);

    int c;
    while ((c = getchar()) != EOF && c != '\n')
        ;

    *Names = (char ***)malloc(sizeof(char ***)*(*rows));
    for (int i = 0; i < (*rows); i++)
        (*Names)[i] = (char **)malloc(sizeof(char **)*(*cols));

    for (int i = 0; i < (*rows); i++)
    {
        for (int j = 0; j < (*cols); j++)
        {
            printf("R%dC%d: ", i, j);
            if (fgets(name, sizeof(name), stdin) == 0)
            {
                fprintf(stderr, "Unexpected EOF\n");
                exit(1);
            }
            name[strlen(name)-1] = '\0';    // Zap newline
            (*Names)[i][j] = strdup(name);
        }
    }
}

int main(void)
{
    int rows;
    int cols;
    char ***data = 0;

    ReadNames(&data, &rows, &cols);
    printf("Rows = %d, cols = %d.\n", rows, cols);
    for (int i = 0; i < rows; i++)
    {
        for (int j = 0; j < cols; j++)
            printf("[%d,%d] = <<%s>>\n", i, j, data[i][j]);
    }

    for (int i = 0; i < rows; i++)
    {
        for (int j = 0; j < cols; j++)
            free(data[i][j]);
        free(data[i]);
    }
    free(data);
    return 0;
}

替代 3 星代码

使用三级指针已经够糟糕了;四是可怕的。此代码将自身限制为三个级别的指针。我假设 C99 兼容,因此可以在函数中方便时声明变量。使用 C89/C90 编译器(现在已经倒退 14 年)的更改非常简单。

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

static char ***ReadNames(int *r, int *c)
{
    int i, j;
    char name[100];
    printf("Number of Rows: ");
    scanf("%d", r);

    printf("Number of Columns: ");
    scanf("%d", c);

    int x;
    while ((x = getchar()) != EOF && x != '\n')
        ;

    char ***Names = (char ***)malloc(sizeof(char ***)*(*r));
    for (i = 0; i < (*r); i++)
        Names[i] = (char **)malloc(sizeof(char **)*(*c));
    for (i = 0; i < (*r); i++)
    {
        for (j = 0; j < (*c); j++)
        {
            if (fgets(name, sizeof(name), stdin) == 0)
            {
                fprintf(stderr, "Unexpected EOF\n");
                exit(1);
            }
            name[strlen(name)-1] = '\0';
            Names[i][j] = strdup(name);
        }
    }
    return Names;
}

static void PrintNames(char ***Names, int r, int c)
{
    int i, j;
    for (i = 0; i < r; i++)
    {
        for (j = 0; j < c; j++)
            printf("%s ", Names[i][j]);
        printf("\n");
    }
}

int main(void)
{
    int rows;
    int cols;
    char ***data = ReadNames(&rows, &cols);

    PrintNames(data, rows, cols);

    printf("Rows = %d, cols = %d.\n", rows, cols);
    for (int i = 0; i < rows; i++)
    {
        for (int j = 0; j < cols; j++)
            printf("[%d,%d] = <<%s>>\n", i, j, data[i][j]);
    }

    for (int i = 0; i < rows; i++)
    {
        for (int j = 0; j < cols; j++)
            free(data[i][j]);
        free(data[i]);
    }
    free(data);
    return 0;
}

示例输出

Number of Rows: 3
Number of Columns: 4
R1C1
R1C2
R1C3
R1C4-EOR
R2C1
R2C2
R2C3
R2C4-EOR
R3C1
R3C2
R3C3
R3C4-EOR
R1C1 R1C2 R1C3 R1C4-EOR 
R2C1 R2C2 R2C3 R2C4-EOR 
R3C1 R3C2 R3C3 R3C4-EOR 
Rows = 3, cols = 4.
[0,0] = <<R1C1>>
[0,1] = <<R1C2>>
[0,2] = <<R1C3>>
[0,3] = <<R1C4-EOR>>
[1,0] = <<R2C1>>
[1,1] = <<R2C2>>
[1,2] = <<R2C3>>
[1,3] = <<R2C4-EOR>>
[2,0] = <<R3C1>>
[2,1] = <<R3C2>>
[2,2] = <<R3C3>>
[2,3] = <<R3C4-EOR>>

两个程序都在valgrind下运行干净。

【讨论】:

  • Leffer.....这样做有什么问题 Names=(char ***)malloc(sizeof(char **)*(*r));名称包含具有数据类型作为双指针的数组的基地址......即姓名[i]
  • 它不像你想象的那样做。特别是,它不会改变调用函数中的指针,一旦你完成了赋值,你就无法改变调用函数中的指针,因为你已经将指针指向了那个指针。
  • 另外,您的问题是您没有将char **** 传递给函数......并且您没有为字符串分配足够的空间。假设用户输入 3 行 2 列;然后,用户应该键入 6 行数据,这些数据将在调用函数中存储和访问?
  • @Jonathan..我刚刚根据您的解释解决了这个问题..存储字符串很好..但是打印再次产生问题..我已经分享了代码...wat否则可能是个问题?
【解决方案2】:

所以,这就是代码工作......

    *Names=(char **)malloc(sizeof(char **)*(*r));    
for(i=0;i<(*r);i++)    
    *(*Names+i)=(char*)malloc(sizeof(char *)*(*c));    
for(i=0;i<(*r);i++)
for(j=0;j<(*c);j++)
{
fflush(stdin);
gets(name);
strcpy((*(*Names+i)+j),name);
}

但是在打印存储的这些名称时...我提供了一个功能..

int PrintNames(char **Names, int r, int c)
{

int i,j;
for(i=0;i<r;i++)
{   printf("\n");
    for(j=0;j<c;j++)
        printf("%s ",*(*(Names+i)+j));
}
return 1;

}

现在这个 PrintNames 也通过 main...调用为 "PrintNames(p, r, c);"....但是程序在打印时停止...可能出了什么问题?

【讨论】:

  • 这不是答案;它属于作为修正案的问题。保留原始代码不变,但也添加它。为什么人们喜欢使用*(*(Names+i)+j) 而不是更简单的Names[i][j]
  • @JonathanLeffler 很好地使用 Names[i][j] 也不能解决问题!
  • 在您的PrintNames() 中,我收到编译器警告:2dsb.c: In function ‘PrintNames’: 2dsb.c:36:13: error: format ‘%s’ expects argument of type ‘char *’, but argument 2 has type ‘int’ [-Werror=format=] printf("%s ", *(*(Names+i)+j)); 这表明存在问题。我(最终)意识到,您确实需要一个用于 main() 中的数据的三重指针,并且您需要在 PrintNames() 中使用它;在传入三重指针的地址时,您需要在 ReadNames() 中使用四重指针;如果您返回三重指针(并且不采用指针参数),您可以简化事情。等等。
猜你喜欢
  • 1970-01-01
  • 2021-12-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-07-11
  • 2014-01-05
  • 1970-01-01
相关资源
最近更新 更多