我有以下C结构并使用函数getPerson(void)
返回指向我的struct的指针,使用用户输入返回指向新结构的指针。以下代码无法编译,它会出现以下错误:
#include <stdio.h>
#include <stdlib.h>
typedef struct {
char name[50];
int age;
} person;
person* getPerson(void)
{
person* newPerson = (person*)malloc(sizeof(person));
int ageInput;
char *nameInputPtr = (char*)malloc(50 * sizeof(char));
printf("Please enter your name: \n");
scanf("%s", nameInputPtr);
printf("Please enter your age: \n");
scanf("%d", &ageInput);
newPerson->name[50] = *nameInputPtr;
newPerson->age = ageInput;
return newPerson;
}
我得到错误:
struct.c:22:2: error: array index 50 is past the end of the array (which contains 50 elements)
[-Werror,-Warray-bounds]
newPerson->name[50] = *nameInputPtr;
^ ~~
struct.c:6:2: note: array 'name' declared here
char name[50];
^
我设法通过第22行中的以下更改修复错误:
22 newPerson->name[49] = *nameInputPtr;
所以我的更改是将数字50更改为第49行,使其位于第6行索引定义的范围内。
因此,我不明白为什么第6行和第22行在原始代码中出错,我想对错误以及我的解决方案的清晰度和功能有一个解释。
答案 0 :(得分:3)
C
中的数组索引基于0
。对于分配了50个字节内存的数组,
char name[50];
尝试使用[50]
作为索引 off-by-one 并调用undefined behaviour。
那就是说,
newPerson->name[50] = *nameInputPtr;
不是复制字符串的方式。您需要使用strcpy()
,例如
strcpy(newPerson->name, nameInputPtr);
此外,最好在使用scanf()
时限制输入字符串长度,以避免可能的缓冲区溢出。变化
scanf("%s", nameInputPtr);
到
scanf("%49s", nameInputPtr);
但是,请注意,如果您已经使用固定大小的分配设计,则使用动态内存没有多大意义。您可以轻松地使用编译时分配的数组。
答案 1 :(得分:2)
什么?
此:
newPerson->name[50] = *nameInputPtr;
说&#34;将*nameInputPtr
处的字符分配给name
&#34;中索引50处的字符。但是name
只有50个字符长,并且数组在C中是基于0的,所以这是超出界限的。
但是,这段代码没有任何意义!你想要:
strcpy(newPerson->name, nameInputPtr);
复制整个字符串。这会冒传播缓冲区溢出的风险,因为您不会限制scanf()
中的输入。
所以,更好,因为你已经有person
,只需输入它:
scanf("%49s", person->name);
请记住检查返回值。
当然你应该为年龄做同样的事情,不需要一个单独的整数然后被复制到结构中。
答案 2 :(得分:0)
您必须使用sprintf
strcpy(newPerson->name, nameInputPtr);
请注意C
中的数组基于0
,name[50]
不存在。
在您的特定情况下,您使用数组作为字符串,您必须验证数组的大小是STR_LEN_MAX+1
,因为字符串是空终止的。这意味着字符串总是需要在字符串中的最后一个字符之后的一个字节,其中可以插入'\0'
字符。