在提出问题之前,我想引用“专家C编程”[页数:276,最后一段]:
“Illiffe矢量数据结构的美妙之处在于,它允许将指向字符串的任意指针数组传递给函数,但只能传递指针数组,而且只能指向字符串。 这是因为字符串和指针都具有明确的越界值(分别为NUL和 NULL )的约定,可以用作结束标记。“
所以,我从上面的文字中理解的是,如果有一个指针数组,它们就会有明显的超出范围的值,比如NULL。(纠正我,如果我错了......)
所以,它让我想知道指针数组的默认值是什么(认为指针数组的最后一个指针为NULL)。尝试下面的代码片段,结果非常不同。
int *x[2];
printf("%p %p",x[0],x[1]);
输出为:(nil)0x400410
int *x[3];
printf("%p %p %p",x[0],x[1],x[2]);
输出为:0xf0b2ff 0x400680(无)
int *x[4];
printf("%p %p %p %p", x[0],x[1],x[2],x[3]);
输出为:(nil)0x4003db 0x7fffe48e4776 0x4006c5
因此,使用上面的输出,很明显有一个明确的Out-of-bound(nil)值分配给其中一个指针(一个指针是NIL),但它真的是终点标记吗?否。
它是C语言的“实现定义”之一吗?
我在Ubuntu机器上使用GCC编译器(4.6.3)。
答案 0 :(得分:4)
它是C语言的“实现定义”之一吗?
不,这不是实现定义的 - 它是明确的“未定义”。对于所有类型的数组也是如此:在显式初始化之前,您在其中看到的值是未定义的。
我从上面的文字中理解的是,如果有一个指针数组,它们就有明确的超出范围的值,如
NULL
。
作者想说有一个值(具体地说,NULL
值)可用于在指针数组中标记“无值”。作者并不是要暗示默认情况下会将这样的无值标记放入指针数组中。
答案 1 :(得分:4)
具有自动存储持续时间的数组或任何对象(即,在没有static
关键字的函数体中定义的任何对象)没有默认初始值,除非您指定一个。它的初始值是垃圾,你在分配内容之前不得访问该值。
具有静态存储持续时间的对象(即,在任何函数外部和/或使用static
关键字定义的任何对象)被初始化为零,其含义为“零”( 0表示整数,0.0表示浮点数,null表示指针)递归地应用于子对象。
您可以使用初始值设定项来确保将指针对象设置为空指针或任何您喜欢的值:
int *x[2] = { NULL, NULL };
或更简单地说:
int *x[2] = { 0 }; /* sets first element to 0, which is converted to a null
pointer; other elements are implicitly set to null
pointers as well */
答案 2 :(得分:2)
您误读了“专家C编程”中的引文。关键词有以下几点:
This is because both strings and pointers have the *convention* of an explicit
out-of-bound value (NUL and NULL, respectively).
有可能甚至传统的都有一个字符串数组,以便最后一个指针设置为NULL
。这可以让人很容易地遍历数组,而不必确切地知道数组中有多少元素:
char* dwarves[] = { "Dopey",
"Grumpy",
"Sleepy",
"Happy",
"Sneezy",
"Bashful",
"Doc",
NULL
};
但是你必须明确地将最后一个指针设置为NULL
。这种结构很有用,因为它们允许优雅的代码。因此,如果您想要打印或以其他方式操作数组,您无需担心其中包含多少字符串,因为NULL
指针将指示结束:
for (char** pWalk = dwarves; *pWalk; pWalk++)
printf ("%s\n", *pWalk);
这种特殊类型的粗糙数组结构的优点在于,字符串按定义具有内置的NUL
终结符,而指针数组以NULL
终止,因此端点为两个维度都是已知的。但是,作为数组中最后一个指针的NULL
不是内置于该语言中的内容。它必须明确设置。如果不这样做,则相当于声明一个char
数组,但不会使用NUL
来终止它:
char myString[] = { 'H', 'e', 'l', 'l', 'o' } // No NUL termination
就像你必须知道这个数组中有多少个字符,如果你想以任何有用的方式操作它,没有指针数组末尾的NULL
,操作它会更多难。
这就是Peter van der Linden在你引用的有关Illiffe数据结构的段落中所说的一切。
答案 3 :(得分:1)
C中没有要求任何局部变量应具有任何“默认”值。因此,当编译器保留两个(或三个)内存位置时,初始值是这些内存位置之前包含的内容 - 不会有任何默认初始化。
答案 4 :(得分:0)
除非你的数组是在文件范围(任何函数之外)或static
关键字声明的,否则数组内容不会被初始化;每个元素将包含一些可能或可能不对应于有效地址的随机位模式。
如果您的数组是在文件范围或static
关键字声明的,那么每个元素都会隐式初始化为NULL
。请注意,尝试取消引用NULL指针会导致未定义的行为,因此您需要在使用它之前检查指针是否为NULL。
空指针表示定义明确的“无处”,保证比较不等于任何有效的内存地址。请注意,有一个空指针常量 1 和一个空指针值 2 ,这两个不一定相同。在源代码中,宏NULL
设置为空指针常量。在翻译期间,源代码中NULL
的每个出现都将替换为真实的空指针值。
除了NULL之外还有无效的指针值;只是NULL是明确定义的并且在任何地方都是一样的。
<小时/> 1。指针上下文中使用的任何0值整数表达式。可以是裸
0
或(void *) 0
,也可以是评估为0的其他内容
2.平台用于表示空指针的值,该指针不必为0.