我正在学习C。我遇到了字符串数组。我对以下代码感到困惑。我正在期待一种输出。但是,由于读取访问冲突,导致获得完全不同的输出或程序崩溃。
我已使用_CRT_SECURE_NO_WARNINGS在Visual Studio 2017上运行此代码
// case 1
char* name[2];
//name[0] = (char*)malloc(sizeof(char*) * 10);
//name[1] = (char*)malloc(sizeof(char*) * 10);
name[0] = "john";
name[1] = 'doe';
printf("%s\n", name[0]); // prints john
//printf("%s\n", name[1]); // gives read access violation exception, why??? even with dynamically allocated memory
// case 2
char* name2[2] = { "emma", "olsson" };
printf("%s\n", name2[0]); // prints emma
printf("%s\n", name2[1]); // prints olsson, why no error???
// case 3
for (int i = 0; i < 2; i++)
{
name[i] = name2[i];
}
printf("%s\n", name[0]); // prints emma
printf("%s\n", name[1]); // prints olsson, why no error???
// case 4
char inputName[10];
int i = 0;
while (i < 2)
{
fgets(inputName, sizeof(inputName), stdin); // first input: Max second input: Payne
char* pos = strchr(inputName, '\n');
if (pos != NULL)
*pos = '\0';
name[i++] = inputName;
}
printf("%s\n", name[0]); // prints Payne, why not Max???
printf("%s\n", name[1]); // prints Payne
答案 0 :(得分:2)
对于情况1,“ doe”不是字符串。
第2种情况之所以有效,是因为您正在用字符串文字初始化指针。
案例3也是可行的,因为您将案例2中相同的初始化指针分配给案例1指针。您的名称数组指针基本上设置为指向name2指向的位置。
在情况4中,您声明了inputName,它指向一组10个字符。然后,每当您收到新输入时,便会将其写入相同的内存部分。然后执行以下操作:name[i++] = inputName;
您没有像您想的那样将新的char数组复制到name [i]。相反,您要告诉name [i] char指针指向inputName。因此,正常情况下,名称将最后一次输入打印两次,因为这是inputName指向的内容,以及两个名称char指针。
答案 1 :(得分:0)
尚不清楚OP的代码是在main()还是用户定义的函数中运行以及返回哪种类型的值。就是说,在删除了多余的变量重新声明之后,这就是我实现工作代码的方式:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void) {
char * name[2];
char * name2[2]={ "emma", "olsson" };
char inputName[10];
char names[BUFSIZ];
int i = 0;
// case 1
name[0] = "john";
name[1] = "doe";
printf("%s %s\n", name[0],name[1]); //john doe
// case 2
printf("%s %s\n", name2[0],name2[1]);//emma olsson
// case 3
for (i = 0; i < 2; i++){
name[i] = name2[i];
}
printf("%s %s\n", name[0],name[1]);//emma olsson
// case 4
i=0;
while (fgets(inputName, sizeof(inputName), stdin) != NULL && (i < 2) ){
strcat(names,inputName);
i++;
}
printf("\n%s\n",names);
return 0;
}
查看实时代码here
OP应该用双引号替换doe
周围的单引号,双引号表示以空值结尾的字符串。单引号用于单个字符,即“ a”表示字节值,而“ a”表示包含两个字符,即“ a”和“ \ 0”的字符串。
此外,OP还应包括其他两个库以方便执行。特别是,string.h是内置字符串函数正确执行所必需的。
案例2和案例3之所以起作用,是因为字符串用双引号而不是单引号引起来。请注意,在每种情况下,printf()的“%s”格式说明符均指示需要显示字符串。
在最后一种情况下,关于stdin的fgets()成功后将用户输入作为字符串返回。但是该输入将在while循环中被覆盖,除非在每次迭代中将旧输入与新输入连接在一起。否则,当inputName元素的值由于其地址保持不变而更改时,仅显示最新的输入字符串。这是一些说明这一点的代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void) {
char * name[2];
char inputName[10];
int i = 0;
while (fgets(inputName, sizeof(inputName), stdin) != NULL && (i < 2) ){
printf("inputName: %p points to: %s",inputName,inputName);
name[i++] = inputName;
}
printf("\n name[0]: %p points to: %s\n name[1]: %p points to: %s",name[0],name[0],name[1],name[1]);
return 0;
}
Output: inputName: 0x7fff8a511a50 points to: Maxine inputName: 0x7fff8a511a50 points to: Pauline name[0]: 0x7fff8a511a50 points to: Pauline name[1]: 0x7fff8a511a50 points to: Pauline
请参见live code.
顺便说一句,您不需要一个数组来显示名称,实际上只要在代码中将用户输入连接起来的循环中,就可以在循环外显示名称。