差异固定宽度字符串和零终止字符串
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。 像strlen和strcpy这样的函数需要处理\ 0终止的字符串才能知道何时停止。 像strncpy这样的函数不需要源字符串为\ 0-终止,因为一个参数告诉要复制多少个字符。
当您声明名称时,指向的名称的内容存储在只读存储器中并且无法修改,但是您可以在不修改内容的C函数中使用“名称”,例如strlen(名称)或使用时作为来源:
char mycopy[32]; strcpy( mycopy, name );