C什么时候应该char为null终止?

时间:2016-02-11 05:56:11

标签: c arrays pointers char printf

无法在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])似乎没有被执行。

5 个答案:

答案 0 :(得分:4)

这里有很多混乱。首先:

  • NULL指的是一个空指针常量,它仅用于将指针设置为指向“无”,即无效的内存位置。
  • 空终止,有时拼写为“nul”,以免与上述内容混淆,意味着在字符数组的末尾加上一个零字符'\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(这是相同的指针值)

当然,某些库也可能具有其参数可能具有类似要求的函数。这应该记录在案。