从C中的1D数组填充2D数组

时间:2015-09-28 01:05:18

标签: c arrays multidimensional-array

我正在努力学习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.

2 个答案:

答案 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块中,这个块可以按照这里构造的方式排列,但不可靠。

当您打印两行

时,可能已经看到了SEEMED
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];

    }
}

看起来你想要的更像是:

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