如何正确释放内存?

How to free memory properly?

请帮忙,我不知道如何正确释放内存。下面有代码

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

#define INT_MSG_LEN 25;

enum {NO_ERROR = 0, 
      ERROR_INPUT = 100, 
      ERROR_LEN = 101};

static const char *error_texts[] = { "Error input!", 
                                     "Error lenghts!"};

void shift(char *msgEnc, char *msg, char *msgRes, char *mainMsg, char *alphabet, int offset);
void report_error(int error);
void print_error(int error);
int get_sameletters(char *msg, char *msgRes, int offset);
int get_letter(char letter, char *alphabet);
int compare(char *msgEnc, char *msg, char *msgRes, char *alphabet, int offset);
char *read_Input_Msg(int *msglen);
char rotate(char *original, int offset);

int main(int argc, char *argv[])
{
    int ret = NO_ERROR;
    char *msgEnc, *msg, alphabet[53] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
    int msgEncLen, msgLen;

    msgEnc = msg = NULL;
    msgEncLen = msgLen = 0;

    msgEnc = read_Input_Msg(&msgEncLen);
    if (msgEnc)
        msg = read_Input_Msg(&msgLen);

    if (msgEnc == NULL || msg == NULL)
        ret = ERROR_INPUT;
    else if (msgEncLen != msgLen)
        ret = ERROR_LEN;
    
    char msgRes[msgEncLen], mainMsg[msgEncLen];
    
    if (ret == NO_ERROR)
        shift(msgEnc, msg, msgRes, mainMsg, alphabet, msgEncLen);
    else
        print_error(ret);

    free(msgEnc);
    free(msg);
    return ret;
}

void shift(char *msgEnc, char *msg, char *msgRes, char *mainMsg, char *alphabet, int offset)
{//function for decoding text by a defined offset
    int dis;
    dis = compare(msgEnc, msg, msgRes, alphabet, offset);
    for (int i = 0; i<offset; ++i)
            mainMsg[i] = msgEnc[i]+dis;

    rotate(mainMsg, offset);
    for(int i = 0; i<offset; ++i)
        printf("%c", mainMsg[i]);
    printf("\n");
}

void report_error(int error)
{//prints error 
    if (error >= ERROR_INPUT && error <= ERROR_LEN)
        fprintf(stderr, "%s\n", error_texts[error - ERROR_INPUT]);
}

void print_error(int error)
{//what error it is
    switch (error){
        case ERROR_INPUT:
            report_error(ERROR_INPUT);
            break;
        case ERROR_LEN:
            report_error(ERROR_LEN);
            break;
    }
}

int get_sameletters(char *msg, char *msgRes, int offset)
{//gets count of sameletters between two strings
    int sameLetters = 0;
    for (int i = 0; i<offset-1; ++i){
        if (msg[i] == msgRes[i])
            sameLetters++;
    }
    return sameLetters;
}

int get_letter(char letter, char *alphabet)
{   
    int k = 0;
    for (int i=0; alphabet[i]; ++i){
        if (letter == alphabet[i])
            k = i;
    }
    return k;
}

int compare(char *msgEnc, char *msg, char *msgRes, char *alphabet, int offset)
{//calculate a distance between first input string and string what will get after decryption
    int distance, max_letters = 0;
    for (int i = 0; alphabet[i]; ++i){
        for (int j = 0; msgEnc[j]; ++j){
                msgRes[j] = alphabet[(get_letter(msgEnc[j], alphabet) + i) % 52];
            }
            int sameLetters = get_sameletters(msg, msgRes, offset);
            if (sameLetters >= max_letters){
                max_letters = sameLetters;
                distance = i;
            }
    }
    return distance;
}

char *read_Input_Msg(int *msglen)
{//input messages, at the same time counts the length of the entered string
    int capacity = INT_MSG_LEN;
    char *msg = malloc(capacity);
    int c, len = 0;
    while ((c = getchar()) != EOF && c != '\n'){
        if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))) {
            free(msg);
            msg = NULL;
            len = 0;
            break;
        }
        if (len == capacity){
            char *tmp = realloc(msg, capacity * 2);
            if (tmp == NULL){
                free(msg);
                msg = NULL;
                len = 0;
                break;
            }
            capacity *= 2;
            msg = tmp;
        }
        msg[len++] = c;
    }
    *msglen = len;
    return msg;
}

char rotate(char *original, int offset)
{
    for (int i = 0; i<offset; ++i){
        if (original[i] > 'Z' && original[i]<'a')
            original[i] += 6;
        else if (original[i] > 'z'){
            int k = (int)original[i];
            k -= 58;
            original[i] = (char)k;
        }
    }
    return *original;
}

When I run it through Valgrind, it says to me that I have errors with the allocated memory, says I do not free it. Writes that memory is not freed at 107.56 and 44 lines, more precisely

==56665== Conditional jump or move depends on uninitialised value(s)
==56665==    at 0x4015BF: compare (main.c:107)
==56665==    by 0x401468: shift (main.c:56)
==56665==    by 0x4012C3: main (main.c:44)
==56665== 
�elloword
==56665== 
==56665== HEAP SUMMARY:
==56665==     in use at exit: 0 bytes in 0 blocks
==56665==   total heap usage: 4 allocs, 4 frees, 2,098 bytes allocated
==56665== 
==56665== All heap blocks were freed -- no leaks are possible
==56665== 
==56665== Use --track-origins=yes to see where uninitialised values come from
==56665== For lists of detected and suppressed errors, rerun with: -s
==56665== ERROR SUMMARY: 52 errors from 1 contexts (suppressed: 0 from 0)

好像释放了内存,但这还不够,因为一些函数调用后还有未释放的内存。我想我只是不知道如何释放它。在每个请求额外内存的函数结束时,我尝试通过 free(函数调用的数组)释放它,但在这种情况下它显示分段错误。如果您至少让我知道一些事情,我将不胜感激。

这里是输入示例

xUbbemehbT
XYlloworld

valgrind 输出不是说你有内存泄漏或者你没有正确释放一些东西。

如果您查看这部分输出:

==56665== HEAP SUMMARY:
==56665==     in use at exit: 0 bytes in 0 blocks
==56665==   total heap usage: 4 allocs, 4 frees, 2,098 bytes allocated
==56665== 
==56665== All heap blocks were freed -- no leaks are possible

它表明所有分配的内存块都已释放。所以你没有分配问题。

重要的是这部分:

==56665== Conditional jump or move depends on uninitialised value(s)
==56665==    at 0x4015BF: compare (main.c:107)
==56665==    by 0x401468: shift (main.c:56)
==56665==    by 0x4012C3: main (main.c:44)

这表示在第 107 行的 compare 函数(从第 56 行的 shift 调用,又从第 44 行的 main 调用),一个读取了从未初始化的值。这一行是:

for (int j = 0; msgEnc[j]; ++j){

所以这告诉我们您正在读取从未写入的 msgEnc 数组中的一个字节。该数组是在 read_Input_Msg 函数中写入的,该函数一次将一个字符读入数组。

因为这个数组应该是一个字符串,并且因为您一次读取一个字节,所以您需要手动添加一个您没有做的终止空字节。因此,当最终调用 compare 时,上面的行正在寻找一个从未明确写入的空字节,因此您最终会读取未初始化的字节。

read_Input_Msg中的主while循环之后,在字符串末尾添加空字节:

while ((c = getchar()) != EOF && c != '\n'){
    ...
}
msg[len]=0;