C语言sizeof与strlen详解

sizeof

sizeof 计算变量所占内存内存空间大小的,单位是字节,如果操作数是类型的话,计算的是使用类型创建的变量所占内存空间的大小。sizeof 只关注占用内存空间的大小,不在乎内存中存放什么数据 。

#include<stdio.h>
int main()
{
    int a = 0;
    printf("%zd\n", sizeof(a));
    printf("%zd\n", sizeof a);   //证明了sizeof不是函数
    printf("%zd\n", sizeof(int));
    return 0;
}

运行结果:

注意:sizeof()括号中的表达式不参与计算!

例如 


strlen 

 strlen 是C语言库函数,功能是求字符串长度。函数原型如下:

size_t strlen ( const char * str );

统计的是从 strlen 函数的参数 str 中这个地址开始向后, \0 之前字符串中字符的个数。 strlen 函数会一直向后找 \0 字符,直到找到为止,所以可能存在越界查找。

应用 :

#include<stdio.h>
#include<string.h>
int main()
{
    size_t len = strlen("abcdef");
    printf("%zd\n", len);
    return 0;
}
#include<stdio.h>
#include<string.h>
int main()
{
    const char* str = "abcdef";
    printf("%zd\n", strlen(str));
    return 0;
}
#include<stdio.h>
#include<string.h>
int main()
{
    char str[] = "abcdef";
    printf("%zd\n", strlen(str));
    return 0;
}

以上三种写法都可以正确求得字符串长度是6,但是有一种方式可能存在越界查找,输出结果是随机值,如:


sizeof和strlen的对比

sizeofstrlen

1. sizeof是操作符。

2. sizeof计算操作数所占内存的大小,单位是字节。

3. 不关注内存中存放什么数据。

4.sizeof()括号中的表达式不参与计算

1. strlen是库函数,使用需要包含头文件 string.h

2. srtlen是求字符串长度的,统计的是 \0 之前字符的个数

3.关注内存中是否有 \0 ,如果没有 \0 ,就会持续往后找,可能会越界。


 数组和指针题目解析

字符数组

代码1

#include<stdio.h>
int main()
{
    char arr[] = { 'a','b','c','d','e','f' };
    printf("%zd\n", sizeof(arr));        //数组名单独放在sizeof内部,计算的是整个数组的大小,6个字节
    printf("%zd\n", sizeof(arr + 0));    //arr是数组名表示数组首元素的地址,arr+0还是首元素的地址,地址的大小4/8个字节
    printf("%zd\n", sizeof(*arr));       //数组名表示数组首元素的地址,*arr表示首元素,大小就是1个字节
    printf("%zd\n", sizeof(arr[1]));     //arr[1]是第二个元素,大小是1个字节
    printf("%zd\n", sizeof(&arr));       //&arr是整个数组的地址,类型char(*)[6],地址的大小4/8个字节
    printf("%zd\n", sizeof(&arr + 1));   //&arr+1跳过整个数组,指向数组后边空间,地址大小4/8个字节
    printf("%zd\n", sizeof(&arr[0] + 1));//第二个元素的地址,地址的大小4/8个字节
    return 0;
}

代码2 

#include<stdio.h>
#include<string.h>
int main()
{
    char arr[] = { 'a','b','c','d','e','f' };
    printf("%zd\n", strlen(arr));        //arr是数组首元素的地址,数组中没有\0,导致越界访问,结果是随机的
    printf("%zd\n", strlen(arr + 0));    //arr+0是数组首元素的地址,数组中没有\0,导致越界访问,结果是随机的
    printf("%zd\n", strlen(*arr));       //arr是数组首元素的地址,*arr是首元素,即'a',ASCII为97,将97作为地址传给strlen,得到野指针,程序异常!
                                        
    printf("%zd\n", strlen(arr[1]));     //将98作为地址传给strlen,程序异常!
    printf("%zd\n", strlen(&arr));       //&arr是数组的地址,起始位置是数组的第一个元素的位置,随机值
    printf("%zd\n", strlen(&arr + 1));   //&arr+1跳过整个数组,随机值
    printf("%zd\n", strlen(&arr[0] + 1));//从第二个元素向后统计,随机值
    return 0;
}

代码3 

#include<stdio.h>
int main()
{
    char arr[] = "abcdef";  //a b c d e f \0
    printf("%d\n", sizeof(arr));        //数组名单独放在sizeof内部,计算数组总大小,7个字节
    printf("%d\n", sizeof(arr + 0));    //数组名表示数组首元素的地址,arr+0还是首元素的地址,地址的大小4/8个字节
    printf("%d\n", sizeof(*arr));       //数组名表示数组首元素的地址,*arr表示首元素,大小就是1个字节
    printf("%d\n", sizeof(arr[1]));     //arr[1]是第二个元素,大小是1个字节
    printf("%d\n", sizeof(&arr));       //&arr是整个数组的地址,地址的大小4/8个字节
    printf("%d\n", sizeof(&arr + 1));   //&arr+1跳过整个数组,指向数组后边空间,地址大小4/8个字节
    printf("%d\n", sizeof(&arr[0] + 1));//第二个元素的地址,地址的大小4/8个字节
    return 0;
}

代码4 

#include<stdio.h>
#include<string.h>
int main()
{
    char arr[] = "abcdef";              //a b c d e f \0
    printf("%d\n", strlen(arr));        //数组名是数组首元素的地址,从第一个元素向后统计,6
    printf("%d\n", strlen(arr + 0));    //arr+0还是首元素的地址,从第一个元素向后统计,6
    printf("%d\n", strlen(*arr));       //*arr是首元素,即'a',ASCII为97,将97作为地址传给strlen,程序异常!
    printf("%d\n", strlen(arr[1]));     //将98作为地址传给strlen,非法访问,程序异常!
    printf("%d\n", strlen(&arr));       //&arr是整个数组的地址,从第一个元素向后统计,6
                                        //会报错size_t strlen(const char*s);   &arr——char(*)[7] 类型不匹配
    printf("%d\n", strlen(&arr + 1));   //&arr+1跳过整个数组,随机值
    printf("%d\n", strlen(&arr[0] + 1));//从第二个元素向后统计,5
    return 0;
}

代码5 

#include<stdio.h>
int main()
{
    const char* p = "abcdef";         //a b c d e f \0
    printf("%d\n", sizeof(p));        //p是指针变量,指针变量大小4/8个字节
    printf("%d\n", sizeof(p + 1));    //p+1是b的地址,大小是4/8个字节
    printf("%d\n", sizeof(*p));       // *p就是'a',大小1个字节
    printf("%d\n", sizeof(p[0]));     //p[0]==*(p+0)==*p=='a' 大小1个字节
                                      //也可以把常量字符串想象成数组,p可以理解为数组名,p[0]就是首元素
    printf("%d\n", sizeof(&p));       //取出p变量的地址,仍是地址,大小为4/8个字节
    printf("%d\n", sizeof(&p + 1));   //取出p变量的地址+1,跳过p变量,但仍是地址,大小为4/8字节
    printf("%d\n", sizeof(&p[0] + 1));//&p[0] + 1==&*(p+0)+1==p+1,指向第二个元素,地址大小4/8字节
    return 0;
}

代码6 

#include<stdio.h>
#include<string.h>
int main()
{
    char* p = "abcdef";               //a b c d e f \0
    printf("%d\n", strlen(p));        //p存放的是字符a的地址,即从字符a的地址向后计数,长度为6
    printf("%d\n", strlen(p + 1));    //从字符b的地址向后计数,长度为5
    printf("%d\n", strlen(*p));       //*p就是'a',ASCII值为97,将97作为地址传给strlen,非法访问,程序异常!
    printf("%d\n", strlen(p[0]));     // p[0]=*(p+0)=*p='a',非法访问,程序异常!
    printf("%d\n", strlen(&p));       //&p取出的是p变量的地址,即以p变量的地址(16进制)向后计数,  随机值                                      
    printf("%d\n", strlen(&p + 1));   //&p取出的是p变量的地址,&p+1,跳过p变量,即从p变量之后的位置向后访问  随机值
    printf("%d\n", strlen(&p[0] + 1));//从第二个元素向后统计,5
    return 0;
}

二维数组 

代码1

#include<stdio.h>
#include<string.h>
int main()
{
    int a[3][4] = { 0 };
    printf("%d\n", sizeof(a));//数组名单独放在sizeof内部,计算数组总大小,12*4=48个字节
    printf("%d\n", sizeof(a[0][0]));//a[0][0]是第一行第一个元素,大小4个字节
    printf("%d\n", sizeof(a[0]));//a[0]是第一行的数组名,数组名单独放在sizeof内部,计算的是第一行元素的大小,16个字节
    printf("%d\n", sizeof(a[0] + 1));//a[0]是第一行的数组名,a[0]是数组首元素的地址,即第一行第一个元素的地址,+1跳过一个元素,是第一行第二个元素的地址,大小是4/8个字节
    printf("%d\n", sizeof(*(a[0] + 1)));//*(a[0] + 1))表示第一行第二个元素,大小是4个字节
    printf("%d\n", sizeof(a + 1));//a是二维数组的数组名,数组名表示数组首元素的地址,即第一行的地址,a+1跳过一行,即为第二行的地址,地址大小4/8个字节
    printf("%d\n", sizeof(*(a + 1)));//a+1是第二行的地址,*(a+1)就是第二行,计算的是第二行的大小,16个字节
             //*(a + 1)==a[1],a[1]是第二行的数组名,数组名单独放在sizeof内部,计算的是数组的大小,16个字节
    printf("%d\n", sizeof(&a[0] + 1));//a[0]是第一行的数组名,&a[0]取出的就是数组的地址,即第一行的地址,&a[0]+1就是第二行的地址,地址大小4/8个字节
    printf("%d\n", sizeof(*(&a[0] + 1)));//对第二行的地址解引用,访问的就是第二行,大小是16个字节
    printf("%d\n", sizeof(*a));  //a表示数组首元素的地址,是二维数组首元素的地址,即第一行的地址,*a就是第一行,计算的是第一行的大小,大小16个字节
    printf("%d\n", sizeof(a[3]));//a[3]无需真实存在,仅仅通过类型推断就能算出长度,是第四行的数组名,单独放在sizeof内部,计算第四行的大小,16个字节
    return 0;
}

数组名的意义

  • 1. sizeof(数组名),这里的数组名表示整个数组,计算的是整个数组的大小。
  • 2. &数组名,这里的数组名表示整个数组,取出的是整个数组的地址。
  • 3. 除此之外所有的数组名都表示首元素的地址。 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值