C:malloc()忽略请求的大小?

时间:2013-01-16 04:10:29

标签: c malloc free

我很久没有使用过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离开C的惩罚吗?

更重要的是,无论free()如何,都应清除tmp变量,因为它受范围的限制。以下是一切都失败的代码:

在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);
}

在messsageParserPieces.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 个答案:

答案 0 :(得分: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将不会终止您的字符串。您应该总是再添加一个字节,如果strncpy不会复制NULL字符,那么您必须自己设置:

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

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

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

  4. 我刚刚在你的while (userInputToken != NULL)循环中发现了其他内容...你总是在循环开始时使用userInputToken进行字符串比较,但是在循环内部(以及在循环内部的部分)你执行此操作:

    userInputToken = tmp;
    free(tmp);
    

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

答案 1 :(得分:1)

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

答案 2 :(得分:1)

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

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

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

答案 3 :(得分: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;
}