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

gcc 4.4.4 c89

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

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

char *name = "Joe bloggs"; 

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

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

非常感谢任何疑虑,

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

N固定宽度字符串是一个正好为N字符的字符串,其中保证所有N字符都被初始化。 如果要表示较短的字符串,则必须在末尾填充零字符。 您必须根据需要添加任意数量的零字符才能用完所有N字符。 请注意,如果您需要存储长度恰好为N的字符串,则固定宽度字符串的末尾不会包含零字符 。 即一般情况下固定宽度的字符串不是零终止!

这样做的目的是什么? 这样做的目的是在存储最大可能长度的字符串时保存1个字符。 如果使用宽度为N固定宽度字符串,则需要正好N字符来表示长度为N的字符串。 将其与普通的以零结尾的字符串进行比较,这需要N + 1字符(零终结符的额外字符)。

为什么最后用零填充? 它用零填充以简化固定宽度字符串的字典比较。 您只需比较所有N字符,直到找到差异。 注意,可以使用绝对任何字符来将固定宽度的字符串填充到全长。 只需确保您获得正确的词典排序。 使用零字符填充是一个不错的选择。

什么时候有用? 非常稀有。 固定宽度字符串提供的节省在通用字符串处理中很少重要:这些节省太小,只有在字符串使用全宽时才会出现。 但是它们可能会在某些特定情况下变得有用。

这一切都来自哪里? “固定宽度字符串”的典型示例是一些旧版Unix文件系统中的14字符宽文件名字段。 它由14个字符arrays表示,并使用固定宽度表示。 那时在全长(所有14个字符)文件名上保存1个字符很重要。

现在要strncpy 。 函数strncpy专门用于初始化该文件系统中的那些14个字符的宽文件名字段。 函数strncpy专门用于生成有效的固定宽度字符串:它将零终止字符串转换为固定宽度字符串。 不幸的是,它被赋予了一个误导性的名称,这就是为什么今天许多人误以为它为零终止字符串的“安全”复制function。 后者是对strncpy目的和function的完全错误的理解。

使用字符串文字来表示固定宽度的字符串(如在您的示例中)不是一个好主意,因为字符串文字总是在末尾添加零字符,而固定宽度字符串不一定这样做。 这就是如何在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... group中的函数自然实现。 例如, memcmp将实现比较。

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

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

请注意,在这种情况下, fw_string1仍然不是零终止。

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

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

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

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

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

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

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