在函数内静态识别的数组

问题描述 投票:0回答:3

我在理解这个程序的特定情况下的静态标识符时遇到了问题。该计划的背景是关于“指针”的讲座。

该程序的工作是为临时文件创建一个新名称,它通过在每次调用函数static int sequence时创建一个新名称来完成此任务(在tmp_name的帮助下)。

  1. 第一次调用 - >“tmp0”
  2. 第二次调用 - >“tmp1”
  3. ...

[码]

#include <stdio.h>
#include <string.h>

/*******************************************************
 * tmp_name -- Return a temporary filename             *
 *                                                     *
 * Each time this function is called, a new name will  *
 * be returned.                                        *
 *                                                     *
 * Returns                                             *
 *      Pointer to the new filename                    *
 *******************************************************/
char *tmp_name(void){

    static char name[30]; /* The name we are generating */
    static int sequence = 0; /* Sequence number for last digit */

    ++sequence; /* Move to the next filename */

    strcpy(name, "tmp");

    name[3] = sequence + '0';

    /* End the string */
    name[4] = '\0';

    return(name);
}

int main(){

    char *tmp_name(void); /* Get the name of temporary file, very first call */
    char *name1; /* Name of a temporary file, second call */
    char *name2; /* Name of another temporary file, third call */

    name1 = tmp_name();
    name2 = tmp_name();

    printf("Name1: %s\nName2: %s\n", name1, name2);
    return(0);
}

所以程序的输出(因为调用printf函数)是打印“tmp1”和“tmp2”(“tmp0”无法打印,完全没问题)。

所以该计划是完美的工作,那么问题是什么?问题是,如果我从static删除static char name[30]程序中断。它打印出来:

Name1: \340\364\277\357\376
Name2: \340\364\277\357\376

我研究了静态意味着什么以及意味着什么,因此使用static int sequence对我来说非常清楚,但我真的不明白为什么数组[name]也是静态声明的。

c arrays function pointers static
3个回答
1
投票
char *stuff() {
    char thing[100];
    strcpy(thing, "what are you returning??");

    return thing;
}

现在,你还要回到这里?一个指针。要什么?请记住,函数返回后会破坏非静态局部变量。所以,在char *data = stuff();,变量data将充满垃圾,因为thing已被处理掉。

然而,静态变量仍然存在并且即使在函数退出时也完全有效,因此您返回的指针仍然指向程序拥有的内存并且肯定包含您放在那里的数据,而在非情况下静态变量,一旦函数退出就失去对这个内存的控制,因此任何程序都可以放置任何内容,这就是你获取这些垃圾数据的方法。


1
投票

问题是,如果我从静态字符名称[30]中删除静态,程序就会中断。

如果为static删除name,它将成为具有自动存储持续时间的对象并返回它(即指向局部变量的指针)会导致未定义的行为。使用static它是有效的,因为name将具有静态存储持续时间(即,name对象在整个程序的执行期间是活着的)。

或者,您可以动态分配内存(例如,使用malloc)并将name复制到其中并返回它。


1
投票

让我们从基础开始:§5.2.3标准N1570

对象的生命周期是程序执行的一部分,在此期间保证为其保留存储。一个对象存在,具有一个常量地址,33)并在其整个生命周期内保留其最后存储的值.34)如果一个对象在其生命周期之外被引用,则该行为是未定义的。当指针指向(或刚刚过去)的对象到达其生命周期的末尾时,指针的值变得不确定。

斜体提出了一个很好的想法 - 它与其他任何东西有什么关系?用于静态存储持续时间

声明标识符的对象没有存储类说明符_Thread_local,并且具有外部或内部链接或存储类说明符static,具有静态存储持续时间。它的生命周期是程序的整个执行,它的存储值只在程序启动之前初始化一次。

所以这意味着当你写static somevar时,它将一直存在,直到程序在这种情况下结束,直到main()结束。 static变量的存储持续时间超出了函数的范围。因此返回指向它的指针是有效的。它不会是非法代码。

现在让我们看看另一个

声明标识符没有链接且没有存储类说明符静态的对象具有自动存储持续时间,一些复合文字也是如此。

这意味着当你在这种情况下从变量名中删除static并且它在函数的封闭块中时 - 它是自动存储持续时间。

然后是解释为什么第二个失败的最重要部分

对于具有可变长度数组类型的此类对象,其生命周期从对象的声明扩展,直到程序的执行离开声明的范围。

这样的对象在这里意味着具有自动存储持续时间正如你在这里看到的那样,当函数体结束的封闭块时 - 你从函数返回的指针的值变得不确定并且访问它是undefined behavior(检查第一段)。

这就解释了为什么你看到你所看到的。(这就是你所问的 - 发生了什么,为什么会这样?)这是给定行为的标准明智解释。

© www.soinside.com 2019 - 2024. All rights reserved.