怎么修?尝试释放动态分配的内存时触发异常

时间:2018-12-29 20:58:07

标签: c

这是我的第一次发帖问题,我确实尝试寻找解决方案,但是即使我找到了,我也不认识它。

因此,正如标题所述,问题出在此触发的异常“在lab10.exe中的0x0F26372D(ucrtbased.dll)引发异常:0xC0000005:访问冲突读取位置0xCCCCCCC4。

如果有用于此异常的处理程序,则程序可以安全地继续。”,当我进入第-> free(word)行时会发生这种情况。

当我学习malloc时,这确实发生了几次,但我忽略了它-认为还有其他问题。但是现在我发现自己做错了。

程序的重点是-编写结构“ word”。我需要输入句子并将其“切”为单词,然后将每个单词放入struct以及单词中字母的大小和单词的序数。

#include <stdio.h>
#include <string.h>

struct word {
    char text_word[50];
    unsigned sizee; //number of letters of the word
    unsigned number; //ordinal number of the word
};

void cutting_sentence(struct word *p, char *sen) { //sen is sentence
    int size_sen, i, j;

    size_sen = strlen(sen) + 1; //size of sentence

    p = (struct word*)malloc(size_sen * sizeof(struct word)); 
    if (p == NULL) {
        printf("\nNot enaugh memory!");
        return 0;
    }

    strcpy(p[0].text_word, strtok(sen, " ,.!?")); 
    p[0].sizee = strlen(p[0].text_word);
    p[0].number = 1;

    printf("word:%s \t size:%u \t ordinal number of the word:%u\n", 
        p[0].text_word, p[0].sizee, p[0].number);

    for (i = p[0].sizee - 1, j = 1;i < size_sen;++i) {
        if (*(sen + i) == ' ' || *(sen + i) == '.' || *(sen + i) == ','
        || *(sen + i) == '?' || *(sen + i) == '!') {
            strcpy(p[j].text_word, strtok(NULL, " ,.!?"));
            p[j].sizee = strlen(p[j].text_word);
            p[j].number = j + 1;

            printf("word:%s \t size:%u \t ordinal number of the 
                        word:%u\n", p[j].text_word, p[j].sizee, p[j].number);

            j++;
        }
    }
}

int main() {
    char sentence[1024];
    struct word *word;

    printf("Sentence: ");
    gets(sentence);

    cutting_sentence(&word, sentence);

    free(word);  //here is exception triggered

    return 0;
}

3 个答案:

答案 0 :(得分:1)

您要更改传递的指针参数的本地值,您需要在其目标位置更改内存,以便调用者发现分配的内存的位置。由于您没有这样做,因此您尝试释放存储在word堆栈中的局部变量main()

要解决的第一件事是不要让变量与类型名称相同,这简直就是邪恶。

然后更改函数原型以传递双指针:

void cutting_sentence(struct word **p, char *sen);

请记住,在使用p的地方,您现在需要使用*p或首先分配一个本地(word *)并在其中包含地址值。

void cutting_sentence(struct word **p, char *sen) { //sen is sentence
    int size_sen, i, j;

    size_sen = strlen(sen) + 1; //size of sentence

    *p = (struct word*)malloc(size_sen * sizeof(struct word)); 
    if (*p == NULL) {
        printf("\nNot enaugh memory!");
        return; //void cannot return a value
    }

以此类推,将p的每种用法更改为*p

然后

int main() {
    char sentence[1024];
    struct word *words;

    printf("Sentence: ");
    gets(sentence);

    cutting_sentence(&words, sentence);

    if (words != NULL)
       free(words);  //now valid

    return 0;
}

答案 1 :(得分:0)

问题比以前讨论的多。

[正如已经指出的],您的第一个参数应为struct word **。但是,一种更简单的方法是消除它,并将返回类型更改为struct word *。这样可以使函数中的代码更简单(即,无需对指针进行双重引用)

虽然可以分配与输入字符串中的字符数量一样多的单词结构,但这有点不正常。

一种更好的方法(至少是惯用的,至少是惯用的)是在循环内使用realloc

无论哪种情况,都可以通过最后一个realloc将数组大小调整为仅使用所需的大小。

我认为您扫描sen以查找定界符的循环过于复杂。只需在循环中使用strtok即可获得相同的效果,并且复杂度更低。

此外,您没有传递单词数量的 count 。一种方法是在数组中添加一个大小为零的额外元素(例如列表结尾标记)


这是重构版本,应该可以帮助您

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

struct word {
    char text_word[50];
    unsigned sizee;                     // number of letters of the word
    unsigned number;                    // ordinal number of the word
};

struct word *
cutting_sentence(char *sen)
{                                       // sen is sentence
    int curcnt = 0;
    int maxcnt = 0;
    char *token;
    struct word *word;
    struct word *words;

    while (1) {
        token = strtok(sen," ,.!?\n");
        if (token == NULL)
            break;
        sen = NULL;

        if (curcnt >= maxcnt) {
            maxcnt += 100;
            words = realloc(words,sizeof(struct word) * (maxcnt + 1));
        }

        word = &words[curcnt];
        strcpy(word->text_word,token);
        word->number = curcnt;
        word->sizee = strlen(token);

        ++curcnt;
    }

    words = realloc(words,sizeof(struct word) * (curcnt + 1));

    // set end-of-list
    word = &words[curcnt];
    word->sizee = 0;

    return words;
}

int
main()
{
    char sentence[1024];
    struct word *words;
    struct word *word;

    printf("Sentence: ");
    fflush(stdout);

    fgets(sentence,sizeof(sentence),stdin);

    words = cutting_sentence(sentence);

    for (word = words;  word->sizee != 0;  ++word)
        printf("main: number=%u sizee=%u text_word='%s'\n",
            word->number,word->sizee,word->text_word);

    free(words);

    return 0;
}

答案 2 :(得分:0)

以下建议的代码:

  1. 消除冗余代码
  2. 正确检查错误
  3. 正确输出错误消息(以及系统认为stderr发生错误的文本原因
  4. 执行所需的功能
  5. 正确初始化struct word指针
  6. 正确更新struct word指针
  7. int sizee更改为size_t sizee是因为函数:strlen()返回了size_t,而不是int
  8. int i更改为unsigned i,因为结构字段number的声明被声明为unsigned
  9. 说明为什么包含每个头文件
  10. struct word中的每个字符分配sentence的实例,这是“过度杀伤力”。如果每个单词都只有一个字符,则最可能的单词数量是。因此,立即可以将分配的内存大小减少一半。计算单词分隔符的循环将导致分配的内存量正确。您可以轻松添加该功能。
  11. 请注意使用功能strtok()的方式。即在循环之前先进行调用,然后在循环结束后进行后续调用

现在是建议的代码:

#include <stdio.h>   // printf(), fgets(), NULL
#include <stdlib.h>  // exit(), EXIT_FAILURE, malloc(), free()
#include <string.h>  // strlen(),  strtok()


struct word 
{
    char text_word[50];
    size_t sizee; //number of letters of the word
    unsigned number; //ordinal number of the word
};

// notice the `**p` so can access the pointer in `main()` so it can be updated
void cutting_sentence(struct word **p, char *sen) 
{ //sen is sentence
    size_t size_sen = strlen(sen); //size of sentence
    struct word *wordptr = *p;

    wordptr = malloc(size_sen * sizeof(struct word)); 
    if ( !wordptr ) 
    {
        perror("malloc failed");
        exit( EXIT_FAILURE );
    }


    unsigned i = 0;
    char * token = strtok(sen, " ,.!?");
    while( token )
    {
        strcpy( wordptr[i].text_word, token ); 
        wordptr[i].sizee = strlen( token );
        wordptr[i].number = i;

        printf("word:%s\t Length:%lu]tordinal number of the word:%u\n", 
                wordptr[i].text_word, 
                wordptr[i].sizee, 
                wordptr[i].number);

        token = strtok( NULL, " ,.!?");
        i++;
    }
}

int main( void ) 
{
    char sentence[1024];
    struct word *wordArray = NULL;

    printf("Sentence: ");
    if( !fgets(sentence, sizeof( sentence ), stdin ) )
    {
        perror( "fgets failed" );
        exit( EXIT_FAILURE );
    }

    // remove trailing new line
    sentence[ strcspn( sentence, "\n") ]  = '\0';
    cutting_sentence(&wordArray, sentence);

    free( wordArray );  //here is exception triggered

    return 0;
}

典型的代码运行结果为:

Sentence: hello my friend
word:hello   Length:5   ordinal number of the word:0
word:my  Length:2   ordinal number of the word:1
word:friend  Length:6   ordinal number of the word:2

请注意,“短”字会导致输出不均匀。您可能要纠正它。