strlen和sizeof

39 篇文章 0 订阅
7 篇文章 0 订阅

定义

strlensizeof 是 C 语言中两个用于确定字符串或数据类型大小的常用操作符,但它们的工作方式和目的有所不同。下面是对这两个操作符的详细解释:

strlen

strlen 是一个库函数,定义在 <string.h> 头文件中。它用于计算以空字符(\0)结尾的字符串的长度。

函数原型

size_t strlen(const char *str);

参数

  • str:指向以空字符结尾的字符串的指针。

返回值

  • 返回字符串中字符的个数,不包括末尾的空字符。

示例

#include <stdio.h>  
#include <string.h>  
  
int main() {  
    char str[] = "Hello";  
    printf("Length of str: %zu\n", strlen(str)); // 输出:Length of str: 5  
    return 0;  
}

注意事项

  • strlen 只能用于以空字符结尾的字符串。如果传递给 strlen 的指针没有指向一个以空字符结尾的字符串,strlen 会继续读取内存,直到遇到空字符为止,这可能导致未定义行为(包括程序崩溃)。
  • strlen 的计算开销较大,因为它需要遍历整个字符串来查找空字符。因此,如果字符串的长度是已知的或者不会改变,使用 strlen 可能不是最高效的方法。

sizeof

sizeof 是一个编译器内置的操作符,用于确定变量或类型所占用的内存大小(以字节为单位)。

语法

size_t sizeof(object);  
size_t sizeof(type);

参数

  • object:可以是变量、数组、结构体等。
  • type:可以是数据类型(如 int, float, char 等)。

返回值

  • 返回对象或类型所占用的内存大小(以字节为单位)。

示例

#include <stdio.h>  
  
int main() {  
    char c = 'A';  
    int i = 42;  
    double d = 3.14;  
    char str[] = "Hello";  
  
    printf("Size of char: %zu bytes\n", sizeof(c));       // 输出:Size of char: 1 byte  
    printf("Size of int: %zu bytes\n", sizeof(i));        // 输出可能是:Size of int: 4 bytes(取决于平台)  
    printf("Size of double: %zu bytes\n", sizeof(d));     // 输出可能是:Size of double: 8 bytes(取决于平台)  
    printf("Size of str: %zu bytes\n", sizeof(str));      // 输出:Size of str: 6 bytes(包括末尾的空字符)  
    printf("Size of pointer: %zu bytes\n", sizeof(&c));   // 输出指针的大小,通常是 4 或 8 字节(取决于平台)  
    return 0;  
}

注意事项

  • sizeof 在编译时就能确定结果,因此它是一个常量表达式。
  • sizeof 计算的是对象或类型在内存中的大小,而不是它存储的值的数量。例如,对于数组 strsizeof(str) 返回的是整个数组(包括末尾的空字符)所占用的字节数,而不是字符串的长度。
  • sizeof 可以用于任何数据类型和对象,包括基本类型、结构体、联合、数组和指针等。

总结来说,strlen 用于计算字符串的长度(不包括末尾的空字符),而 sizeof 用于确定变量或类型在内存中的大小(以字节为单位)。在处理字符串时,如果你想知道字符串包含多少个字符,应该使用 strlen;如果你想知道存储字符串的数组或变量需要多少内存,应该使用 sizeof

详细示例及结论

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main()
{
    char name[24]="haha ";
    int iLen = strlen(name);
    printf("strlen name has " " = %d\n",iLen);
    iLen = sizeof(name);
    printf("sizeof name has " "  = %d\n",iLen);
// strlen name has  = 5
// sizeof name has   = 24
//结论 空格占用一个字符

    char name1[24]="haha";
    iLen = strlen(name1);
    printf("strlen name  = %d\n",iLen);
    iLen = sizeof(name1);
    printf("sizeof name  = %d\n",iLen);
// strlen name  = 4 
// sizeof name  = 24

    char name2[24]="haha\n";
    iLen = strlen(name2);
    printf("strlen name has \\n = %d\n",iLen);
    iLen = sizeof(name2);
    printf("sizeof name has \\n = %d\n",iLen);
// strlen name has \n = 5
// sizeof name has \n = 24
//结论 换行符占用一个字符
    char name3[24]="haha\0";
    iLen = strlen(name3);
    printf("strlen name has \\0 = %d\n",iLen);
    iLen = sizeof(name3);
    printf("sizeof name has \\0  = %d\n",iLen);
// strlen name has \0 = 4
// sizeof name has \0  = 24
//结论 结束符不占用字符
    char name4[24]="";
    iLen = strlen(name4);
    printf("strlen name has no member = %d\n",iLen);
    iLen = sizeof(name4);
    printf("sizeof name has no member  = %d\n",iLen);

// strlen name has no member = 0
// sizeof name has no member  = 24


    char name5[24]="haha\\n";
    iLen = strlen(name5);
    printf("strlen name has \\n = %d\n",iLen);
    iLen = sizeof(name5);
    printf("sizeof name has \\n = %d\n",iLen);
//     strlen name has \n = 6
// sizeof name has \n = 24
    return 0;
}

编译运行结果

常见问题

每一个字符串默认自带什么字符

在C语言中,每一个字符串默认自带一个结束字符,即空字符(null character),用 \0 表示。这个空字符用于标识字符串的结束位置。因此,当你定义一个字符串时,编译器会自动在字符串的末尾添加一个 \0 字符。例如,当你写下以下代码:

char str[] = "Hello";

实际上,在内存中,str 数组的内容会是:

H e l l o \0

这里,\0 就是字符串的结束符,它告诉 strlen 和其他字符串处理函数在哪里停止读取字符串。这个特性使得C语言的字符串函数能够正确地处理变长字符串,而不需要提前知道字符串的确切长度。

stren 字符串长度 不包含结束符吧

是的,strlen 函数计算字符串的长度时,是不包含末尾的空字符(null character,即 \0)的。strlen 函数返回的是从字符串开始到第一个空字符之前的字符数,即实际存储的可见字符的数量。因此,如果你有一个字符串 "Hello"strlen 函数会返回 5,因为字符串包含五个字符 'H', 'e', 'l', 'l', 'o',而不包括末尾的 \0

这个特性是设计 strlen 函数时有意为之的,因为空字符在C语言中被用作字符串的结束标志,而不是字符串内容的一部分。因此,在计算字符串长度时,空字符不被计入长度内。这样,strlen 和其他字符串处理函数就能够正确地处理字符串,直到遇到结束标志为止。

字符串拷贝 目的字符串的长度是不是要比strlen计算的拷贝的字符串长度加1

是的,当进行字符串拷贝操作时,目的字符串(即目标缓冲区)的长度应该至少要比源字符串的长度(通过 strlen 计算得出)多 1。这是因为 strlen 函数返回的是源字符串中字符的数量,不包括末尾的空字符(null terminator, \0)。在拷贝字符串时,你需要确保目的字符串有足够的空间来容纳源字符串的所有字符,以及额外的空字符作为结束符。

例如,如果你有一个源字符串 "Hello",它的长度是 5(通过 strlen 计算得出)。当你拷贝这个字符串到另一个缓冲区时,你需要一个至少长度为 6 的缓冲区来确保能够存储所有的字符以及末尾的空字符。

char src[] = "Hello";  
char dest[6]; // 长度至少为 strlen(src) + 1  
  
strcpy(dest, src); // 拷贝字符串,包括末尾的空字符

在上面的代码中,dest 数组的长度是 6,这足够存储源字符串 "Hello" 的 5 个字符以及一个空字符。使用 strcpy 函数进行拷贝时,它会将源字符串的所有字符(包括末尾的空字符)复制到目的字符串中。

注意,如果目的字符串的长度小于源字符串的长度加一,就会发生缓冲区溢出(buffer overflow),这是一种常见的安全漏洞,可能导致程序崩溃或更严重的安全问题。因此,在进行字符串拷贝操作时,务必确保目的字符串有足够的空间。

不加1 会有什么影响 举例说明

如果在进行字符串拷贝操作时,目的字符串(即目标缓冲区)的长度没有比源字符串的长度多 1,即没有为末尾的空字符(null terminator, \0)预留空间,那么将会发生缓冲区溢出(buffer overflow)。这会导致一系列的问题,包括但不限于:

  1. 数据损坏:拷贝操作会覆盖目的字符串缓冲区末尾之后的内存区域,可能损坏该区域存储的其他重要数据。

  2. 程序崩溃:如果溢出的数据破坏了程序的执行状态(比如函数返回地址),程序可能会立即崩溃。

  3. 安全漏洞:攻击者可以利用缓冲区溢出漏洞执行恶意代码,获取系统的敏感信息或控制权限。

下面是一个具体的例子来说明不加 1 会产生的影响:

#include <stdio.h>  
#include <string.h>  
  
int main() {  
    char src[] = "Hello";  
    char dest[5]; // 长度没有比 strlen(src) + 1 大  
  
    strcpy(dest, src); // 拷贝字符串,但没有足够的空间容纳空字符  
  
    printf("dest: %s\n", dest); // 尝试打印 dest,但可能会崩溃或输出错误内容  
  
    return 0;  
}

在这个例子中,dest 数组的长度是 5,与 src 字符串的可见字符数相等,但没有额外的空间来存储末尾的空字符。当使用 strcpy 函数进行拷贝时,它会尝试将 src 中的所有字符(包括末尾的空字符)复制到 dest 中。由于 dest 没有足够的空间,最后一个空字符会被写入 dest 数组之后的内存区域,这可能会导致未定义的行为。

在实际执行时,程序可能会崩溃,或者如果 dest 数组后面恰好有其他变量的内存,那么这些变量的值可能会被意外地修改。此外,如果 dest 数组后面是程序的栈空间,并且溢出的数据覆盖了函数的返回地址,那么程序可能会跳转到错误的地址执行,导致更严重的后果。

为了避免这种情况,总是要确保目的字符串的长度至少比源字符串的长度多 1,以便有足够的空间来存储空字符。在实践中,使用像 strncpy 这样的安全字符串拷贝函数也是一个好的做法,因为它们允许你指定一个最大拷贝长度,从而防止缓冲区溢出。

  • 9
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值