gcc 4.4.4 c89
我最近讨论了"固定宽度字符串"和"零终止字符串".
当我想到这一点.他们似乎是一回事.带终止空值的字符串.
即
char *name = "Joe bloggs";
Run Code Online (Sandbox Code Playgroud)
是固定宽度的字符串,无法更改.并且还有一个终止空值.
同样在讨论中我被告知strncpy永远不应该用在'零终止字符串'上.
非常感谢任何疑虑,
术语"固定宽度字符串"通常指的是完全不同的东西.
固定宽度的字符串with N是一个完全N字符的字符串,其中所有N字符都保证初始化.如果要表示较短的字符串,则必须在末尾填充零字符.您必须根据需要添加任意数量的零字符才能用完所有N字符.请注意,如果您需要精确存储长度字符串N,则固定宽度字符串的末尾不会包含零字符.即一般情况下固定宽度的字符串不是零终止!
这样做的目的是什么?这样做的目的是在存储最大可能长度的字符串时保存1个字符.如果使用宽度为固定宽度的字符串N,则需要使用完全N字符来表示长度字符串N.将其与普通的以零结尾的字符串进行比较,这需要N + 1字符(零终结符的额外字符).
为什么最后用零填充?它用零填充以简化固定宽度字符串的字典比较.您只需比较所有N字符,直到找到差异为止.注意,可以使用绝对任何字符来将固定宽度的字符串填充到全长.只需确保您获得正确的词典排序.使用零字符填充是一个不错的选择.
什么时候有用?非常稀有.固定宽度字符串提供的节省在通用字符串处理中很少重要:这些节省太小,只有在字符串使用全宽时才会出现.但是它们可能会在某些特定情况下变得有用.
这一切从何而来?"固定宽度字符串"的典型示例是在一些旧版Unix文件系统中的14字符宽文件名字段.它由14个字符阵列表示,并使用固定宽度表示.那时在全长(所有14个字符)文件名上保存1个字符很重要.
现在来strncpy.功能strncpy是专门为在该文件系统中初始化那些14个字符宽的文件名字段而引入的.strncpy专门创建函数以生成有效的固定宽度字符串:它将零终止字符串转换为固定宽度字符串.不幸的是,它被赋予了一个误导性的名称,这就是为什么今天许多人误以为它为零终止字符串的"安全"复制功能的原因.后者是对strncpy目的和功能的完全错误的理解.
使用字符串文字来表示固定宽度的字符串(如在您的示例中)不是一个好主意,因为字符串文字总是在末尾添加零字符,而固定宽度字符串不一定这样做.这就是如何在C程序中初始化一堆固定宽度的字符串
char fw_string1[7] = { 'T', 'h', 'i', 's', ' ', 'i', 's' };
char fw_string2[7] = { 's', 't', 'r', 'i', 'n', 'g' };
char fw_string3[7] = { 'H', 'e', 'l', 'l', 'o' };
Run Code Online (Sandbox Code Playgroud)
所有数组都具有相同数量的元素 - 7.注意,第一个字符串不是以零结尾,而其余的是零填充.将"普通"字符串转换为固定宽度字符串将如下所示
char fw_string4[7];
strncpy(fw_string4, "Hi!", 7);
Run Code Online (Sandbox Code Playgroud)
在这种情况下,函数strncpy正好用于它的预期用途.
请记住,除了转换功能外strncpy,标准库几乎没有提供使用固定宽度字符串的方法.您基本上必须将它们视为原始字符数组,并手动实现任何更高级别的操作.大多数基本操作将由mem...组中的函数自然地实现.memcmp例如,将实施比较.
PS实际上,考虑到caf的注释,在C语言中,可以使用字符串文字来初始化固定宽度的字符串,因为C语言允许文字初始化器比数组长一个字符(即在C中它是正常的,如果终止为零不适合数组).因此,上述内容可以等同地重写为
char fw_string1[7] = "This is";
char fw_string2[7] = "string";
char fw_string3[7] = "Hello";
Run Code Online (Sandbox Code Playgroud)
请注意,fw_string1在这种情况下仍然不是零终止.