如果字符串中间出现空字符怎么办?

时间:2016-01-25 10:24:11

标签: c null sizeof strlen

我理解字符串的结尾由空字符表示,但我无法理解以下代码的输出。

#include <stdio.h>
#include <string.h>

int
main(void)
{
    char s[] = "Hello\0Hi";
    printf("%d %d", strlen(s), sizeof(s));
}

输出: 5 9

如果strlen()在o的末尾检测到字符串的结尾,那么为什么sizeof()不会做同样的事情呢?即使它没有做同样的事情,也不是'\ 0' A 空字符(即只有一个字符),所以答案不应该是8吗?

6 个答案:

答案 0 :(得分:17)

sizeof运算符不会给出字符串的长度,而是给出它的操作数类型的大小。由于在您的代码中操作数是一个数组,sizeof给出了数组的大小,包括null个字符。

如果是这样的话

const char *string = "This is a large text\0This is another string";
printf("%zu %zu\n", strlen(string), sizeof(string));

结果会有很大不同,因为string是指针而不是数组。

注意:使用"%zu"的{​​{1}}说明符,这是size_t返回的内容,是strlen()给出的值的类型。

答案 1 :(得分:8)

strlen()并不关心字符串的实际大小。它查找空字节,并在看到第一个空字节时停止。

sizeof()运算符知道总大小。它并不关心你在字符串文字中的字节数。您可能在字符串中包含所有空字节,而sizeof()仍然会给出正确的数组大小(在这种情况下strlen()会重新调整0

他们没有可比性;他们做了不同的事情。

答案 2 :(得分:4)

  

如果strlen()在o的末尾检测到字符串的结尾,那么为什么sizeof()不会做同样的事情呢?

strlen仅适用于字符串(字符数组),而sizeof适用于每种数据类型。 sizeof计算任何给定数据类型的确切内存空间;而strlen提供字符串的长度(不包括NULL终止符\0)。因此,在正常情况下,对于典型的字符数组s

也是如此
char s[] = "Hello";
strlen( s ) + 1  = sizeof( s ); // +1 for the \0

在你的情况下它是不同的,因为你在字符数组s的中间有一个NULL终结符:

char s[] = "Hello\0Hi";

此处,strlen会检测到第一个\0,并将长度设为5.但sizeof会计算足以容纳该字符的空格总数数组,包括两个\0 ,这就是为什么它将9作为第二个输出。

答案 3 :(得分:4)

strlen()计算字符串的长度。这是通过返回'\0'字符之前(不包括)字符的数量来完成的。 (参见下面的手册页。)

sizeof()返回给定变量(或数据类型)的字节数。请注意,您的示例"Hello\0Hi"有9个字符。但是你似乎不明白你的问题中字符9的来源。让我先解释给定的字符串。您的示例字符串是:

"Hello\0Hi"

这可以写成以下数组:

['H', 'e', 'l', 'l', 'o', '\0', 'H', 'i', '\0']

请注意最后一个'\0'字符。使用字符串引号时,编译器以'\0'字符结束字符串。这意味着""也是['\0'],因此有1个元素。

请注意 sizeof() NOT 返回数组中的元素数。它返回字节数。 char是1个字节,因此sizeof()确实返回元素的数量。但是如果您使用任何其他数据类型,例如,如果您在sizeof()上调用[1, 2, 3, 4],它将返回16.因为int是4个字节,并且数组有4个元素。

将数组作为参数传递的

BEWARE 只传递指针。如果您将s传递给另一个函数并调用sizeof(),它将返回指针的大小,这与sizeof(void *)相同。这是一个独立于数组的固定长度。

STRLEN(3)                BSD Library Functions Manual                STRLEN(3)

NAME
     strlen, strnlen -- find length of string

LIBRARY
     Standard C Library (libc, -lc)

SYNOPSIS
     #include <string.h>

     size_t
     strlen(const char *s);

     size_t
     strnlen(const char *s, size_t maxlen);

DESCRIPTION
     The strlen() function computes the length of the string s.  The strnlen()
     function attempts to compute the length of s, but never scans beyond the
     first maxlen bytes of s.

RETURN VALUES
     The strlen() function returns the number of characters that precede the
     terminating NUL character.  The strnlen() function returns either the
     same result as strlen() or maxlen, whichever is smaller.

SEE ALSO
     string(3), wcslen(3), wcswidth(3)

STANDARDS
     The strlen() function conforms to ISO/IEC 9899:1990 (``ISO C90'').
     The strnlen() function conforms to IEEE Std 1003.1-2008 (``POSIX.1'').

BSD                            February 28, 2009                           BSD

答案 4 :(得分:2)

由于名称 literal 本身意味着字符串文字是用双引号括起来的字符序列。隐含地,这个字符序列附加一个终止零。

因此,双引号中包含的任何字符都是字符串文字的一部分。

当字符串文字用于初始化字符数组时,其所有字符(包括终止零)都用作字符数组的相应元素的初始值。

每个字符串文字依次具有字符数组的类型。

例如,C中的这个字符串文字"Hello\0Hi"的类型为char[9]:引号中包含8个字符加上隐式终止零。

因此在内存中,此字符串文字存储为

{ 'H', 'e', 'l', 'l', 'o', '\0', 'H', 'i', '\0' }

运算符sizeof返回对象占用的字节数。因此,对于上面的字符串文字,运算符sizeof将返回值9 - 它是文本在内存中占用的字节数。

如果你写了"Hello\0Hi",那么编译器本身可能不会从文字中删除这部分Hi。它必须将它与引号括起来的文字的其他字符一起存储在内存中。

sizeof运算符返回C中任何对象的字节大小,而不仅仅是字符数组。

通常,字符数组可以存储任何原始数据,例如从二进制文件读取的一些二进制数据。在这种情况下,用户和程序不会将此数据视为字符串,因此处理的结果与字符串不同。

标准C函数strlen专门为字符数组编写,用于查找字符数组中存储字符串的长度。它不知道数组中存储了哪些数据以及它们是如何写入数组的。它所做的就是搜索字符数组中的第一个零字符,并在零字符之前返回字符数组中的字符数。

您可以按顺序在一个字符数组中存储多个字符串。例如

char s[12];

strcpy( s, "Hello" );
strcpy( s + sizeof( "Hello" ), "World" );

puts( s ); // outputs "Hello"
puts( s + sizeof( "Hello" ) ); // outputs "World"

如果要定义像这样的二维数组

char t[2][6] = { "Hello", "World" };

然后在内存中它将以与上面的一维数组相同的方式存储。所以你可以写

char *s = ( char * )t;

puts( s ); // outputs "Hello"
puts( s + sizeof( "Hello" ) ); // outputs "World"

另一个例子。标准C函数strtok可以将存储在字符数组中的一个字符串拆分为多个字符串,用零字节替换用户分隔符指定的字符串。结果,字符数组将包含几个字符串。

例如

char s[] = "Hello World";

printf( "%zu\n", sizeof( s ) ); // outputs 12

strtok( s, " " );

puts( s ); // outputs "Hello"
puts( s + sizeof( "Hello" ) ); // outputs "World"

printf( "%zu\n", sizeof( s ) ); // outputs 12

最后一个printf语句将输出相同的值等于12,因为该数组占用的字节数相同。分配给阵列的内存中只有一个字节从' '更改为'\0'

答案 5 :(得分:1)

C中的字符数组和字符数组的指针不是一回事。虽然您可以打印地址并获得相同的价值。 C中的数组由以下内容组成。

  1. 数组大小
  2. 其地址/指针
  3. 同质类型的元素
  4. 指针由以下组成:

    1. 地址
    2. 输入信息

      char s[] = "Hello\0Hi"; printf("%d %d", strlen(s), sizeof(s));

    3. 这里使用sizeof()计算数组的大小(s变量),为9。

      但是如果你将这个字符数组视为字符串而不是数组(现在是字符串),则会丢失其大小信息,并成为指向字符的指针。当您尝试使用%s打印字符数组时,会发生同样的事情。

      因此strlen()%s将字符数组视为字符串,它仅使用其地址信息。你可以猜测,strlen()继续递增指针以计算长度达到第一个空字符。当它遇到空字符时,你会得到一个长度到那一点。

      因此strlen()为您提供5而不计算null字符。

      所以sizeof()运算符只告诉其操作数的大小。如果给它数组变量而不是它使用数组大小​​信息并告诉大小而不管空字符位置。

      但是如果给sizeof() pointer to array of characters而不是找到没有大小信息的指针,则打印指针的大小,在64位系统上通常是64位/ 8字节,在32位系统上是32位/ 4字节。 / p>

      如果使用像"Hello"这样的双引号来初始化字符数组,那么还有一件事就是添加一个空字符,否则就不会出现{'H','e','l','l','o'}

      使用gcc编译器。希望它只会有助于理解。