详解sizeof()和strlen()的细节及用法

sizeof和strlen的对比

  1. sizeof() 计算变量所占内存内存空间大小的,单位是字节,如果操作数是类型的话,计算的是使用类型创建的变量所占内存空间的大小
    sizeof ()只关注占⽤内存空间的大小,不在乎内存中存放什么数据
  2. strlen()是C语言库函数,功能是求字符串长度。 函数原型:
  size_t strlen ( const char * str );

统计的是从 strlen()函数的参数 str 中这个地址开始向后, \0 之前字符串中字符的个数。strlen()函数会⼀直向后找\0 字符,直到找到为止,所以可能存在越界查找。
那我们思考一下如果我们传一个字符给strlen()会怎么样?详细请看下面求strlen(*arr),这时我们会讲到实际案例!!!
那我们再思考一下如果我们传一个数组地址给strlen()会怎么样?详细请看下面求strlen(&arr),这时我们会讲到实际案例!!!在这里插入图片描述
在开始下面的介绍前还有一点非常重要,数组名的意义:
3. sizeof(数组名),这里的数组名表示整个数组,计算的是整个数组的大小
4. &数组名,这里的数组名表示整个数组,取出的是整个数组的地址
5. 除此之外所有的数组名都表示首元素的地址

计算一维数组

整形数组

    int a[] = {
    
    1,2,3,4};
    printf("%d\n",sizeof(a));
    printf("%d\n",sizeof(a+0));
    printf("%d\n",sizeof(*a));
    printf("%d\n",sizeof(a+1));
    printf("%d\n",sizeof(a[1]));
    printf("%d\n",sizeof(&a));
    printf("%d\n",sizeof(*&a));
    printf("%d\n",sizeof(&a+1));
    printf("%d\n",sizeof(&a[0]));
    printf("%d\n",sizeof(&a[0]+1));

我们先看一下输出的结果:
在这里插入图片描述
1.sizeof(a);//sizeof(数组名) 计算的是数组的总大小-=单位字节–16
2.sizeof(a+0);//肯定有人想问上一个还是16字节,怎么这儿就变成8了?其实这里a+0是一个表达式,并不满足sizeof(数组名)形式,所以这里a还是首元素地址,a+0还为首元素地址,地址大小都为4 / 8字节
3.sizeof(*a);//这里a是首元素地址,所以*a就是首元素的类型(int)的大小,即为4
4.sizeof(a+1);//这里a为首元素地址,则a+1就是第二个元素地址,类比于2.,为4 / 8字节
5.sizeof(a[1]);//第二个元素大小,4
6.sizeof(&a);//&a取出的是数组的地址,是地址都是4 / 8
7.sizeof(*&a);//&a是数组a的地址,*解引用后则就是数组a,此处计算的还是数组的大小,16字节
8…sizeof(&a+1);//根据上面我们不难想到,此处&a+1相当于&a跳过了一个数组,但还是一个地址,为4 / 8字节
9…sizeof(&a[0]);//首元素地址,4 / 8字节
10…sizeof(&a[0]+1);//第二个元素的地址,4 / 8字节

字符数组

字符数组与整形数组的sizeof()用法极其相似,这里就不多介绍了!

    char arr[] = {
    
     'a','b','c','d','e','f' };
    printf("%d\n", strlen(arr));
    printf("%d\n", strlen(arr+0));
    printf("%d\n", strlen(*arr));
    printf("%d\n", strlen(arr[1]));
    printf("%d\n", strlen(&arr));
    printf("%d\n", strlen(&arr+1));
    printf("%d\n", strlen(&arr[0]+1));

运行结果:
在这里插入图片描述
1.strlen(arr);
2.strlen(arr+0);

我们可以看出这个字符数组并没有以'\0'结尾,所以strlen()计算首元素地址时,就产生了随机值!所以第一个和第二个是随机值!
3.strlen(*arr);
4. strlen(arr[1]);
开头我们介绍了strlen()函数接收的是一个地址。此处的*arr是数组首元素,arr[1]是数组第二个元素。所以编译器就会报错。还可以再深入讲一下,既然strlen()接收的是一个地址,而*arr是字符a,ASCII表的值为97,,此时strlen()就会把97当成一个地址去访问空间,但这个地址不是我们所拥有的空间,就形成了非法访问。
在这里插入图片描述
这里0x0000000000000061其实就是97,这也就印证了我们的说法。
5.strlen(&arr);
6.strlen(&arr+1);
7.strlen(&arr[0]+1);
&arr,&arr+1,&arr[0]+1其实都是地址,虽然第一个是一个数组的地址,但他的地址与首元素地址一样,所以为随机值,第二个跳过了一个数组所以为随机值-6,6是数组大小,第三个以为跳过了数组中的一个元素,所以为随机值-1
可以看出虽然&arr是一个数组地址,类型为数组指针char(*p)[6],事实上这只是当成一个地址看待,并不会真正影响结果。

字符串

    char arr[]="abcdef";
    printf("%d\n", strlen(arr));
    printf("%d\n", strlen(arr+0));
    printf("%d\n", strlen(&arr));
    printf("%d\n", strlen(&arr+1));
    printf("%d\n", strlen(&arr[0]+1));

在这里插入图片描述

我们看到这其实就会想到这不就是char arr[] = { 'a','b','c','d','e','f' ,'\0'};吗?没错!这里sizeof()计算方法还是与上面是一样的,但strlen()还是要说一下的。
1.strlen(arr);
2.strlen(arr+0);
既然有了'\0'为结尾,那结果肯定就是字符串长度了,即为6
3.strlen(&arr);//这就会返回'\0'之前字符个数,即为6
4.strlen(&arr+1);//但是这里&arr+1跳过了数组arr,于是返回了一个随机值
5.strlen(&arr[0]+1);//这指向的是'b'的地址,于是返回5

计算常量字符串

    char *p = "abcdef";
    printf("%d\n", sizeof(p));
    printf("%d\n", sizeof(p+1));
    printf("%d\n", sizeof(*p));
    printf("%d\n", sizeof(p[0]));
    printf("%d\n", sizeof(&p));

在这里插入图片描述
这儿难道是把"abcdef"放到p里面?其实这里的p仅仅放了'a'的地址
1.sizeof(p);//这儿就是计算指针变量p的地址,4 / 8字节
2.sizeof(p+1);//p+1得到的是字符'b'的地址,4 / 8字节
3.sizeof(*p);//*p其实就是字符串的第一个字符'a'1字节
4.sizeof(p[0]);//事实上这里的p[0]就等价于*(p+0),就是第一个元素,1字节
5.sizeof(&p);//这里&p把指针p的地址取出来了,4 / 8字节

    char *p = "abcdef";
    printf("%d\n", strlen(p));
    printf("%d\n", strlen(&p));
    printf("%d\n", strlen(&p+1));

在这里插入图片描述

1.strlen(p); //上面也分析过了,p存放的就是'a'的地址,strlen()找到'\0'结束,所以就是6
2.strlen(&p);
3.strlen(&p+1);//&p是指针p的地址,这里我画了一张图来说明一下:
在这里插入图片描述
所以这里求出来的其实是随机值!

计算二维数组

    int a[3][4] = {
    
    0};
    printf("%d\n",sizeof(a));
    printf("%d\n",sizeof(a[0][0]));
    printf("%d\n",sizeof(a[0]));
    printf("%d\n",sizeof(a[0]+1));
    printf("%d\n",sizeof(*(a[0]+1)));
    printf("%d\n",sizeof(a+1));
    printf("%d\n",sizeof(*(a+1)));
    printf("%d\n",sizeof(&a[0]+1));
    printf("%d\n",sizeof(*(&a[0]+1)));
    printf("%d\n",sizeof(*a));
    printf("%d\n",sizeof(a[3]));

我们看看编译器输出的结果吧!!!下面讲解一下为什么。
在这里插入图片描述

1.sizeof(a);//这里的a代表整个二维数组的数组名,大小为124,36字节
2.sizeof(a[0][0]);//这则是数组第一个元素,4字节
3.sizeof(a[0]);//a[0]是二维数组的第一行作为一维数组的数组名,所以sizeof()所求的是数组第一行的大小,大小为4
4,16字节
4.sizeof(a[0]+1);//此处a[0]表示第一行的数组名,表示的是首元素地址,其实就是第一行第一个元素的地址,所以a[0]+1就表示第一行第二个元素的地址,4 / 8字节
5.sizeof(*(a[0]+1));//如上*a[0]+1就是第一行第二个元素,4字节
6.sizeof(a+1);//我们考虑一下这是谁的地址呢?a是二维数组的数组名,是首元素地址,而二维数组的首元素是他的第一行,那么a就是第一行的地址,那么加一后就是第二行的地址,4 / 8字节
在这里插入图片描述
在这里插入图片描述
从这我们也可以看出两个地址相差了16,正是4个整形的大小,所以这也验证了上面,加一后跳过了一行。

7.sizeof(*(a+1));//如6.,解引用后就代表第二行,16字节
8.sizeof(&a[0]+1);//&a[0]取出第一行地址,加一后为第二行地址,4 / 8字节
9.sizeof(*(&a[0]+1));//解引用得到数组第二行,16字节
10.sizeof(*a);//a是首元素地址,第一行地址,解引用后为第一行,16字节
11.sizeof(a[3]);//a[3]是数组第四行,虽没有第四行,但根据数组类型,计算的任是一行有四个整形的数组大小,所以还为16

猜你喜欢

转载自blog.csdn.net/2301_77404033/article/details/132185734