c-更改多维数组中的一个元素会更改所有具有值的元素



我正在尝试编写一个程序,让用户将数据放入多维数组中,并将其显示为表。这是我的代码的简化版本:

#include <stdio.h>
#include <stdlib.h>
#define ROWS 5
#define COLS 5
int main(void) {
int row, col;
char *table[ROWS][COLS], text[11];
for (int i = 0; i < ROWS; i++)
for (int j = 0; j < COLS; j++)
table[i][j] = malloc(11);
while (1) {
printf("> ");
scanf("%d %d %s", &row, &col, text);
if (row > ROWS || col > COLS)
return 1;
table[row][col] = text;
for (int i = 0; i < ROWS; i++) {
for (int j = 0; j < COLS; j++)
printf("|%10s|", table[i][j]);
printf("n");
}
}
return 0;
}

我可以输入第一个值,它将被正确存储,如下所示:

$ ./a.out
> 0 0 foo
|       foo||          ||          ||          ||          |
|          ||          ||          ||          ||          |
|          ||          ||          ||          ||          |
|          ||          ||          ||          ||          |
|          ||          ||          ||          ||          |

然而,当我尝试输入第二个值时,第一个值也会发生变化:

> 0 1 bar
|       bar||       bar||          ||          ||          |
|          ||          ||          ||          ||          |
|          ||          ||          ||          ||          |
|          ||          ||          ||          ||          |
|          ||          ||          ||          ||          |

如果我输入第三个、第四个、第五个等值,这种情况就会继续;所有的值都被改变了。

为什么会发生这种情况,我该如何阻止它的发生?

当你这样做时:

table[row][col] = text;

您正在破坏先前从malloc获得的table中的值任何循环迭代都将使table值指向相同的内存位置(即text(。

您想要:

strcpy(table[row][col],text);

此外,您的row/col限额检查需要>=


这是更正后的代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define ROWS 5
#define COLS 5
int
main(void)
{
int row, col;
char *table[ROWS][COLS], text[11];
for (int i = 0; i < ROWS; i++)
for (int j = 0; j < COLS; j++)
table[i][j] = malloc(11);
while (1) {
printf("> ");
scanf("%d %d %s", &row, &col, text);
// NOTE/BUG: the limit check is incorrect
#if 0
if (row > ROWS || col > COLS)
return 1;
#else
if (row >= ROWS || col >= COLS)
return 1;
#endif
// NOTE/BUG: this blows away the value obtained from malloc
#if 0
table[row][col] = text;
#else
strcpy(table[row][col],text);
#endif
for (int i = 0; i < ROWS; i++) {
for (int j = 0; j < COLS; j++)
printf("|%10s|", table[i][j]);
printf("n");
}
}
return 0;
}

更新:

请注意,虽然上述方法有效,但它有点脆弱。

如果输入的文本行是(例如q(,则程序进入无限循环。

11硬接线。最好像使用ROWSCOLS一样使用#define

没有检查text缓冲区是否溢出。

我建议使用fgetsstrtolstrsep,因为错误检测和恢复要好得多。

此外,malloc预分配11的固定阵列。如果我们要硬接线,我们还不如省去malloc,做:

char table[ROWS][COLS][11];

根据最终用途,可能最好最初填充table,只根据需要填充元素(即NULL的初始值(。然后,使用realloc添加元素。

此外,我不确定printf的格式是否正是您想要的(例如||(。

因此,我对代码进行了更多的概括。其中一些可能会有所帮助[有些可能对您的用例过于花哨]:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define ROWS    5
#define COLS    5
int
main(void)
{
int row;
int col;
int len;
char **tp;
char *bp;
char *cp;
int maxlen = 0;
char buf[1000];
char *table[ROWS][COLS];
for (int i = 0; i < ROWS; i++)
for (int j = 0; j < COLS; j++)
table[i][j] = NULL;
while (1) {
printf("> ");
// get next line -- stop on EOF
bp = fgets(buf,sizeof(buf),stdin);
if (bp == NULL)
break;
// strip newline
cp = strchr(bp,'n');
if (cp != NULL)
*cp = 0;
cp = bp;
// get row number -- skip with garbage after it (e.g. 23x)
row = strtol(cp,&cp,10);
if (*cp++ != ' ')
continue;
if ((row < 0) || (row >= ROWS))
continue;
// get column number -- skip with garbage after it (e.g. 23x)
col = strtol(cp,&cp,10);
if (*cp++ != ' ')
continue;
if ((col < 0) || (col >= COLS))
continue;
// look for text
#ifdef WORDONLY
// this skips internal whitespace (e.g. "hello world" --> "hello")
bp = cp;
cp = strsep(&bp," ");
if (cp == NULL)
continue;
#else
// this preserves internal whitespace (e.g. "hello world")
for (;  *cp != 0;  ++cp) {
if (*cp != ' ')
break;
}
if (*cp == 0)
continue;
#endif
// get the text length
len = strlen(cp);
if (len > maxlen)
maxlen = len;
// point to table entry
tp = &table[row][col];
// resize it (allowing for EOS)
*tp = realloc(*tp,len + 1);
// copy in the current buffer token
strcpy(*tp,cp);
char fmt[10];
sprintf(fmt," %%%ds |",maxlen);
for (int i = 0; i < ROWS; i++) {
printf("|");
for (int j = 0; j < COLS; j++) {
cp = table[i][j];
if (cp == NULL)
cp = "";
printf(fmt, cp);
}
printf("n");
}
}
return 0;
}

最新更新