我正在尝试编写一个类似于接口的简单shell,它接受用户输入(通过char)并通过指向指针*的指针存储它(确切地说argv是如何工作的)。这是我的代码:
char input[100];
char **argvInput;
char ch;
int charLoop = 0;
int wordCount = 0;
argvInput = malloc(25 * sizeof(char *));
while((ch = getc(stdin))) {
if ((ch == ' ' || ch == '\n') && charLoop != 0) {
input[charLoop] = '\0';
argvInput[wordCount] = malloc((charLoop + 1) * sizeof(char));
argvInput[wordCount] = input;
charLoop = 0;
wordCount++;
if (ch == '\n') {
break;
}
} else if (ch != ' ' && ch != '\n') {
input[charLoop] = ch;
charLoop++;
} else {
break;
}
}
如果我通过:
循环遍历argvInputint i = 0;
for (i = 0; i < wordCount; i++)
printf("Word %i: %s\n", i, argvInput[i]);
argvInput [i]的所有值都是最后一次输入赋值。所以,如果我输入: “快乐的日子即将来临”,循环的输出是:
Word 0: soon
Word 1: soon
Word 2: soon
Word 3: soon
Word 4: soon
我很茫然。很明显,每个循环都会覆盖之前的值,但我正盯着屏幕,无法弄清楚原因......
答案 0 :(得分:4)
这条线是你的祸根:
argvInput[wordCount] = input;
如果您要用另一个替换指针(即input
),则分配新空间无关紧要。
相反,使用strncpy
将input
的部分内容提取到argvInput[wordCount]
。
答案 1 :(得分:2)
argvInput[wordCount] = input;
仅使argvInput[wordCount]
的指针指向input
的内存,而不是将输入内容复制到新分配的内存中。您应该使用memcpy或strcpy来更正您的程序。
指针分配后,内存状态如下图所示。由malloc((charLoop + 1) * sizeof(char));
分配的内存(图中为灰色内存)无法再被您的程序访问,这将导致内存泄漏问题。请注意这一点。
答案 2 :(得分:0)
我建议使用%p而不是%s打印argvInput指针来识别此问题:printf("Word %i: %p\n", i, (void *) argvInput[i]);
你对它打印的价值有什么看法?这与argv的行为有何不同?尝试打印argv:for (size_t x = 0; x < argc; x++) { printf("Word %zu: %p\n", x, (void *) argv[x]); }
现在您已经发现了问题,解释它可能会变得更容易。
此代码分配内存,并在argvInput [wordCount]中存储指向该内存的指针:argvInput[wordCount] = malloc((charLoop + 1) * sizeof(char));
(顺便说一下,sizeof char
此代码用指向输入的指针替换指向已分配内存的指针:argvInput[wordCount] = input;
...因此,所有项目都包含指向同一数组的指针:输入,并且因为丢失引用而导致分配的内存泄漏它。显然,这是有问题的路线;它没有按照你最初的想法做到。
有人建议您使用strdup调用替换malloc调用,并删除有问题的行。我不喜欢这个建议,因为strdup不符合C标准,因此不需要存在。
strncpy会起作用,但它不必要地复杂。 strcpy保证也能正常工作,因为目标数组的大小足以存储字符串。因此,我建议用strcpy(argvInput[wordCount], input);
替换有问题的行。
另一个未详细解释的选项是strtok。现在看来这是最好的,因为它需要对你的代码进行太多的修改。
我有一个用这个代码挑选的骨头:char ch; ch = getc(stdin);
错了。 getc返回一个int是有原因的:任何成功的字符读取都将以unsigned char值的形式返回,该值不可能是负数。如果getc遇到EOF或错误,它将返回负值。将返回值分配给ch后,如何区分错误和成功?
如果第一个角色是'',你有没有想过会发生什么?目前,您的代码将突破循环。如果您的代码是模仿常见的argv解析行为,这似乎是一个错误。调整此代码以解决您的问题可能是一个好主意:
for (int c = getc(stdin); c >= 0; c = getc(stdin)) {
if (c == '\n') {
/* Terminate your argv array and break out of the loop */
}
else if (c != ' ') {
/* Copy c into input */
}
else if (charLoop != 0) {
/* Allocate argvInput[wordCount] and copy input into it,
* reset charLoop and increment wordCount */
}
}