无法在StackOverflow上找到解决此问题的任何问题。
我意识到char *数组不必以NULL结尾,但是想知道你什么时候想要它?
例如,在调试我的代码时,我使用了很多printf()来查看我的变量在代码的某个阶段是否正确。
我有一个char **值,它包含4个char *,我最后一个char * NULL。 在NULL终止时,从值[0]到值[3]的printfs给出了这个 注意:名称只是我在完成打印值数组
后立即打印的另一个数组Testing values1[0]: %HOME/bin:%PATH
Testing values1[1]: /%HOME/include
Testing values1[2]: /%HOME/lib
Testing values1[3]: (null)
Testing names2[0]: PATH
Testing names2[1]: IDIR
Testing names2[2]: LIBDIR
我有一个带有3个char *的char **,所有这些都是有效的char *。 没有NULL终止,printf从值[0]到值[3]给我这个(名字没有显示)
Testing values1[0]: %HOME/bin:%PATH
Testing values1[1]: /%HOME/include
Testing values1[2]: /%HOME/lib
我认为当printf(....,values [3])将是一个未定义的行为,比如打印垃圾值,但如上面的输出中所示,包括和之后的所有内容(...,值[3])似乎没有被执行。
答案 0 :(得分:4)
这里有很多混乱。首先:
'\0'
(有时称为“空字符”),表示字符串结束的位置。它与NULL指针无关。比“null终止”更好的名称可能是零终止,因为这样可以减少混淆。现在它发生了,0,NULL和'\0'
都给出零值,所以它们实际上可能用于错误的目的,代码仍然可以工作。但是,你应该做的是:
0
表示整数。NULL
作为指针。'\0'
终止characer数组,从而使其成为C字符串。下一个混乱的问题:
我有一个char **值,包含4个char *
指针不具有值。数组具有价值。指针不是数组,数组不是指针。指向指针不是数组,也不是2D数组。
虽然在某些情况下,您可以从数组中获取指向第一个元素的指针。
指向可变长度字符串的指针数组可以声明为:char* string_array [N];
。您可以使用指向指针来遍历此数组,但这不是一个好主意。更好的想法是使用数组索引:string_array[i]
。
总的来说,实际上很少需要使用指向指针的情况。通过函数参数返回指向已分配资源的指针是它们的正常用法。如果你发现自己在其他地方使用指针指针,那几乎就是程序设计糟糕的一个迹象。
例如,一种非常广泛但100%错误使用指针指针的特殊情况是在堆上动态分配2D数组时。
什么时候应该将char **终止?
从不。如上所述,这没有任何意义。您最有可能不会使用char**
开头。
但是,您可以使用NULL结束字符指针数组,以指示数组的结尾。这是常见的做法,但不要将此与字符串的零终止混淆。
示例:
const char* str_array [] =
{
"hello",
"world",
NULL
};
for(size_t i = 0; str_array[i] != NULL; i++)
{
puts(str_array[i]);
}
答案 1 :(得分:2)
我得到了TA的回答,作为回应“什么时候应该终止char?”我认为合理。如果还有其他原因可以解决这个问题,那将会很酷。
“这是一个很好的概念性问题,您可以将其视为类似于C字符串为空终止的原因。
假设您不想显式存储数组的长度(因为它是您管理和传递的额外数据等)。你怎么知道阵列的结束?最后的NULL充当了一个标记值,因此您可以简单地迭代它,直到达到魔术数组末尾值。
如果您有一个固定的数组大小或以其他方式存储它,则不需要NULL结尾。“
答案 2 :(得分:0)
根据C11
,章节§7.21.6.1,fprintf()
,%s
转换说明符
s
如果不存在l长度修饰符,则参数应为指向初始值的指针 字符数组的元素。
因此,您可能无法传递NULL
作为参数。它调用undefined behavior。你无法预测UB的行为。
您可以做的是,检查参数为!= NULL
然后传递变量。像
if (values[n])
puts(values[n]);
答案 3 :(得分:0)
每个字符串都需要以null结尾。简单的选择是使用null(即0或'\ 0')来设置整个数组。
或者,如果您不想null终止,那么您需要跟踪字符串的长度。
答案 4 :(得分:0)
在C99(& POSIX)中,必需 char*
终止的唯一NULL
数组是argv
main
的第二个参数main
1}}。因此,int main(int argc, char**argv);
函数被(或应该)声明为
argc
和(至少在POSIX系统上)它是必需的(并由运行时crt0强制执行),你应该期望:
argv
是积极的argc+1
是一个\0
指针数组,每个指针都是一个C字符串(以argv[argc]
字节结尾)NULL
必须是argv
指针 argv[
中的两个不同指针(即]
i argv[
和]
j {{1} } i 和 j 非负且小于argc+1
)不是pointer aliases(这是相同的指针值)当然,某些库也可能具有其参数可能具有类似要求的函数。这应该记录在案。