我很久没有使用过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()教程的内容 - 而且我已经看过几个了。
任何见解都将非常感谢!
答案 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;
所以,为了清楚起见,你有三个问题:
strncpy
也不会,因为它在允许的字节数内没有遇到字符串终止符。)我刚刚在你的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;
}