差异固定宽度字符串和零终止字符串

时间:2010-05-22 04:15:45

标签: c

gcc 4.4.4 c89

我最近讨论了“固定宽度字符串”和“零终止字符串”。

当我想到这一点。他们似乎是一回事。带有终止空值的字符串。

char *name = "Joe bloggs";

是固定宽度的字符串,无法更改。并且还有一个终止空值。

同样在讨论中我被告知strncpy永远不会用在'零终止字符串'上。

非常感谢任何疑虑,

3 个答案:

答案 0 :(得分:7)

术语“固定宽度字符串”通常指的是完全不同的东西。

带有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' };

所有数组都具有相同数量的元素 - 7.注意,第一个字符串不是以零结尾的,而其余的是零填充。将“普通”字符串转换为固定宽度字符串将如下所示

char fw_string4[7];

strncpy(fw_string4, "Hi!", 7);

在这种情况下,函数strncpy的用途正是它的用途。

请记住,除了转换函数strncpy之外,标准库几乎没有提供使用固定宽度字符串的方法。您基本上必须将它们视为原始字符数组,并手动实现任何更高级别的操作。大多数基本操作将由mem...组的功能自然地实现。例如,memcmp将实施比较。

P.S。实际上,考虑到caf的注释,在C语言中,可以使用字符串文字来初始化固定宽度的字符串,因为C语言允许文字初始化器比数组长一个字符(即在C中它是正常的,如果终止零的话不适合数组)。因此,上述内容可以等同地重写为

char fw_string1[7] = "This is";
char fw_string2[7] = "string";
char fw_string3[7] = "Hello";

请注意,fw_string1在这种情况下仍然不会以零结尾。

答案 1 :(得分:1)

首先,我认为你的意思是固定长度的字符串,不是用字符串固定的。

其次,上面是一个以空字符结尾的字符串。它不应该被改变,因为它被定义为文字常量。

AFAIK C没有任何真正的“固定长度字符串”。最好的情况是,你可以定义一个大小为N的缓冲区,并在其中放置不超过N-1个字符,其中放置更多将是一个错误,忘记空终止符可能是一个错误。

至于strncpy,它的作用是复制指定数量的字符,其余部分填零。这意味着如果目标不够长,您可能要写入可用空间,或者不会在字符串中使用空终止符,这会在您尝试使用该字符串时导致错误。

答案 2 :(得分:1)

我不太确定术语“修复宽度字符串”。根据C函数字符串需要或不需要结尾\ 0。像 strlen strcpy 这样的函数需要处理\ 0终止的字符串,以便知道何时停止。像 strncpy 这样的函数不需要源字符串为\ 0-终止,因为一个参数告诉要复制多少个字符。

当您声明名称时,指向的名称的内容存储在只读存储器中并且无法修改,但是您可以在不修改内容的C函数中使用“名称”,例如 strlen(name)或用作源时:

char mycopy[32];
strcpy( mycopy, name );