&引用;未分配要释放的指针";发生在mac上,但不发生在window7上

&引用;未分配要释放的指针";发生在mac上,但不发生在window7上,c,pointers,malloc,calloc,C,Pointers,Malloc,Calloc,我正在一本书上做练习,把句子中的单词改成拉丁语。代码在Windows7中运行良好,但当我在mac中编译它时,错误就出现了 经过一些测试后,错误来自于此。我不明白这个问题的原因。我对所有指针使用动态内存,并且还添加了空指针检查 while (walker != NULL && *walker != NULL){ free(**walker); free(*walker); free(walker); walker++; } 完整源代码: #i

我正在一本书上做练习,把句子中的单词改成拉丁语。代码在Windows7中运行良好,但当我在mac中编译它时,错误就出现了

经过一些测试后,错误来自于此。我不明白这个问题的原因。我对所有指针使用动态内存,并且还添加了空指针检查

while (walker != NULL && *walker != NULL){
    free(**walker); 
    free(*walker);
    free(walker); 

    walker++;
}
完整源代码:

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

#define inputSize 81
void getSentence(char sentence [], int size);
int countWord(char sentence[]);
char ***parseSentence(char sentence[], int *count);
char *translate(char *world);
char *translateSentence(char ***words, int count);

int main(void){
    /* Local definition*/
    char sentence[inputSize];
    int wordsCnt;
    char ***head;
    char *result;

    getSentence(sentence, inputSize);
    head = parseSentence(sentence, &wordsCnt);

    result = translateSentence(head, wordsCnt);
    printf("\nFinish the translation: \n");
    printf("%s", result);


    return 0;
}

void getSentence(char sentence [81], int size){
    char *input = (char *)malloc(size);
    int length;

    printf("Input the sentence to big latin : ");
    fflush(stdout);
    fgets(input, size, stdin);

    // do not copy the return character at inedx of length - 1
    // add back delimater 
    length = strlen(input);
    strncpy(sentence, input, length-1);
    sentence[length-1]='\0';

    free(input);
}

int countWord(char sentence[]){
    int count=0;

    /*Copy string for counting */
    int length = strlen(sentence);
    char *temp = (char *)malloc(length+1);
    strcpy(temp, sentence);

    /* Counting */
    char *pToken = strtok(temp, " ");
    char *last = NULL;
    assert(pToken == temp);
    while (pToken){
        count++;

        pToken = strtok(NULL, " ");
    }

    free(temp);
    return count;
}
char ***parseSentence(char sentence[], int *count){
    // parse the sentence into string tokens
    // save string tokens as a array
    // and assign the first one element to the head
    char *pToken;
    char ***words;
    char *pW;

    int noWords = countWord(sentence);
    *count = noWords;

    /* Initiaze array */
    int i;
    words = (char ***)calloc(noWords+1, sizeof(char **));
    for (i = 0; i< noWords; i++){
        words[i] = (char **)malloc(sizeof(char *));
    }

    /* Parse string */
    // first element
    pToken = strtok(sentence, " ");

    if (pToken){
        pW = (char *)malloc(strlen(pToken)+1);
        strcpy(pW, pToken);
        **words = pW;
        /***words = pToken;*/

        // other elements
        for (i=1; i<noWords; i++){
            pToken = strtok(NULL, " ");
            pW = (char *)malloc(strlen(pToken)+1);
            strcpy(pW, pToken);
            **(words + i) = pW;
            /***(words + i) = pToken;*/
        }
    }

    /* Loop control */
    words[noWords] = NULL;


    return words;
}

/* Translate a world into big latin */
char *translate(char *word){
    int length = strlen(word);
    char *bigLatin = (char *)malloc(length+3);

    /* translate the word into pig latin */
    static char *vowel = "AEIOUaeiou";
    char *matchLetter;
    matchLetter = strchr(vowel, *word);
    // consonant
    if (matchLetter == NULL){
        // copy the letter except the head
        // length = lenght of string without delimiter
        // cat the head and add ay
        // this will copy the delimater,
        strncpy(bigLatin, word+1, length);
        strncat(bigLatin, word, 1);
        strcat(bigLatin, "ay");
    }
    // vowel
    else {
        // just append "ay"
        strcpy(bigLatin, word);
        strcat(bigLatin, "ay");
    }


    return bigLatin;
}

char *translateSentence(char ***words, int count){
    char *bigLatinSentence;
    int length = 0;
    char *bigLatinWord;

    /* calculate the sum of the length of the words */
    char ***walker = words;
    while (*walker){
        length += strlen(**walker);
        walker++;
    }

    /* allocate space for return string */
    // one space between 2 words
    // numbers of space required = 
    // length of words
    // + (no. of words * of a spaces (1) -1 ) 
    // + delimater
    // + (no. of words * ay (2) )
    int lengthOfResult = length + count + (count * 2);
    bigLatinSentence = (char *)malloc(lengthOfResult);
    // trick to initialize the first memory 
    strcpy(bigLatinSentence, "");

    /* Translate each word */
    int i;
    char *w;
    for (i=0; i<count; i++){
        w = translate(**(words + i));
        strcat(bigLatinSentence, w);
        strcat(bigLatinSentence, " ");
        assert(w != **(words + i));
        free(w);
    }


    /* free memory of big latin words */
    walker = words;
    while (walker != NULL && *walker != NULL){
        free(**walker); 
        free(*walker);
        free(walker); 

        walker++;
    }

    return bigLatinSentence;
}
#包括
#包括
#包括
#包括
#定义输入大小81
无效语句(字符语句[],整数大小);
int countWord(char语句[]);
字符***语法句子(字符句子[],整数*计数);
字符*翻译(字符*世界);
字符*翻译内容(字符***字,整数计数);
内部主(空){
/*局部定义*/
字符句子[inputSize];
int-wordsCnt;
字符***头;
字符*结果;
获取句子(句子,输入大小);
head=语法分析句子(句子和单词scnt);
结果=翻译内容(head,wordsCnt);
printf(“\n完成翻译:\n”);
printf(“%s”,结果);
返回0;
}
void get句子(字符句子[81],整数大小){
字符*输入=(字符*)malloc(大小);
整数长度;
printf(“将句子输入到大拉丁语:”);
fflush(stdout);
fgets(输入、大小、标准输入);
//不要在长度为-1的inedx处复制返回字符
//加回熟化剂
长度=strlen(输入);
strncpy(句子,输入,长度-1);
句子[length-1]=“0”;
免费(输入);
}
int countWord(字符句子[]){
整数计数=0;
/*复制字符串进行计数*/
int-length=strlen(句子);
char*temp=(char*)malloc(长度+1);
strcpy(临时,句子);
/*计数*/
字符*pToken=strtok(临时“”);
char*last=NULL;
断言(pToken==temp);
而(托肯){
计数++;
pToken=strtok(空,“”);
}
免费(临时);
返回计数;
}
字符***解析句子(字符句子[],整数*计数){
//将句子解析为字符串标记
//将字符串标记另存为数组
//并将第一个元素指定给头部
查普顿;
字符***字;
char*pW;
int noWords=countWord(句子);
*计数=noWords;
/*初始化数组*/
int i;
words=(char***)calloc(noWords+1,sizeof(char**));
对于(i=0;i
while (walker != NULL && *walker != NULL){
    free(**walker); 
    free(*walker);
    free(walker); 

    walker++;
}
释放前,需要检查
**walker
是否不为空

另外-当您计算返回字符串所需的内存长度时,由于您复制每个单词加上一个空格(包括最后一个单词后面的空格),因此短了一个字节加上终止的
\0
。换句话说,当您将结果复制到
biglatinterance
中时,您将覆盖一些不属于您的内存。有时您可以侥幸逃脱,有时您无法

int lengthOfResult = length + count + (count * 2);
一定是

int lengthOfResult = length + count + (count * 2) + 1; /* + 1 for final '\0' */


你有个漏洞:

int main(void)
{
    ...
    free(result); /* You have to free the return of translateSentence() */
    return 0;
}

您的代码不必要地复杂,因为您设置了以下内容:

  • n
    :字数
  • words
    :指向可按顺序保存
    n+1
    char**
    值的分配内存

  • words[i]
    0哇,所以我对此很感兴趣,我花了一段时间才弄明白

    现在我明白了,我觉得自己很傻

    在gdb下运行时,我注意到,在第二次运行时,它在线路上的循环中失败了

    自由(步行者)

    现在为什么会这样。这就是为什么我没有马上看到它而感到愚蠢的地方。当你第一次运行那行时,在第二次运行时,单词的整个字符***指针数组(第一次运行时称为walker),当你运行那行时,你试图释放已经释放的内存

    因此,它应该是:

    while (walker != NULL && *walker != NULL){
        free(**walker); 
        free(*walker);
    
        walker++;
    }
    
    free(words); 
    
    编辑:

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <assert.h>
    
    #define inputSize 81
    void getSentence(char sentence [], int size);
    int countWord(char sentence[]);
    char ***parseSentence(char sentence[], int *count);
    char *translate(char *world);
    char *translateSentence(char ***words, int count);
    
    int main(void){
        /* Local definition*/
        char sentence[inputSize];
        int wordsCnt;
        char ***head;
        char *result;
    
        getSentence(sentence, inputSize);
        head = parseSentence(sentence, &wordsCnt);
    
        result = translateSentence(head, wordsCnt);
        printf("\nFinish the translation: \n");
        printf("%s", result);
    
    
        return 0;
    }
    
    void getSentence(char sentence [81], int size){
        char *input = (char *)malloc(size);
        int length;
    
        printf("Input the sentence to big latin : ");
        fflush(stdout);
        fgets(input, size, stdin);
    
        // do not copy the return character at inedx of length - 1
        // add back delimater 
        length = strlen(input);
        strncpy(sentence, input, length-1);
        sentence[length-1]='\0';
    
        free(input);
    }
    
    int countWord(char sentence[]){
        int count=0;
    
        /*Copy string for counting */
        int length = strlen(sentence);
        char *temp = (char *)malloc(length+1);
        strcpy(temp, sentence);
    
        /* Counting */
        char *pToken = strtok(temp, " ");
        char *last = NULL;
        assert(pToken == temp);
        while (pToken){
            count++;
    
            pToken = strtok(NULL, " ");
        }
    
        free(temp);
        return count;
    }
    char ***parseSentence(char sentence[], int *count){
        // parse the sentence into string tokens
        // save string tokens as a array
        // and assign the first one element to the head
        char *pToken;
        char ***words;
        char *pW;
    
        int noWords = countWord(sentence);
        *count = noWords;
    
        /* Initiaze array */
        int i;
        words = (char ***)calloc(noWords+1, sizeof(char **));
        for (i = 0; i< noWords; i++){
            words[i] = (char **)malloc(sizeof(char *));
        }
    
        /* Parse string */
        // first element
        pToken = strtok(sentence, " ");
    
        if (pToken){
            pW = (char *)malloc(strlen(pToken)+1);
            strcpy(pW, pToken);
            **words = pW;
            /***words = pToken;*/
    
            // other elements
            for (i=1; i<noWords; i++){
                pToken = strtok(NULL, " ");
                pW = (char *)malloc(strlen(pToken)+1);
                strcpy(pW, pToken);
                **(words + i) = pW;
                /***(words + i) = pToken;*/
            }
        }
    
        /* Loop control */
        words[noWords] = NULL;
    
    
        return words;
    }
    
    /* Translate a world into big latin */
    char *translate(char *word){
        int length = strlen(word);
        char *bigLatin = (char *)malloc(length+3);
    
        /* translate the word into pig latin */
        static char *vowel = "AEIOUaeiou";
        char *matchLetter;
        matchLetter = strchr(vowel, *word);
        // consonant
        if (matchLetter == NULL){
            // copy the letter except the head
            // length = lenght of string without delimiter
            // cat the head and add ay
            // this will copy the delimater,
            strncpy(bigLatin, word+1, length);
            strncat(bigLatin, word, 1);
            strcat(bigLatin, "ay");
        }
        // vowel
        else {
            // just append "ay"
            strcpy(bigLatin, word);
            strcat(bigLatin, "ay");
        }
    
    
        return bigLatin;
    }
    
    char *translateSentence(char ***words, int count){
        char *bigLatinSentence;
        int length = 0;
        char *bigLatinWord;
    
        /* calculate the sum of the length of the words */
        char ***walker = words;
        while (*walker){
            length += strlen(**walker);
            walker++;
        }
    
        /* allocate space for return string */
        // one space between 2 words
        // numbers of space required = 
        // length of words
        // + (no. of words * of a spaces (1) -1 ) 
        // + delimater
        // + (no. of words * ay (2) )
        int lengthOfResult = length + count + (count * 2);
        bigLatinSentence = (char *)malloc(lengthOfResult);
        // trick to initialize the first memory 
        strcpy(bigLatinSentence, "");
    
        /* Translate each word */
        int i;
        char *w;
        for (i=0; i<count; i++){
            w = translate(**(words + i));
            strcat(bigLatinSentence, w);
            strcat(bigLatinSentence, " ");
            assert(w != **(words + i));
            free(w);
        }
    
    
        /* free memory of big latin words */
        walker = words;
        while (walker != NULL && *walker != NULL){
            free(**walker); 
            free(*walker);
            free(walker); 
    
            walker++;
        }
    
        return bigLatinSentence;
    }
    
    我还想指出的是,你不必在C中从void*开始施法


    因此,当你调用malloc时,你不需要(char*)。

    也许我读错了,但是
    free(NULL)
    保证可以工作(并且什么也不做)。@delnan它是一样的:(@delnan你是对的-这是我使用“不符合标准”时(很久以前)养成的习惯)编译器和我会因为不检查而被处理到核心转储。真的,当我看到有人释放三个指针并测试其中两个指针的
    NULL
    ,我的不一致警报就会响起。该死的,看起来人们已经把我揍了一顿。哦,好吧。谢谢你的帮助。我想我明白你说的。但我不明白为什么要释放第一次和第二次释放相同的内存!因为释放()释放walker指向的整个内存块。因此,当您第一次调用它时,它会释放整个数组。然后您执行walker++并指向该数组中的另一个元素并调用free,但整个数组已被释放。也感谢您的帮助。但真的有必要释放结果吗?因为我读的书中说当程序结束时,他会清除所有的记忆。不客气,不,不要相信它,C没有垃圾收集器,这是你的工作,如果你在UnixI上,请使用always valgrind:)@tork谢谢你的帮助。我是C的新手,我真的不知道什么时候应该添加间接寻址。我使用
    char***
    的原因是因为我想计算
    char**
    的地址。当指针开始变得复杂和凌乱时,我建议在白板/黑板上绘制图表(如果没有白板,也可以使用纸张)。这项技能的培养也需要一段时间,但它可以帮助很多人
    while (walker != NULL && *walker != NULL){
        free(**walker); 
        free(*walker);
    
        walker++;
    }
    
    free(words);