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 它会做你想做的事。

然而,整个想法从根本上来说是蹩脚的,不要在现实生活中这样做。如果你想要一个函数来初始化数组,在函数外部声明一个数组,将指向这个数组的指针作为参数传递给函数,然后通过该指针初始化一个数组。您可能还想将数组的大小作为第二个参数传递。

为了学习,特意省略了示例代码。