通过程序解读sizeof

<pre name="code" class="cpp">#include <iostream>
#include <string>

using namespace std;

void foo3(char *c1)
{
    int c3 = sizeof( c1 ); // c3 ==
    cout<< c3 << endl;
}
void foo4(int *c2)
{
    int c4 = sizeof( c2 ); // c4 ==
    cout<< c4 << endl;
}

//字节对齐的细节和编译器实现相关,但一般而言,满足三个准则:
//1) 结构体变量的首地址能够被其最宽基本类型成员的大小所整除;
//2) 结构体每个成员相对于结构体首地址的偏移量(offset)都是成员大小的整数倍,如有需要编译器会在成员之间加上填充字节;
//3) 结构体的总大小为结构体最宽基本(内置)类型成员大小的整数倍,如有需要编译器会在最末一个成员之后加上填充字节.
struct student
{
    int num; // 占4个字节
    char name[20]; // 占20个字节
    char sex; // 占4个字节(结构体为每个成员分配空间时,根据最宽基本类型成员大小的整数倍进行分配,这里指的是int/float)
    double age; // 占4字节
    float score; // 占4字节
    char addr[30]; // 占32字节(分配的空间必须为最宽基本类型成员大小的整数倍)
};

struct S1
{
    char a; // 4字节
    int i; // 4字节
};

// 嵌套的结构体
struct S2
{
    char a; // 4字节
    int i; // 4字节
    student t; // 占68字节,最宽基本类型成员为int/float型,4字节(注意,这里最大成员不是t,因为它不属于内置类型;具体计算S2时,student要按S2中的最近倍数来算)
};

// 空结构体
struct S3{};

// 共用体成员共用一个空间,所以其为最宽基本类型成员的大小
union U
{
    int i;
    char a;
};

int main()
{
    /* 1.
    int count=0; int m=779;
    while(m)
    {
        count++; m=m&(m-1);
    }
    //printf("%d\n",count);
    cout<< count << endl;
    return 0;
    */

    // sizeof的用法
    //(1)数组1
    int p1[10];
    int *p2[10];
    int (*p3)[10];


    cout<< "int p1[10]       sizeof(p1):" << sizeof(p1) << endl;
    cout<< "int *p2[10]      sizeof(p2):" << sizeof(p2) << endl;
    cout<< "int (*p3)[10]    sizeof(p3):" << sizeof(p3) << endl;
    cout<< "----------------------------"<< endl;

    //(2)内置类型
    char a1;
    int a2;
    float a3;
    double a4;
    long a5;
    long double a6;
    string a7;
    string a8="abc"; // string类型变量本质上属于指针

    cout<< "char:            " << sizeof(a1) << endl;
    cout<< "int:             " << sizeof(a2) << endl;
    cout<< "float:           " << sizeof(a3) << endl;
    cout<< "double:          " << sizeof(a4) << endl;
    cout<< "long:            " << sizeof(a5) << endl;
    cout<< "long double:     " << sizeof(a6) << endl;
    cout<< "string:          " << sizeof(a7) << endl;
    cout<< "string a8=\"abc\": " << sizeof(a8) << endl;
    cout<< "----------------------------"<< endl;


    //(3)指针:所有的指针(包括结构体)均占4字节(一个int型大小)。
    char *b1;
    int *b2;
    float *b3;
    double *b4;
    long *b5;
    long double *b6;

    cout<< "char*:       " << sizeof(b1) << endl;
    cout<< "int*:        " << sizeof(b2) << endl;
    cout<< "float*:      " << sizeof(b3) << endl;
    cout<< "double*:     " << sizeof(b4) << endl;
    cout<< "long*:       " << sizeof(b5) << endl;
    cout<< "long double*:" << sizeof(b6) << endl;
    cout<< "----------------------------"<< endl;

    //(4)数组2
    char c1[]="abcd";
    int c2[4];

    cout<< "char c1[]=\"abcd\":  " << sizeof(c1) << endl;
    cout<< "int c2[4]:        " << sizeof(c2) << endl;

    //数组名做形参:本质就是指针
    cout<< "foo3(char *c1):   ";
    foo3(c1);
    cout<< "foo3(int *c2):    ";
    foo4(c2);
    cout<< "----------------------------"<< endl;

    // (5)结构体
    S1 s1;
    S1 *s2;
    S2 s3;
    S3 s4;
    student student1;
    student *student2;

    cout<< "S1 s1:             " << sizeof(s1) << endl;
    cout<< "S1 *s2:            " << sizeof(s2) << endl;
    cout<< "student student1:  " << sizeof(student1) << endl;
    cout<< "student *student2: " << sizeof(student2) << endl;
    cout<< "S2 s3:             " << sizeof(s3) << endl;
    cout<< "S3 s4:             " << sizeof(s4) << endl;
    cout<< "----------------------------"<< endl;

    // 共用体
    U u;
    cout<< "U u:               " << sizeof(u) << endl;

	system("pause");

    return 0;
}

<div id="art_demo">本篇文章小编并不是为大家讲解string类型的用法,而是讲解我个人比较好奇的问题,就是string 类型占几个字节</div><p>在C语言中我们操作字符串肯定用到的是指针或者数组,这样相对来说对字符串的处理还是比较麻烦的,好在C++中提供了 string 类型的支持,让我们在处理字符串时方便了许多。</p><p><strong><span style="COLOR: #ff0000">首先,我写了一段测试代码,如下所示:
</span></strong></p><pre name="code" class="cpp">#include <iostream>
using namespace std;
int main(void)
{
 string str_test1;
 string str_test2 = "Hello World";
 int value1, value2, value3;
 value1 = sizeof(str_test1);
 value2 = sizeof(str_test2);
 value3 = sizeof(string);
 cout<<"str_test1占 "<<value1<<" 个字节"<<endl;
 cout<<"str_test2占 "<<value2<<" 个字节"<<endl;
 cout<<"string占 "<<value3<<" 个字节"<<endl;
 system("pause");
 return 0;
}
首先,我用G++编译运行,得到的结果如下图所示:

结果都是4字节;
<p>这说明string占4个字节。
之后,我用VS2012编译运行,得到的结果如下图所示:
结果都是28字节。</p><p>奇怪,这里string竟然占28个字节。
这里,我们注意观察,还会发现一个问题,不管有没有对string类型的变量赋值,或者是赋什么值,得到的结果是一样的。</p><p><strong>下面,来解释上述问题:
</strong>string的实现在各库中可能有所不同,但是在同一库中相同一点是,无论你的string里放多长的字符串,它的sizeof()都是固定的,字符串所占的空间是从堆中动态分配的,与sizeof()无关。    sizeof(string)=4可能是最典型的实现之一,不过也有sizeof()为12、32字节的库实现。通常,我们所用到的 string 类型一般都会是这样实现:
</p><p><pre name="code" class="cpp">class{      
char *_Ptr;    //指向字符串的指针      
int _Len;      //字符串的长度      
........};



所以,我们一般接触到的string类型所占字节数为 8+。






                
<think> 首先,用户的问题是:“我想了解strlen和sizeof在大小方面的差异及相关知识 请问strlen和sizeof在大小计算上的区别”。这直接针对strlen和sizeof函数在计算大小上的区别。 根据系统级指令: - 所有行内数学表达式必须使用$...$格式。 - 独立公式使用$$...$$格式并单独成段。 - 使用中文回答。 - 生成相关问题。 - 回答中引用的段落末尾自然地添加引用标识,例如[^1]。 用户提供了多个引用: - 引用[1]:强调strlen和sizeof的区别,并提到这篇博客会透彻解释。 - 引用[2]:总结四点区别:sizeof是运算符,strlen是库函数;sizeof编译时计算,strlen运行时;sizeof计算对象最大字节数,strlen计算字符串实际长度;sizeof参数多样化,strlen必须是字符指针。 - 引用[3]:提供详细区别和测试代码,包括sizeof结果类型是size_t等等。 - 引用[4]:讨论在特定字符串上的计算差异。 用户要求尽可能多地参考上一次的问题和我的回答。但在这个对话中,这是第一条消息,所以没有之前的上下文。我需要基于提供的引用回答。 关键点总结: - **sizeof**:是运算符,编译时计算大小。它返回对象或类型在内存中所占的字节数。参数可以是类型、变量、数组等。 - **strlen**:是函数,运行时计算以空字符'\0'结尾的字符串的长度(不算结束符)。参数必须是字符指针(指向字符串)。 在大小计算上的区别: - sizeof计算的是整个对象的字节大小,包括数组的所有元素,无论内容如何。 - strlen计算的是字符串的实际长度,即从开始到第一个'\0'之前的字符数(不包括'\0')。 例如,从引用[3]的测试代码: - 对于`char *str1 = "abcdef";`:sizeof(str1)返回指针的大小(如4或8字节),strlen(str1)返回6(字符串长度)。 - 对于`char str2[] = "abcdef";`:sizeof(str2)返回7(包括结尾的'\0'),strlen(str2)返回6。 - 对于`char str3[8] = {'a', 'b', 'c'};`:sizeof(str3)返回8(数组大小),strlen(str3)可能不确定,因为没有'\0',所以是未定义行为。 - 对于`char str4[] = "ab\0cd";`:sizeof(str4)返回5(包括两个'\0'),strlen(str4)返回2(遇到第一个'\0'就停止)。 引用[4]的例子:`char x[] = "12345\r\n\0";`:sizeof(x)包括所有字符和结束符,strlen(x)只计算到第一个'\0'。 回答结构: - 使用中文。 - 清晰地逐步解释。 - 包括数学表达式:例如,sizeof返回字节数,可以用$ \text{sizeof}(object) $表示。 - 生成相关问题。 大纲: 1. **介绍**:简要说明strlen和sizeof是什么。 2. **本质区别**: - sizeof是运算符,编译时确定。 - strlen是函数,运行时计算。 3. **大小计算差异**: - sizeof的对象:整体大小,包括所有元素和填充。 - strlen的对象:C字符串的实际字符数(不含'\0')。 4. **参数差异**: - sizeof的参数可以是类型、变量、数组等。 - strlen的参数必须是char*指针,指向以'\0'结尾的字符串。 5. **示例**:用引用中的例子说明。 6. **结论**:总结关键区别。 7. **相关问题**:生成3-5个相关问题。 确保回答真实可靠:基于C/C++标准。 数学表达式: - 行内:如$ \text{sizeof}(\text{int}) = 4 $(假设在32位系统)。 - 独立公式:如果需要公式,单独成段。 引用标识:在解释时,自然地添加[^1], [^2]等,基于提供的引用索引。 相关问题: - 例如: 1. 为什么strlen遇到'\0'就停止计算长度? 2. sizeof如何计算结构体的大小? 3. 何时使用strlen vs sizeof? 4. strlen的安全性问题和替代方案? 最终回答: - 结构清晰。 - 帮助用户逐步理解。 </think> ### strlen和sizeof在大小计算上的区别 在C/C++编程中,`strlen`和`sizeof`都用于“大小”的计算,但它们在本质、计算方式和结果上有显著区别。以下我将基于核心差异逐步解释,确保内容清晰可靠(参考了提供的引用资料)。关键点在于:**`sizeof`计算对象在内存中的总字节大小(编译时完成),而`strlen`计算字符串的实际字符长度(运行时完成,以空字符`'\0'`为结束标志)**。 #### 1. **本质区别** - **`sizeof`**:这是一个**运算符(operator)**,在编译时就确定了结果。它返回对象或类型所占内存的字节总数,包括所有元素、填充字节和结束符。参数可以是任何类型(如数组、指针、结构体等)。例如: - `sizeof(int)` 在32位系统上返回 $4$(字节),因为`int`类型固定占4字节。 - 引用[2]指出:`sizeof()`在编译时计算,参数多样化(数组、指针、函数等)[^2]。 - **`strlen`**:这是一个**库函数(function)**,需要运行时执行。它计算以`'\0'`结尾的字符串的实际字符数(不包括结束符`'\0'`)。参数必须是`char*`类型的指针或数组名(数组名会退化为指针)。例如: - `strlen("abc")` 返回 $3$,因为有三个可见字符。 - 引用[3]强调:`strlen()`运行时计算,参数必须是字符指针,且依赖`'\0'`作为结束标志[^3]。 #### 2. **大小计算差异** `sizeof` 和 `strlen` 在“大小”输出的含义不同: - **`sizeof` 计算内存总大小**: - 针对数组时,返回整个数组的字节大小(包括结尾的`'\0'`)。 - 针对指针时,返回指针本身的大小(通常4或8字节,取决于系统)。 - 公式:$ \text{sizeof}(object) = \text{对象在内存中的总字节数} $。 - 示例:假设 `char str[] = "hello";`: - `sizeof(str)` 返回 $6$(包括5个字符 + 1个隐含的`'\0'`)。 - **`strlen` 计算字符串有效长度**: - 只计算从起始位置到第一个`'\0'`之前的字符数(忽略`'\0'`)。 - 公式:$ \text{strlen}(ptr) = \text{从ptr开始到第一个}\texttt{'\0'}\text{的字符数量} $。 - 示例:同上 `char str[] = "hello";`: - `strlen(str)` 返回 $5$(只有5个可见字符)。 - 如果字符串中嵌入了`'\0'`,`strlen`会提前停止(引用[3]测试代码中的`str4`案例)[^3]。 #### 3. **关键对比表** | 特性 | `sizeof` | `strlen` | |------|----------|----------| | 类型 | 运算符 | 函数 | | 计算时机 | 编译时 | 运行时 | | 参数类型 | 任意(类型、变量、数组等) | 必须是`char*`(指向字符串) | | 结果依据 | 对象内存布局(包括填充字节) | 字符串内容(依赖`'\0'`结束符) | | 安全性 | 始终安全(编译时已知) | 不安全(如果字符串无`'\0'`,可能导致未定义行为) | | 返回类型 | `size_t`(通常 `unsigned int`) | `size_t` | #### 4. **示例代码分析** 参考引用[3]的测试代码(稍作简化): ```c #include <stdio.h> #include <string.h> int main() { char *str1 = "abcdef"; // 字符串字面量,隐含'\0' char str2[] = "abcdef"; // 数组初始化,隐含'\0' char str3[8] = {'a', 'b', 'c'}; // 数组部分初始化,无显式'\0' char str4[] = "ab\0cd"; // 字符串中有嵌入'\0' printf("sizeof(str1) = %zu\n", sizeof(str1)); // 输出指针大小(如8字节) printf("strlen(str1) = %zu\n", strlen(str1)); // 输出6(字符串长度) printf("sizeof(str2) = %zu\n", sizeof(str2)); // 输出7(包括隐含'\0') printf("strlen(str2) = %zu\n", strlen(str2)); // 输出6 printf("sizeof(str3) = %zu\n", sizeof(str3)); // 输出8(数组总大小) printf("strlen(str3) = %zu\n", strlen(str3)); // 未定义行为(可能输出3或崩溃) printf("sizeof(str4) = %zu\n", sizeof(str4)); // 输出5(包括两个'\0') printf("strlen(str4) = %zu\n", strlen(str4)); // 输出2(停在第一个'\0') return 0; } ``` - **解读**: - `str1`:`sizeof` 返回指针大小(8字节在64位系统),`strlen` 返回6。 - `str2`:`sizeof` 返回7(6字符 + 1`'\0'`),`strlen` 返回6。 - `str3`:`sizeof` 返回8(数组大小),`strlen` 不可靠(因数组未以`'\0'`结束)。 - `str4`:`sizeof` 返回5(`a`,`b`,`\0`,`c`,`d` + 隐含`'\0'`),`strlen` 返回2(遇到`'\0'`停止)。 - 引用[4]的案例 `char x[] = "12345\r\n\0";` 中:`sizeof(x)` 返回字节总数(包括所有字符和结束符),`strlen(x)` 返回字符串长度(忽略`'\0'`)[^4]。 #### 5. **常见误区与注意事项** - **数组 vs 指针**:当参数是数组名时,`sizeof` 返回数组总大小,但如果是数组名作为函数参数(退化为指针),`sizeof` 返回指针大小(引用[2]强调此点)[^2]。 - **字符串中的'\0'**:`strlen` 以第一个`'\0'`为结束标志,而`sizeof` 计入所有字节(包括嵌入的`'\0'`)。 - **安全性**:`strlen` 在缺少`'\0'`时行为未定义(如`str3`),可能导致程序崩溃;`sizeof` 始终安全。 - 性能:`sizeof` 在编译时完成,无运行时开销;`strlen` 需遍历字符串,时间复杂度为 $O(n)$($n$ 为字符串长度)。 #### 6. **总结** - **何时用 `sizeof`**:当需要对象或类型的总内存大小时(如数组大小、结构体对齐)。 - **何时用 `strlen`**:当需要字符串的实际字符长度时(如处理用户输入文本)。 - 核心差异:`sizeof` 关注内存占用(编译时),`strlen` 关注字符串内容(运行时)。记住:`sizeof` 是“看容器”,`strlen` 是“数内容”[^1][^2][^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值