那里。
我正在尝试创建一个读取N个单词的程序(当你输入时它结束 - )并打印出它。
我的问题是:我正在尝试使用某种动态的char *数组。它重新分配一个元素,但是当我尝试在堆上创建一个String空间时,崩溃了(第21行)。
可以修复吗?谢谢。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define WORD_SIZE 11
int main()
{
char word[WORD_SIZE];
char **set;
int j;
int numberWord = 0;
/* input */
printf("Insert a word, or '-' to stop: ");
fgets(word, WORD_SIZE, stdin);
while (strcmp(word, "-\n")) {
/* process */
set = realloc(set, sizeof(char *) * (numberWord + 1));
set[numberWord] = malloc(sizeof(char) * WORD_SIZE);
numberWord++;
/* input */
printf("Insert a word, or '-' to stop: ");
fgets(word, WORD_SIZE, stdin);
}
/* output */
printf("\nSORTED:\n");
for (j = 0; j < numberWord; j++) {
printf("%s", set[j]);
}
printf("\n");
free(set);
return 0;
}
答案 0 :(得分:1)
realloc
要求重新分配的内存先前已分配(see here)。
尝试在循环之前添加set = malloc(1);
,以便在事先分配至少1个字节。
答案 1 :(得分:0)
除了初始化set
和复制word
之外,您还有一些额外的微妙问题,这些问题可能会让您感到困惑。首先,让我们从几个非重要的逻辑问题开始。很少,如果你真的想要存储一个字符串,'\n'
悬挂在最后,只需删除newline
读取并包含在word
中fgets
,例如< / p>
/* remove trailing '\n' */
size_t len = strlen (word);
if (word[len - 1] == '\n')
word[--len] = 0; /* overwrite with nul-byte */
(拥有len
还可让您分配保留word
所需的确切内存量,例如len + 1
)
此时,您还可以通过简单的长度和字符比较检查退出条件,例如
if (len == 1 && *word == '-') /* test for '-' */
break;
(这也意味着您的阅读循环只能是for (;;) {...}
,而不会将"-"
存储为您的一个单词)
如我的评论中所述,永远不要直接指定重新分配指针的返回值。为什么?如果realloc
失败,则set
未被释放,而realloc
会返回NULL
- 然后您将set
分配给set
,并失去对 /* process - validate all allocations */
void *tmp = realloc (set, sizeof *set * (numberWord + 1));
if (!tmp) {
fprintf (stderr, "error: virtual memory exhausted - realloc.\n");
break;
}
set = tmp;
的引用造成内存泄漏。相反,总是使用临时指针,例如
word
您正在为每个free
分配内存,但未能 /* output */
printf ("\nSORTED:\n");
for (j = 0; j < numberWord; j++) {
printf (" %s\n", set[j]);
free (set[j]); /* don't forget to free word */
}
free(set); /* free pointers */
putchar ('\n'); /* don't use printf for single char */
为每个单词分配的内存。如果此后不再需要内存,可以在输出循环中执行此操作,例如
SORTED
在您的上方,表示您正在以set
顺序输出您的单词,但您无处可以对单词进行排序。对单词进行排序的最简单方法是为set
中的指针创建一个简单的比较函数,然后将qsort
传递给int cmpstrings (const void *a, const void *b) {
return strcmp (*(char * const *)a, *(char * const *)b);
}
int main (void) {
...
qsort (set, numberWord, sizeof *set, cmpstrings); /* sort */
进行排序,例如。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define WORD_SIZE 11
int cmpstrings (const void *a, const void *b) {
return strcmp (*(char * const *)a, *(char * const *)b);
}
int main (void) {
char word[WORD_SIZE] = "",
**set = NULL;
int j, numberWord = 0;
for (;;) {
/* input */
printf("Insert a word, or '-' to stop: ");
fgets(word, WORD_SIZE, stdin);
/* remove trailing '\n' */
size_t len = strlen (word);
if (word[len - 1] == '\n')
word[--len] = 0; /* overwrite with nul-byte */
if (len == 1 && *word == '-') /* test for '-' */
break;
/* process - validate all allocations */
void *tmp = realloc (set, sizeof *set * (numberWord + 1));
if (!tmp) {
fprintf (stderr, "error: virtual memory exhausted - realloc.\n");
break;
}
set = tmp;
set[numberWord] = malloc (sizeof *set[numberWord] * (len + 1));
if (!set[numberWord]) {
fprintf (stderr, "error: virtual memory exhausted - malloc.\n");
break;
}
strcpy (set[numberWord], word);
numberWord++;
}
qsort (set, numberWord, sizeof *set, cmpstrings); /* sort */
/* output */
printf ("\nSORTED:\n");
for (j = 0; j < numberWord; j++) {
printf (" %s\n", set[j]);
free (set[j]); /* don't forget to free word */
}
free(set); /* free pointers */
putchar ('\n'); /* don't use printf for single char */
return 0;
}
将所有部分组合在一起并以更简洁的方式重新排列输入请求的逻辑,您可以执行以下操作:
$ ./bin/dynwords
Insert a word, or '-' to stop: my
Insert a word, or '-' to stop: dog
Insert a word, or '-' to stop: has
Insert a word, or '-' to stop: fleas
Insert a word, or '-' to stop: the
Insert a word, or '-' to stop: cat
Insert a word, or '-' to stop: doesn't
Insert a word, or '-' to stop: have
Insert a word, or '-' to stop: any
Insert a word, or '-' to stop: -
SORTED:
any
cat
doesn't
dog
fleas
has
have
my
the
示例使用/输出
valgrind
在你编写的动态分配内存的任何代码中,你有2个职责关于任何分配的内存块:(1)总是保留一个指向起始地址的指针内存块,(2)当不再需要时,它可以释放。
您必须使用内存错误检查程序,以确保您没有在已分配的内存块之外/之外写入,尝试读取或基于未初始化值的条件跳转,并最终确认您已释放你分配的所有内存。
对于Linux $ valgrind ./bin/dynwords
==10572== Memcheck, a memory error detector
==10572== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==10572== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==10572== Command: ./bin/dynwords
==10572==
Insert a word, or '-' to stop: my
Insert a word, or '-' to stop: dog
Insert a word, or '-' to stop: has
Insert a word, or '-' to stop: fleas
Insert a word, or '-' to stop: the
Insert a word, or '-' to stop: cat
Insert a word, or '-' to stop: doesn't
Insert a word, or '-' to stop: have
Insert a word, or '-' to stop: any
Insert a word, or '-' to stop: -
SORTED:
any
cat
doesn't
dog
fleas
has
have
my
the
==10572==
==10572== HEAP SUMMARY:
==10572== in use at exit: 0 bytes in 0 blocks
==10572== total heap usage: 18 allocs, 18 frees, 402 bytes allocated
==10572==
==10572== All heap blocks were freed -- no leaks are possible
==10572==
==10572== For counts of detected and suppressed errors, rerun with: -v
==10572== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
是正常的选择。每个平台都有类似的记忆检查器。它们都很简单易用,只需通过它运行程序,例如
freed
始终确认您已分配{{1}}所有内存并且没有错误。
仔细看看,如果您有任何疑问,请告诉我。包含了许多微妙的变化,因此,如果您有不明白的地方,请在下方发表评论。