我正在尝试编写一个简单的程序,它接受特定的输入,动态分配,输出和释放。问题是它没有正确输出。输入的样式如下:
第一行是我需要阅读的行数 - i。
然后有i行。在每一行上我读了一个单词,然后是一个整数n,表示接下来会有多少个整数然后出现n个整数。
例如,
2
yellow 2 32 44
green 3 123 3213 3213
说明:
第1行 - 必须有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;
}
答案 0 :(得分:1)
data = (int **) malloc (n * sizeof (char *));
这没有意义......返回值指向int *
,但您要以sizeof (char *)
的倍数进行分配。这两个不需要具有相同的表示,这意味着它们不需要具有相同的宽度。有关详细信息,请参阅this page。 PS:Don't cast malloc。当你在那里时,请阅读网站的其余部分。它会阻止你遇到未来的常见问题。与此同时,我假设您的意思是data = malloc(n * sizeof *data);
。
n
可能应该是size_t
而不是int
。要使用size_t
接收scanf
,请使用%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
消耗尽可能多的空白。其原因可能是与前一个循环中已损坏代码的目的相同,在阅读下一个“单词”项之前,要读取并丢弃任何'\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';