我正在努力学习C.我想从一个文件中的一维数组中填充二维数组。
现在,我试图将数组指针(输出:Hello,My,name,is,Ram。)的元素转换为名为words的2D数组。目的是删除逗号并突出显示不同行中的每个单词。我也实现了这一点但是我的输出结果有些胡言乱语。我逐个检查了我的条目,发现第一行(Hello,My,name,is,Ram。)存储在word []的第1行到第5行。然而,下一行(我,拥有,20,千,钱。)从第10行开始,我不明白为什么?加上我的输出看起来很奇怪,有一些未知的值。请告诉我如何更正我的输出并将2 D数组的大小等于它包含的值
这是我的代码:
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]=='\0')
{
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 word\n");
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.+̮\213\377\310`\267t\377̮\213\377Iown20thousandbucks.
> Program ended with exit code: 0
我文件中的行看起来像.-
Hello,My,name,is,Ram.
I,own,20,thousand,bucks.
答案 0 :(得分:0)
要讨论的内容还有很多,也许对于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);
在此点声明之后,这没有意义:
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块中,这个块可以按照这里构造的方式排列,但不可靠。
当您打印两行
时,可能已经看到了SEEMEDprintf("%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]=='\0')
{
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
且没有零终止。
请考虑以下几点,也许我们可以对其进行编辑,以便在代码中推进您的计划。
答案 1 :(得分:-1)
您的代码遗失#include <stdio.h>
和#include <stdlib.h>
。
之后,您的代码正确分配内存;但是你永远不会使用word
所以它可以删除。
您的代码正确读取第一行。但是,在条件array[p] == '\0'
之后,下次进入j
循环时,它会在points[0]
读取的数据结束后继续从fgets
读取垃圾。这导致了未定义的行为,你很幸运,结果甚至是连贯的。
您需要为array[p] == '\0'
案例添加额外代码才能将array
移至阅读下一行,例如array = points[1]; p = counter = 0; break;
。 (实际上p
在此循环中是多余的,您可以直接使用counter
这将涉及一个额外的变量来跟踪你所要达到的points
指数,并确保你不会走到尽头。
更好的方法是在处理时只读取每一行:摆脱array
,拥有一个缓冲区char line[50];
,并在开始时调用fgets
然后每次处理该行时都达到'\0'
。
(你的整个算法可以大大改进,但我会把它留给你:学习的一部分是按你想象的方式做事,看看你最终得到的利弊是什么,然后尝试自己改进它。)
最后,显示字符串的代码是错误的。根据输入文件,words[16][0]
可能会超过您阅读的内容,并且您当前在每个字符之前打印Printing element in word
。您在问题中发布的样本输出并未显示,因此我猜您发布的代码与您测试的代码不符。
相反,我建议你更新你的阅读&#34;代码以null终止字符串(使用words[i][j]='\0';
而不是words[i][j]='\n';
),然后您可以使用标准函数来打印它们:
for (int n = 0; n < i; n++)
printf("%s\n", words[n]);
Here是您使用我建议的最小更改的代码。我添加了一些调试printf
行,您可以取消注释以查看它是如何工作的,我更改为使用stdin
而不是打开文件,以便可以看到它在在线编译器中工作。您仍然可以做很多事情来改进您的代码! (首先,处理\n
在缓冲区中留下的额外fgets
。