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

C 固定宽度字符串和零终止字符串的差异,c,C,通用条款4.4.4 c89 我最近讨论了“固定宽度字符串”和“零终止字符串” 当我想到这个的时候。他们似乎是同一件事。以null结尾的字符串 i、 e 是无法更改的固定宽度字符串。并且还有一个终止null 在讨论中,我还被告知,strncpy永远不应该用于“以零结尾的字符串” 非常感谢您的建议,首先,我想您指的是固定长度的字符串,而不是固定长度的字符串 其次,上面的字符串是以null结尾的字符串。它不应该被更改,因为它是一个文本常量 AFAIK C没有任何真正的“固定长度字符串”。充其量,您可以

通用条款4.4.4 c89

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

当我想到这个的时候。他们似乎是同一件事。以null结尾的字符串

i、 e

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

在讨论中,我还被告知,strncpy永远不应该用于“以零结尾的字符串”


非常感谢您的建议,

首先,我想您指的是固定长度的字符串,而不是固定长度的字符串

其次,上面的字符串是以null结尾的字符串。它不应该被更改,因为它是一个文本常量

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

至于strncpy,它所做的是复制指定数量的字符,并将其余字符置零。这意味着,如果目标不够长,您可能正在写入超过可用空间的内容,或者字符串没有空终止符,从而导致在尝试使用字符串时出错。

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

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…
组的函数自然实现<例如,code>memcmp将实现比较

另外,实际上,考虑到caf的评论,在C语言中可以使用字符串文字来初始化固定宽度的字符串,因为C语言允许文字初始值设定项比数组长一个字符(即,在C语言中,如果终止零不适合数组,则可以)。因此,上述内容可以等效地重写为

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

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

我不太确定术语“固定宽度字符串”。取决于C函数字符串是否需要结尾\0。strlen和strcpy等函数需要处理\0终止的字符串,以便知道何时停止。像strncpy这样的函数不需要源字符串以\0结尾,因为一个参数告诉您要复制多少个字符

当您以声明名称的方式声明名称时,名称所指向的内容存储在只读内存中,不能进行修改,但可以进行修改
char fw_string1[7] = "This is";
char fw_string2[7] = "string";
char fw_string3[7] = "Hello";
char mycopy[32];
strcpy( mycopy, name );