C:malloc()是否忽略请求的大小?
我已经很长时间没有使用C了,显然我忘记的比我想象的要多。在尝试使用malloc()分配字符串时,我不断获取该字符串的旧数据,包括当请求的空间较短时它的旧的、较长的长度。这种情况确实包括指向字符串free()d并设置为NULL的指针。以下是我在终端中看到的示例运行:C:malloc()是否忽略请求的大小?,c,malloc,free,C,Malloc,Free,我已经很长时间没有使用C了,显然我忘记的比我想象的要多。在尝试使用malloc()分配字符串时,我不断获取该字符串的旧数据,包括当请求的空间较短时它的旧的、较长的长度。这种情况确实包括指向字符串free()d并设置为NULL的指针。以下是我在终端中看到的示例运行: yes, quit, or other (<-message from program) oooo (<-user input; this will
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)
在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;
}
我假设这是某种明显的错误,但今晚我在谷歌上搜索了大约两个小时。我想不出如何搜索这个不带malloc()教程的文档,我已经看过了一些
如果您有任何见解,我们将不胜感激 您可能应该使用calloc。您也不应该像这样使用未初始化的内存。Malloc以块的形式分配内存。当您释放一个块时,它可能会被重用。您无法获得确切的大小,除非使用malloc重置内存,否则无法保证其字节的值。您所知道的是,您有一块至少与您请求的大小一样大的内存可供使用。因此,在本例中,您在写入内存块之前打印内存块的旧内容 您可能应该使用calloc。您也不应该像这样使用未初始化的内存。Malloc以块的形式分配内存。当您释放一个块时,它可能会被重用。您无法获得确切的大小,除非使用malloc重置内存,否则无法保证其字节的值。您所知道的是,您有一块至少与您请求的大小一样大的内存可供使用。因此,在本例中,您在写入内存块之前打印内存块的旧内容
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
复制,则必须自己设置:
size_t length = strlen(userInputToken)-1;
tmp = malloc(length + 1);
strncpy(tmp, userInputToken, length);
tmp[length] = 0;
所以,我想说清楚,你有三个问题:
我刚刚在您的
循环中发现了其他东西(userInputToken!=NULL)
循环。。。您总是在循环开始时使用userInputToken
进行字符串比较,但在循环内部(以及循环上方的部分),您可以执行以下操作:
userInputToken = tmp;
free(tmp);
这意味着userInputToken
是一个悬空指针。它指向已释放的内存,您不能使用它。你必须重新思考你的方法,让它继续存在,直到不再需要它
这段代码表明您希望tmp
被初始化。事实并非如此。分配内存后,必须初始化内存。这就是你用strncpy所做的
还有一个问题,因为您没有分配足够的字节来保存字符串,因此无法使用普通的%s
格式说明符来显示它。您正在分配strlen(userInputToken)-1
字节并复制相同的数字。这意味着没有空字符的空间,strncpy
将不会终止字符串。您应该始终再添加一个字节,如果空字符不会被strncpy
复制,则必须自己设置:
size_t length = strlen(userInputToken)-1;
tmp = malloc(length + 1);
strncpy(tmp, userInputToken, length);
tmp[length] = 0;
所以,我想说清楚,你有三个问题:
我刚刚在您的
循环中发现了其他东西(userInputToken!=NULL)
循环。。。您总是在循环开始时使用userInputToken
进行字符串比较,但在循环内部(以及循环上方的部分),您可以执行以下操作:
userInputToken = tmp;
free(tmp);
这意味着
userInputToken
是一个悬空指针。它指向已释放的内存,您不能使用它。您必须重新考虑您的方法,并允许其继续使用,直到不再需要为止。您用这一行验证分配的长度是不正确的:
printf("\npreC--tmp:%s\n", tmp); // This shows that the malloc DOES NOT use the given length.
malloc
将分配请求的字节数,但不会初始化分配的内存。因此,当您尝试将其打印为字符串(应以'\0'
结尾)时,它将尝试打印所有字符,直到在内存中找到'\0'
。终止字符不能来自同一内存块。'\0'
的存在是不确定的。您用此行验证分配的长度是不正确的:
printf("\npreC--tmp:%s\n", tmp); // This shows that the malloc DOES NOT use the given length.
malloc
将分配请求的字节数,但不会初始化分配的内存。因此,当您尝试将其打印为字符串(应以'\0'
结尾)时,它将尝试打印所有字符,直到在内存中找到'\0'
。终止字符不能来自同一内存块。'\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;
}
#包括
#包括
#在