malloc到指针“数组”的元素

时间:2017-04-22 02:42:00

标签: c pointers malloc dynamic-memory-allocation realloc

那里。

我正在尝试创建一个读取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;
}

2 个答案:

答案 0 :(得分:1)

realloc要求重新分配的内存先前已分配(see here)。

尝试在循环之前添加set = malloc(1);,以便在事先分配至少1个字节。

答案 1 :(得分:0)

除了初始化set和复制word之外,您还有一些额外的微妙问题,这些问题可能会让您感到困惑。首先,让我们从几个非重要的逻辑问题开始。很少,如果你真的想要存储一个字符串,'\n'悬挂在最后,只需删除newline读取并包含在wordfgets,例如< / 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}}所有内存并且没有错误。

仔细看看,如果您有任何疑问,请告诉我。包含了许多微妙的变化,因此,如果您有不明白的地方,请在下方发表评论。