简体   繁体   English

C:动态内存分配-输出错误

[英]C: Dynamic memory allocation - error of output

I'm trying to write a simple program that takes specific input, dynamically allocates it, outputs it and frees. 我正在尝试编写一个简单的程序,该程序需要特定的输入,动态分配它,输出它并释放它。 The thing is it does not output it properly. 问题是它无法正确输出。 The input's style is the following: 输入的样式如下:

The first line is the number of lines that I need to read - i. 第一行是我需要阅读的行数-i。

Then there are i lines. 然后有i行。 On each line I read one word, then an integer n that shows how many integers will proceed next and then there come n integers. 在每一行中,我读一个单词,然后是一个整数n,该整数n显示接下来要处理的整数个数,然后是n个整数。

For example, 例如,

2
yellow 2 32 44
green 3 123 3213 3213

Explanation: 说明:

1st line - there must come 2 lines. 第一行-必须有2行。

2nd and 3rd line - word + number of integers + integers. 第二和第三行-单词+整数数量+整数。

My attempt: 我的尝试:

#include <stdio.h>
#include <stdlib.h>

int main()
{
    int i, j;
    int n; /* n - number of words */
    char **words; /* words - array of keywords */
    int **data;
    scanf ("%d\n", &n);

    words = (char **) malloc (n * sizeof (char *));
    data = (int **) malloc (n * sizeof (int *));

    for (i = 0; i < n; ++i)
    {
        words[i] = (char *) malloc (sizeof (char));
        for (j = 0 ;; ++j)
        {
            words[i] = (char *) realloc (words[i], sizeof (char) * (j + 2));
            scanf ("%c", &words[i][j]);

            if (words[i][j] == ' ')
                break;
            else if (words[i][j] == '\n')
                --j;

        }

        words[i][j] = '\0';
        data[i] = (int *) malloc (sizeof (int));
        scanf ("%d", &data[i][0]);

        for (j = 0; j < data[i][0]; ++j)
        {
            data[i] = (int *) realloc (data[i], sizeof (int) * (j + 2));
            scanf ("%d", &data[i][j]);
        }
    }

    for (i = 0; i < n; ++i)
    {
        printf ("%s ", words[i]);
        printf ("%d ", data[i][0]);
        for (j = 0; j < data[i][0]; ++j)
        {
            printf ("%d ", data[i][j]);
        }
        printf ("\n");
    }

    for (i = 0; i < n; ++i)
    {
        free (words[i]);
        free (data[i]);
    }
    free (words);
    free (data);
    return 0;
}

data = (int **) malloc (n * sizeof (char *)); This doesn't make sense... The return value points to an int * , yet you're allocating in multiples of sizeof (char *) . 这没有意义...返回值指向一个int * ,但是您正在以sizeof (char *)倍数进行分配。 These two aren't required to have the same representation, which implies that they're not required to have the same width. 不需要这两个具有相同的表示形式,这意味着它们不需要具有相同的宽度。 See this page for more info. 请参阅此页面以获取更多信息。 PS: Don't cast malloc . PS: 不要转换malloc While you're there, read the rest of the website. 当您在那里时,请阅读网站的其余部分。 It'll prevent you from encountering future common problems. 它可以防止您将来遇到常见问题。 In the mean time, I'll assume you meant data = malloc(n * sizeof *data); 同时,我假设您的意思是data = malloc(n * sizeof *data); .

n , by the way, should probably be a size_t instead of an int . 顺便说一下, n应该应该是size_t而不是int To recieve a size_t using scanf , use the %zu format specifier. 要使用scanf接收size_t ,请使用%zu格式说明符。 An example of this is provided below. 下面提供了一个示例。


    data[i] = (int *) malloc (sizeof (int));
    scanf ("%d", &data[i][0]);
    for (j = 0; j < data[i][0]; ++j)
    {
        data[i] = (int *) realloc (data[i], sizeof (int) * (j + 2));
            scanf ("%d", &data[i][j]);
    }

In this poorly indented example of code (which nobody wants to read, because it's poorly indented), a problem exists. 在这个缩进程度很差的代码示例中(由于缩进程度太低,没有人希望阅读),存在一个问题。 The problem would normally go undetected because nobody wants to read it until it's correctly formatted, unnecessary casts are removed and consideration is given to the silly logic it presents. 该问题通常不会被发现,因为在正确格式化之前,没有人愿意阅读它,删除了不必要的强制转换,并考虑了它所呈现的愚蠢逻辑。

The loop is supposed to end when j == data[i][0] . j == data[i][0]时,循环应结束。 In the first iteration of the loop, data[i][0] changes, so the condition for the loop changes. 在循环的第一次迭代中, data[i][0]发生变化,因此循环的条件发生了变化。 Hence, this loop isn't doing what you want it to do. 因此,此循环没有执行您想要的操作。 Perhaps you meant to write something like this: 也许您打算写这样的东西:

    size_t count;
    /* Note how scanf returns a value, and when that value isn't 1 an assertion error
     * is raised? An exercise for you is to get that assertion error to raise, or read
     * the manual... */
    assert(scanf("%zu", &count) == 1);

    /* Note how malloc doesn't need a cast? */
    data[i] = malloc(count * sizeof data[i][0]);
    for (j = 0; j < count; ++j)
    {
        /* Note how count never changes, in this loop? */
        assert(scanf("%d ", &data[i][j]) == 1);
    }

While we're on this topic, you'll notice that I added a space to the end of the last scanf format string. 当我们讨论这个主题时,您会注意到我在最后一个scanf格式字符串的末尾添加了一个空格。 That space consumes as much whitespace as possible from stdin . 该空间从stdin消耗了尽可能多的空格。 The reason for this is, presumably for the same purpose as the broken code in your previous loop, to read and discard any '\\n' characters before reading the next item "word": 这样做的原因大概是出于与上一个循环中损坏的代码相同的目的,是在读取下一个项目“ word”之前读取并丢弃所有'\\n'字符:


    words[i] = (char *) malloc (sizeof (char));
    for (j = 0 ;; ++j)
    {
        words[i] = (char *) realloc (words[i], sizeof (char) * (j + 2));
        scanf ("%c", &words[i][j]);
        if (words[i][j] == ' ')
            break;
        else if (words[i][j] == '\n')
            --j;
    }
    words[i][j] = '\0';

The possibility for leading '\\n' characters is now virtually eliminated, with the exception of the user maliciously pressing enter without entering a word. 现在,几乎消除了前导'\\n'字符的可能性,除了用户恶意输入而没有输入单词的情况下。 malloc casts removed, and a more sensible allocation algorithm in vision, I presume you meant: 删除了malloc强制类型转换,并且在视觉上采用了更明智的分配算法,我想您的意思是:

    size_t j = 0;
    words[i] = NULL;
    for (int c = getchar(); c >= 0; c = getchar()) {
        /* Reallocate when j is a power of two, eg: 0, 1, 2, 4, 8, 16...
         * ... and double the size of the buffer each time
         */
        if (j & (j - 1) == 0) {
            char *temp = realloc(words[i], j * 2 + 1);
            /* hint: Check *all* return values */
            assert(temp != NULL);
            words[i] = temp;
        }

        if (strchr(" \n", c) == NULL) { break; }
        words[i][j] = c;
        j++;
    }

    words[i][j] = '\0';

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM