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

标签 c io dynamic-arrays

我正在尝试编写一个简单的程序,它接受特定的输入,动态分配它,输出它并释放它。问题是它没有正确输出。输入的样式如下:

第一行是我需要阅读的行数 - i。

然后有 i 行。在每一行上,我读一个单词,然后读一个整数 n,它显示接下来将进行多少个整数,然后是 n 个整数。

例如,

2
yellow 2 32 44
green 3 123 3213 3213

说明:

第一行 - 必须有 2 行。

第 2 行和第 3 行 - 单词 + 整数个数 + 整数。

我的尝试:

#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 *)); 这没有意义...返回值指向一个int *,但您却以 sizeof (char *) 的倍数进行分配。这两个不需要具有相同的表示,这意味着它们不需要具有相同的宽度。请参阅this page了解更多信息。 PS:Don't cast malloc 。当您在那里时,请阅读网站的其余部分。它将防止您遇到 future 的常见问题。同时,我假设您的意思是 data = malloc(n * sizeof *data);

顺便说一句,

n 可能应该是 size_t 而不是 int。要使用 scanf 接收 size_t,请使用 %zu 格式说明符。下面提供了一个示例。

<小时/>
    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]);
    }

在这个缩进不佳的代码示例中(没有人愿意阅读,因为它缩进不佳),存在一个问题。该问题通常不会被发现,因为在格式正确、删除不必要的转换并考虑它所呈现的愚蠢逻辑之前没有人愿意阅读它。

j == data[i][0]时,循环应该结束。在循环的第一次迭代中,data[i][0] 发生变化,因此循环条件发生变化。因此,这个循环没有做你想要它做的事情。也许你想写这样的东西:

    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);
    }

当我们讨论这个主题时,您会注意到我在最后一个 scanf 格式字符串的末尾添加了一个空格。该空间消耗了 stdin 中尽可能多的空白。这样做的原因大概是为了与上一个循环中的损坏代码相同的目的,在读取下一个项目“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';

现在几乎消除了前导 '\n' 字符的可能性,但用户恶意按 Enter 键而不输入单词的情况除外。删除了 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';

关于C:动态内存分配-输出错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15998693/

相关文章:

c++ - char sprintf() 句柄的限制

Windows 和 Linux 下的 C 代码

将 const char* 转换为 int

c - 使用结构从动态数组的变量返回随机值

c++ - 使用堆上的成员初始化类内的类

c++ - 需要在 C++ 中创建多个动态数组

C 命令行参数,分词

c - 如何添加扫描端口ip

java - 扫描仪在 Mac OSX 终端中无法正常工作

java - BufferedReader 中跳过和重置方法的一些实际用例是什么?