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;
您正在丢弃table
先前从Any 循环迭代中获得的值,这malloc
将使该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
是硬连线的。最好使用#define
just likeROWS
和COLS
没有检查是否溢出缓冲区text
。
我会重新编码使用fgets
,因为错误检测strtol
和strsep
恢复要好得多。
此外,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;
}
推荐阅读
- javascript - 如何将两个数组作为键和值合并到一个具有多个值的键的对象中?
- python - Plotly hover_data 不适用于 dict?
- razor - 如何在 Razor Dotnet 核心项目的子文件夹中运行 Blazor 应用程序项目?
- api - 如何使用推送通知和 API 制作反应原生应用程序
- r - 如何在 R 中编写一个函数来复制多个列,每次添加不同的后缀?
- java - 在同一按钮上使用动作侦听器时出现摆动错误
- python - 如何获取 boost.python 教程示例以链接 Python3:Raspberry Pi3 / boost 1.72 (linux)
- android - 什么是 Android 中的高程叠加
- flutter - 如何添加要在收藏夹页面上显示的项目?
- github - 用于谷歌聊天的 Github BOT