我正在尝试学习C.我想从我从文件中获得的1D数组填充2D数组。
现在,我正在尝试将数组指针的元素(输出:Hello,My,name,is,Ram.)放入一个名为words的2D数组中。其目的是删除逗号并突出显示不同行的每个单词。我已经实现了这一点,但我得到一些胡言乱语随着我的输出。我逐个检查了我的条目,发现第一行(Hello, my,name,is,Ram.)存储在word[]中的第1行到第5行。然而,下一行(I,own,20,thousand,bucks.)从第[10]行开始,我不明白为什么?加上我的输出看起来很奇怪,有一些未知的值。请告诉我我应该怎么做来纠正我的输出和大小的二维数组等于它包含的值
下面是我的代码:
int main(int argc, const char * argv[]) {
// insert code here...
FILE *fp;
char (*points)[50];
char *array;
int width=20,height=50;
char *word;
char words [width][height];
int counter=0; // To traverse through array and tracks the current position in array.
points = malloc(sizeof(*points) * 2);
word=malloc(width*height*sizeof(char));
if (points == NULL) {
perror("malloc");
exit(0);
}
fp = fopen("/Users/shubhamsharma/Desktop/data.txt", "r");
if (fp == NULL) {
perror("fopen");
exit(EXIT_FAILURE);
}
fgets(points[0], sizeof(*points), fp);
fgets(points[1], sizeof(*points), fp);
array=points[0];
printf("%s", points[0]);
printf("%s", points[1]);
for(int i=0;i<width;i++)
{
for(int j=0,p=counter;j<height;j++,p++)
{
if(array[p]==','||array[p]==' ')
{
words[i][j]='n';
counter=++p;
break;
}
else
words[i][j]=array[p];
}}
printf("n%c",words[16][0]);
for (int i=0; i<width; i++) {
for (int j=0; j<height; j++) {
if(words[i][j]=='n')
{
break;
}
printf("nPrinting element in wordn");
printf("%c",words[i][j]);
}
}
printf("n");
fclose(fp);
free(points);
return 0;
return 0;
}
输出:> Hello,My,name,is,Ram. I,own,20,thousand,bucks. Printing element in word
> HelloMynameisRam.+̮213377310`267t377̮213377Iown20thousandbucks.
> Program ended with exit code: 0
我的文件中的行看起来像。-
Hello,My,name,is,Ram.
I,own,20,thousand,bucks.
有很多要讨论的,也许太多了,因为stackoverflow更喜欢一个答案,所以让我来总结一下跳出来的问题。
char words[width][height];
我看不出这将如何为你编译。这两个整数宽度和高度不是常量,这在以这种方式分配时是必需的。
这在c++和C中是不同的,这就是为什么我们要明确你要用什么来编译,如果你打算用C而不是c++来写,这是至关重要的。
假设是C,您需要某种方法来定义这两者。也许:
#define WIDTH 20
#define HEIGHT 50
虽然我早就放弃了C而选择了c++,但我认为C编译器没有其他选择。
,
int width = WIDTH, height = HEIGHT;
这只是为了确保只有一个地方可以获得这些值。现在
char words[WIDTH][HEIGHT];
将编译。它声明了一个包含20个字符数组的数组,每个数组长50字节。这将对应于它在其余代码中的用法。对我来说,选择的两个词似乎在意义上是相反的,因为我们通常认为行是高度,而每行中的字符串似乎是长度(或宽度),但这并不是真正的问题。否则,可以。
然而,这把我们带到了
points = malloc(sizeof(*points) * 2);
这对point的声明没有意义:
char (*points)[50];
我猜不出这是什么意思。编译器似乎认为这是一个char[50] *
,一个指向50字节数组的指针,但这是因为*points
周围的括号。看起来您可能已经将它放在那里,以便在它不存在时阻止编译器投诉。这个声明将是一个包含50个指向char的指针的数组(或者一行中有50个char *);
char * points[50];
表示编译器不接受:
points = malloc(sizeof(*points) * 2);
但是,它允许的是:
points[0] = malloc( sizeof( *points ) * 2 );
在后面的代码中就是这样使用的。这和你想的不一样。您要分配的是100字节(在大多数编译器上),这是*points
大小的两倍,表明您需要为两个字符数组(每个字符数组50字节)提供空间。然而,您得到的是一个100字节的字符数组。
这很重要,因为在代码中,它与:
一起使用fgets(points[0], sizeof(*points), fp);
fgets(points[1], sizeof(*points), fp);
array=points[0];
printf("%s", points[0]);
printf("%s", points[1]);
使用points[1]
,但是在[1]点没有分配任何资源。事实上,我不确定编译器生成了什么,原始形式的代码不会编译,但是以这种方式使用的点需要两个指针赋值,而不是一个。
points[0] = malloc( sizeof( *points ) );
points[1] = malloc( sizeof( *points ) );
可能使上面的用法有效,尽管不清楚为什么大小是基于点数数组的,也许说
更合乎逻辑。points[0] = malloc( HEIGHT );
points[1] = malloc( HEIGHT );
所以这些点可以更合理地声明
char * points[2];
这就是它的用法。
需要说明的是,在提供的代码中,没有明确的方法说明使用points[0]
和points[1]
是有意义的。后面使用char * array;
表明您希望两个fgets
操作将内容放置在一个连续的RAM块中,这可以被安排,但不像这里构造的那样可靠。
当你打印两行
时,它可能看起来工作。printf("%s", points[0]);
printf("%s", points[1]);
但它确实看起来更像是一个副作用,而不是一个计划。
基于你对数组的使用:
for(int i=0;i<width;i++)
{
for(int j=0,p=counter;j<height;j++,p++)
{
if(array[p]==','||array[p]==' ')
{
words[i][j]='n';
counter=++p;
break;
}
else
words[i][j]=array[p];
}
}
看来你的意思更像是:
array = malloc( HEIGHT * 2 );
之后,这可能已经完成了您所期望的。
fgets( array, HEIGHT * 2, fp );
,你可以(为什么我不确定)对齐点
points[0] = array;
points[1] = array + HEIGHT;
我还应该指出,在上面的循环中并没有出现处理字符串终止为零的情况。
这意味着单词可能包含垃圾,除非每个单词都是19个字符,并以n
结尾,并且没有零结尾。
考虑这些要点,也许我们可以在代码中编辑它来推进您的计划。
您的代码缺少#include <stdio.h>
和#include <stdlib.h>
。
之后,你的代码正确分配内存;但你从不使用word
,所以它可以被删除。
你的代码正确读取第一行。然而,在条件array[p] == ' '
之后,下一次进入j
循环时,它只是在fgets
读取的数据结束后继续从points[0]
读取垃圾。这会导致未定义的行为,你很幸运,结果甚至像它们一样连贯。
您需要为array[p] == ' '
案例提供额外的代码来将array
移动到读取下一行,例如array = points[1]; p = counter = 0; break;
。(实际上p
在这个循环中是多余的,你可以直接使用counter
)
这将涉及一个额外的变量来跟踪您所达到的points
索引,并确保您不会离开结束。
一个更好的方法是只读取每一行,因为你正在处理它:摆脱array
,有一个单独的缓冲区char line[50];
,并在开始时调用fgets
,然后每次你到达' '
处理该行。
(你的整个算法可以得到很大的改进,但我把这个问题留给你:学习的一部分是按照你想的方式做事,看看你最终得到的东西的优缺点,然后试着自己改进它)
最后,显示字符串的代码是错误的。根据输入文件的不同,words[16][0]
可能超出了您所读内容的末尾,并且当前在每个字符之前打印Printing element in word
。你在你的问题中发布的示例输出没有显示这一点,所以我猜你发布的代码与你测试的代码不匹配。
相反,我建议你更新你的"读取"代码以null终止字符串(使用words[i][j]=' ';
而不是words[i][j]='n';
),然后你可以使用标准函数来打印它们:
for (int n = 0; n < i; n++)
printf("%sn", words[n]);
这是你的代码与我所建议的最小的变化工作。我放入了一些调试printf
行,您可以取消注释以查看它是如何工作的,并且我更改为使用stdin
而不是打开文件,以便可以看到它在在线编译器中工作。您仍然可以做很多事情来改进您的代码!(首先,处理fgets
在缓冲区中留下的额外n
)