1

我很久没用过 C 了,显然我忘记的比我想象的要多。在尝试使用 malloc() 分配字符串时,我不断获取该字符串的旧数据,包括它的旧数据,当请求的空间较短时长度较长。这种情况确实包括指向被 free()'d 并设置为 NULL 的字符串的指针。这是我在终端中看到的示例运行:

yes, quit, or other            (<-message from program)
oooo                           (<-user input; this will be put to upper case and token'd)

------uIT LENGTH:4             (<-debug message showing length of userInputToken)

preC--tmp:                     (<-contents of tmp variable)

pstC--tmp:OOOO                 (<-contents of temp variable)
bad input                      (<-program response)
yes, quit, or other
yes

------uIT LENGTH:3

preC--tmp:OOOO                 (<-: tmp = malloc(sizeof(char)*(strlen(userInputToken)-1)); )

pstC--tmp:YESO                 (<-: strncpy(tmp,userInputToken,strlen(userInputToken)-1);  )
bad input
yes, quit, or other
yes

------uIT LENGTH:3

preC--tmp:YESO

pstC--tmp:YESO
bad input
yes, quit, or other
quit

------uIT LENGTH:4

preC--tmp:YESO

pstC--tmp:QUIT                 (<-: Successful quit because I only did 4 chars; if 5 were used, this would have failed)

如您所见, strlen(userInputToken) 获得了正确的长度,并用于获取正确数量的复制字符——但无论是 free() 还是 malloc() 似乎都不关心它。我无法弄清楚这里发生了什么!这是将 C 留给 Python 的惩罚吗?

更重要的是,应该清除 tmp 变量,而不管 free() 是什么,因为它受到其范围的限制。这是一切都失败的代码:

在 main.c 中:

void run() {
    outputFlagContainer *outputFlags = malloc(sizeof(outputFlagContainer));

    while(true) {
        puts("yes, quit, or other");
        outputFlags = getUserInput(outputFlags);
        if (outputFlags->YES) {
            puts("It was a yes!");
        } else if (outputFlags->QUIT) {
            break;
        } else {
            puts("bad input");
        }
    }

    free(outputFlags);
}

在 messageParserPieces.h 中:

outputFlagContainer *getUserInput(outputFlagContainer *outputFlags) {
    outputFlags = resetOutputFlags(outputFlags);
    char *userInput = NULL;
    char user_input[MAX_INPUT];
    char *userInputToken = NULL;
    char *tmp = NULL;
    char *finalCharacterCheck = NULL;

    // Tokens to search for:
    char QUIT[] = "QUIT";
    char YES[] = "YES";

    userInput = fgets(user_input, MAX_INPUT-1, stdin);
    int i = 0;
    while(userInput[i]) {
        userInput[i] = toupper(userInput[i]);
        i++;
    }

    userInputToken = strtok(userInput, " ");
    if (userInputToken) {
        finalCharacterCheck = strchr(userInputToken, '\n');
        if (finalCharacterCheck) {
            int MEOW = strlen(userInputToken)-1; // DEBUG LINE
            printf("\n------uIT LENGTH:%d\n", MEOW); // DEBUG LINE

            // The problem appears to happen here and under the circumstances that
            // userInput is (for example) 4 characters and then after getUserInput()
            // is called again, userInput is 3 characters long. 
            tmp = malloc(sizeof(char)*(strlen(userInputToken)-1));
            if (tmp == NULL) {
                exit(1);
            }

            printf("\npreC--tmp:%s\n", tmp); // This shows that the malloc DOES NOT use the given length.

            strncpy(tmp,userInputToken,strlen(userInputToken)-1);

            printf("\npstC--tmp:%s\n", tmp); // Copies in the correct number of characters.

            userInputToken = tmp;
            free(tmp);
            tmp = NULL;
        }
    }

    while (userInputToken != NULL) { // NULL = NO (more) tokens.
        if (0 == strcmp(userInputToken, YES)) {
            outputFlags->YES = true;
        } else if (0 == strcmp(userInputToken, QUIT)) {
            outputFlags->QUIT = true;
        }

        userInputToken = strtok(NULL, " ");
        if (userInputToken) {
            finalCharacterCheck = strchr(userInputToken, '\n');
            if (finalCharacterCheck) {
                tmp = malloc(sizeof(char)*(strlen(userInputToken)-1));
                if (tmp == NULL) {
                    exit(1);
                }
                strncpy(tmp,userInputToken,strlen(userInputToken)-1);
                userInputToken = tmp;
                free(tmp);
                tmp = NULL;
            }
        }
    }
    return outputFlags;
}

我假设这是某种明显的错误,但我今晚尝试用谷歌搜索它大约 2 小时。我想不出如何搜索这个不带 malloc() 教程的东西——我已经看过几个了。

任何见解都将不胜感激!

4

4 回答 4

2
tmp = malloc(sizeof(char)*(strlen(userInputToken)-1));
if (tmp == NULL) {
    exit(1);
}

printf("\npreC--tmp:%s\n", tmp); // This shows that the malloc DOES NOT use the given length.

strncpy(tmp,userInputToken,strlen(userInputToken)-1);
printf("\npstC--tmp:%s\n", tmp); // Copies in the correct number of characters.

此片段显示您希望tmp使用某些内容进行初始化。这不是真的。您必须在分配内存后对其进行初始化。这就是你所做的strncpy

还有一个问题,因为您没有分配足够的字节来保存字符串,因此您无法使用纯%s格式说明符显示它。您正在分配strlen(userInputToken)-1字节并复制相同的数字。这意味着没有空字符的空间,strncpy因此不会终止您的字符串。你应该总是多加一个字节,如果 NULL 字符不会被复制,strncpy那么你必须自己设置它:

size_t length = strlen(userInputToken)-1;
tmp = malloc(length + 1);
strncpy(tmp, userInputToken, length);
tmp[length] = 0;

所以,为了清楚起见,你有三个问题:

  1. 在初始化之前显示新分配的“字符串”;
  2. 您没有分配足够的内存来保存字符串
  3. 您不会终止字符串(也不会,strncpy因为它没有在允许的字节数内遇到字符串终止符)。

我刚刚在你的循环中发现了其他东西while (userInputToken != NULL)......你总是在循环开始时使用字符串比较userInputToken,但在循环内部(以及循环上方的部分)你这样做:

userInputToken = tmp;
free(tmp);

这意味着userInputToken是一个悬空指针。它指向已被释放的内存,你不能使用它。您将不得不重新考虑您的方法,并让它一直存在,直到不再需要它为止。

于 2013-01-16T04:19:47.283 回答
1

您可能应该使用 calloc。您也不应该像这样使用未初始化的内存。Malloc 以块的形式分配内存。当您释放一个块时,它可能会被重用。您没有得到确切的大小,并且在您使用 malloc 设置内存之前,不能保证其字节的值是多少。您所知道的是,您有一块至少与您请求的大小一样大的内存可供使用。所以在这个例子中,你在写入之前打印内存块的旧内容。

于 2013-01-16T04:19:03.357 回答
1

您使用此行对分配长度的验证不正确:

printf("\npreC--tmp:%s\n", tmp); // This shows that the malloc DOES NOT use the given length.

malloc将分配请求的字节数,但不会初始化分配的内存。因此,当您尝试将其打印为应以 结尾的字符串时'\0',它将尝试打印所有字符,直到'\0'在内存中找到为止。终止字符可能不是来自同一个内存块。的存在'\0'是不确定的。

于 2013-01-16T04:23:39.110 回答
0

我希望这有帮助

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

#define MAX_INPUT 128
#define true 1
#define false 0

typedef struct _outputFlagContainer{

int  YES, QUIT;

}outputFlagContainer;


void run();
outputFlagContainer *getUserInput(outputFlagContainer *outputFlags);
outputFlagContainer *resetOutputFlags(outputFlagContainer *outputFlags);

int main(int argc, char *argv[]){

run();      
return 0;
}    

void run() {

    outputFlagContainer *outputFlags = malloc(sizeof(outputFlagContainer));

    while(true) {       

        puts("yes, quit, or other");

        outputFlags = getUserInput(outputFlags);

        if (outputFlags->YES) 
        {
            puts("It was a yes!");
        }
        else if (outputFlags->QUIT) 
        {
            break;
        }
        else
        {
            puts("bad input");
        }

    }

    free(outputFlags);
}

outputFlagContainer *resetOutputFlags(outputFlagContainer *outputFlags) {

    if(outputFlags!= NULL){

        outputFlags->YES = false;
        outputFlags->QUIT = false;      

    }

    return outputFlags;

}

outputFlagContainer *getUserInput(outputFlagContainer *outputFlags) {

    int len;
    char user_input[MAX_INPUT]={0};     // Zero Initialization

    char *userInput = NULL;
    char *userInputToken = NULL;
    char *tmp = NULL;
    char *finalCharacterCheck = NULL;

    // Tokens to search for:        // Immutable Strings
    char *QUIT = "QUIT";
    char *YES = "YES";

    // Reset The Structure
    outputFlags = resetOutputFlags(outputFlags);

    userInput = fgets(user_input, MAX_INPUT, stdin);        // it copies one less than MAX_INPUT 

    // Converting to Upper Case
    int i = 0;
    while(userInput[i]) {
        userInput[i] = toupper(userInput[i]);
        i++;
    }

    userInputToken = strtok(userInput, " ");

    if (userInputToken) {

        finalCharacterCheck = strchr(userInputToken, '\n');

        if (finalCharacterCheck) {

            len = strlen(userInputToken);

            printf("\n------uIT LENGTH:%d\n", len); // DEBUG LINE

            tmp = malloc(sizeof(char)*(len+1));
            if (tmp == NULL)
                exit(1);

            strncpy(tmp,userInputToken,len);
            tmp[len]='\0';

            printf("\npstC--tmp:%s\n", tmp); // Copies in the correct number of characters.

            strcpy(user_input,tmp);
            userInputToken = user_input;
            free(tmp);
            tmp = NULL;
        }
    }

    while (userInputToken != NULL) { // NULL = NO (more) tokens.

        if (0 == strcmp(userInputToken, YES)) {

            outputFlags->YES = true;

        } 
        else if (0 == strcmp(userInputToken, QUIT)) {

            outputFlags->QUIT = true;

        }

        userInputToken = strtok(NULL, " ");

        if (userInputToken) {

            finalCharacterCheck = strchr(userInputToken, '\n');

            if (finalCharacterCheck) {

                len = strlen(userInputToken);        
                tmp = malloc(sizeof(char)*(len+1));
                if (tmp == NULL) {
                    exit(1);
                }

                strncpy(tmp,userInputToken,len);
                tmp[len]='\0';

                strcpy(user_input,tmp);
                userInputToken = user_input;                                                
                free(tmp);
                tmp = NULL;
            }
        }
    }

    return outputFlags;
}
于 2013-01-16T12:41:56.497 回答