我在理解本程序特定情况下的静态标识符时遇到了问题。该计划的背景是关于"指针"。
的讲座这个程序的工作是为临时文件创建一个新名称,它通过每次函数tmp_name
创建一个新名称来完成这个(在#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
因此,程序的输出(因为static
函数被调用)是打印&#34; tmp1&#34;和&#34; tmp2&#34; (&#34; tmp0&#34;无法打印,完全没问题。)
所以程序是完美的工作,那么问题是什么?问题是,如果我从static char name[30]
删除Name1: \340\364\277\357\376
Name2: \340\364\277\357\376
,程序会中断。它打印出来:
static int sequence
我研究了静态意味着什么以及意味着什么,因此{{1}}的使用对我来说非常清楚,但我真的不明白为什么数组[name]也是静态声明的。
答案 0 :(得分:1)
char *stuff() {
char thing[100];
strcpy(thing, "what are you returning??");
return thing;
}
现在,你在这里回来什么?一个指针。要什么?请记住,函数返回后会破坏非静态局部变量。因此,在char *data = stuff();
中,变量data
将充满垃圾,因为thing
已被处理掉。
然而,即使函数退出,静态变量仍然存在并且完全有效,因此您返回的指针仍指向程序拥有的内存并且肯定包含你放在那里的数据,而在非静态变量的情况下,一旦函数退出就会失去对这个内存的控制,因此任何程序都可以放置任何内容,这就是你获取这些垃圾数据的方法。 / p>
答案 1 :(得分:1)
问题是,如果我从静态字符名称[30]中删除静态,程序就会中断。
如果删除static
name
,它将成为具有自动存储持续时间的对象并返回它(即指向本地变量的指针)会导致未定义的行为。 static
可以使用name
,因为name
将具有静态存储持续时间(即,malloc
对象在整个程序执行期间仍处于活动状态。)
或者,您可以动态分配内存(例如,使用name
)并将ExeConfigurationFileMap configFileMap = new ExeConfigurationFileMap();
configFileMap.ExeConfigFilename = "My.config"; // This works locally but not on azure I think
Configuration config = ConfigurationManager.OpenMappedExeConfiguration(configFileMap, ConfigurationUserLevel.None);
AppSettingsSection section = (AppSettingsSection)config.GetSection("appSettings");
var test = section.Settings["test"].Value; // throws nullref
复制到其中并将其返回。
答案 2 :(得分:1)
对象的生命周期是程序执行的一部分,在此期间保证为其保留存储。对象存在,具有常量地址,33)并在其整个生命周期内保留其最后存储的值.34)如果在其生命周期之外引用对象,则行为未定义。 当指针指向(或刚刚过去)的对象到达其生命周期的末尾时,指针的值变得不确定。
斜体字提出了一个好主意 - 它与其他任何东西有什么关系?对于静态存储持续时间
声明标识符的对象没有存储类说明符_Thread_local,并且具有外部或内部链接或具有存储类说明符
static
,具有静态存储持续时间。它的生命周期是程序的整个执行,它的存储值只在程序启动之前初始化一次。
这意味着当你写static somevar
时,它会一直存在,直到程序在这种情况下结束,直到main()
结束。 static
变量的存储持续时间超出了函数的范围。因此返回指向它的指针是有效的。它不会是非法代码。
现在让我们看看另一个
一个对象,其标识符声明没有链接且没有存储类说明符static具有自动存储持续时间,一些复合文字也是如此。
这意味着在这种情况下从变量名中删除static
并且它位于函数的封闭块中时 - 它是自动存储持续时间。
然后是解释为什么第二个失败的最重要的部分
对于具有可变长度数组类型的此类对象,其生命周期从对象的声明扩展,直到程序的执行离开声明的范围。
这样的对象在这里意味着具有自动存储持续时间的对象。正如你在这里看到函数体结束的封闭块时 - 你从函数返回的指针的值变得不确定并且访问它是undefined behavior(检查第一段)。
这就解释了为什么你看到你所看到的。(这就是你所问的 - 发生了什么,为什么会这样?)这是给定行为的标准明智解释。