C 中返回的数组不包含相同的值
Returned array in C doesn't contain same values
我正在自学 C,我对导致以下问题的原因感到困惑:当我在方法中创建数组并将其 return 作为指向调用函数的指针时,none的内容是正确的。我将这个问题归结为以下示例:
char * makeArr(void){
char stuff[4];
stuff[0]='a';
stuff[1]='b';
stuff[2]='c';
stuff[3]='d';
printf("location of stuff:%p\n",stuff);
int i;
for(i = 0; i < 4; i++){
printf("%c\n",stuff[i]);
}
return stuff;
}
int main(void){
char* myarr;
myarr = makeArr();
int i;
printf("\n");
printf("location of myarr:%p\n", myarr);
for(i = 0; i < 4; i++){
printf("%c\n",myarr[i]);
}
}
输出 return 如下:
location of stuff:0028FF08
a
b
c
d
location of myarr:0028FF08
Ä
ÿ
(
(a null character)
所以我已经验证了两个值之间的位置相同,但是值不同。我想我遗漏了一些关键的 C 警告;我可以推测这与数组衰减为指针或变量范围的问题有关,但是如果能对此有所启发,我们将不胜感激。
您的数组 stuff
是在函数 makeArr
的本地定义的。你不应该期望它在那个函数的生命周期之后继续存在。
char * makeArr(void){
char stuff[4];
相反,试试这个:
char * makeArr(void){
char *stuff=(char*)calloc(4, sizeof(char));
这将动态创建一个数组,该数组将一直存在,直到您 free()
它。
您尝试做的是 return 局部变量的地址,该变量在函数退出时超出范围,无异于:
char *fn(void) {
char xyzzy = '7';
return &xyzzy;
}
这是因为,除了某些有限的情况,数组会衰减为指向该数组第一个元素的指针。
虽然技术上你可以return那个指针(它本身并不是无效的),但你不能 do 是在之后用类似的东西取消引用它:
char *plugh = fn();
putchar (*plugh);
这样做是未定义的行为,根据 C11 6.5.3.2 Address and indirection operators /4
(我的粗体):
If an invalid value has been assigned to the pointer, the behaviour of the unary *
operator is undefined.
Among the invalid values for dereferencing a pointer by the unary *
operator are a null pointer, an address inappropriately aligned for the type of object pointed to, and the address of an object after the end of its lifetime.
说明问题后,有(至少)两种方法可以解决它。
首先,您可以在函数外部创建数组(扩大其范围),并将其地址传递给要填充的函数。
void makeArr (char *stuff) {
stuff[0]='a';
stuff[1]='b';
stuff[2]='c';
stuff[3]='d';
}
int main(void) {
char myarr[4];
makeArr (myarr);
// Use myarr here
}
其次,您可以在函数内部动态分配数组并将其传回。当函数退出时,在堆上创建的项目不会超出范围,但是您应该确保在尝试使用它之前分配成功,并且在您使用它时释放内存重新完成它。
char *makeArr (void) {
char *stuff = malloc (4);
if (stuff != NULL) {
stuff[0]='a';
stuff[1]='b';
stuff[2]='c';
stuff[3]='d';
}
return stuff;
}
int main(void) {
char *myarr;
myarr = makeArr();
if (myarr != NULL) {
// Use myarr here
free (myarr);
}
}
stuff[]
只在函数调用时存在于栈中,在return之后被覆盖。如果你想让它保存值,声明它 static
它会做你想做的事。
然而,整个想法从根本上来说是蹩脚的,不要在现实生活中这样做。如果你想要一个函数来初始化数组,在函数外部声明一个数组,将指向这个数组的指针作为参数传递给函数,然后通过该指针初始化一个数组。您可能还想将数组的大小作为第二个参数传递。
为了学习,特意省略了示例代码。
我正在自学 C,我对导致以下问题的原因感到困惑:当我在方法中创建数组并将其 return 作为指向调用函数的指针时,none的内容是正确的。我将这个问题归结为以下示例:
char * makeArr(void){
char stuff[4];
stuff[0]='a';
stuff[1]='b';
stuff[2]='c';
stuff[3]='d';
printf("location of stuff:%p\n",stuff);
int i;
for(i = 0; i < 4; i++){
printf("%c\n",stuff[i]);
}
return stuff;
}
int main(void){
char* myarr;
myarr = makeArr();
int i;
printf("\n");
printf("location of myarr:%p\n", myarr);
for(i = 0; i < 4; i++){
printf("%c\n",myarr[i]);
}
}
输出 return 如下:
location of stuff:0028FF08
a
b
c
d
location of myarr:0028FF08
Ä
ÿ
(
(a null character)
所以我已经验证了两个值之间的位置相同,但是值不同。我想我遗漏了一些关键的 C 警告;我可以推测这与数组衰减为指针或变量范围的问题有关,但是如果能对此有所启发,我们将不胜感激。
您的数组 stuff
是在函数 makeArr
的本地定义的。你不应该期望它在那个函数的生命周期之后继续存在。
char * makeArr(void){
char stuff[4];
相反,试试这个:
char * makeArr(void){
char *stuff=(char*)calloc(4, sizeof(char));
这将动态创建一个数组,该数组将一直存在,直到您 free()
它。
您尝试做的是 return 局部变量的地址,该变量在函数退出时超出范围,无异于:
char *fn(void) {
char xyzzy = '7';
return &xyzzy;
}
这是因为,除了某些有限的情况,数组会衰减为指向该数组第一个元素的指针。
虽然技术上你可以return那个指针(它本身并不是无效的),但你不能 do 是在之后用类似的东西取消引用它:
char *plugh = fn();
putchar (*plugh);
这样做是未定义的行为,根据 C11 6.5.3.2 Address and indirection operators /4
(我的粗体):
If an invalid value has been assigned to the pointer, the behaviour of the unary
*
operator is undefined.Among the invalid values for dereferencing a pointer by the unary
*
operator are a null pointer, an address inappropriately aligned for the type of object pointed to, and the address of an object after the end of its lifetime.
说明问题后,有(至少)两种方法可以解决它。
首先,您可以在函数外部创建数组(扩大其范围),并将其地址传递给要填充的函数。
void makeArr (char *stuff) {
stuff[0]='a';
stuff[1]='b';
stuff[2]='c';
stuff[3]='d';
}
int main(void) {
char myarr[4];
makeArr (myarr);
// Use myarr here
}
其次,您可以在函数内部动态分配数组并将其传回。当函数退出时,在堆上创建的项目不会超出范围,但是您应该确保在尝试使用它之前分配成功,并且在您使用它时释放内存重新完成它。
char *makeArr (void) {
char *stuff = malloc (4);
if (stuff != NULL) {
stuff[0]='a';
stuff[1]='b';
stuff[2]='c';
stuff[3]='d';
}
return stuff;
}
int main(void) {
char *myarr;
myarr = makeArr();
if (myarr != NULL) {
// Use myarr here
free (myarr);
}
}
stuff[]
只在函数调用时存在于栈中,在return之后被覆盖。如果你想让它保存值,声明它 static
它会做你想做的事。
然而,整个想法从根本上来说是蹩脚的,不要在现实生活中这样做。如果你想要一个函数来初始化数组,在函数外部声明一个数组,将指向这个数组的指针作为参数传递给函数,然后通过该指针初始化一个数组。您可能还想将数组的大小作为第二个参数传递。
为了学习,特意省略了示例代码。