文章目录
- 一、sizeof和strlen的对比
- 1、sizeof
- 2、strlen
- 3、sizeof和strlen的对比
- 二、数组和指针笔试题解析
- 1、一维数组
- 2、字符数组
- 3、二维数组
一、sizeof和strlen的对比
1、sizeof
siezeof是一个操作符,sizeof计算的是变量所占内存空间大小,单位是字节,操作数也可以是类型要用()括号扩起来,计算的是类型创建所占内存空间的大小。
sizeof只关注占用内存的大小,不在乎内存中存放什么数据。
#include<stdio.h>
int main()
{
int a = 10;
printf("%zd\n", sizeof(a));
printf("%zd\n", sizeof a);
printf("%zd\n", sizeof(int));
return 0;
}
2、strlen
strlen库函数使用时,需引入头文件<string.h>
strlen是C语言库函数,功能求字符串长度。函数原型如下:
size_t strlen ( const char * str );
strlen函数计算的长度是从参数str这个地址开始向后,\0之前字符串中字符的个数。
strlen函数会一直向后找\0字符,直到找到为止,所以可能存在越界查找。
#include <stdio.h>
#include<string.h>
int main()
{
char arr1[3] = { 'a', 'b', 'c' };
char arr2[] = "abc";
printf("%d\n", strlen(arr1));
//arr1初始化后没有\0,打印的值随机
printf("%d\n", strlen(arr2));
//arr2后加\0,打印结果为3
printf("%zd\n", sizeof(arr1));
//只有三个char类型的数据,占用3个字节的空间
printf("%zd\n", sizeof(arr2));
//arr2后加了\0,有四个char类型的数据,占用4个字节的空间
return 0;
}
3、sizeof和strlen的对比
sizeof | strlen |
---|---|
1、sizeof是操作数 2、sizeof计算操作数所占内存的大小单位是字节 3、不关注内存中存放什么数据 4、返回值为size_t 类型无符号整形 | 1、strlen是库函数,使用时需包含头文件string.h 2、strlen是求字符串长度,统计的是\0之前字符的个数,在字符串中使用 3、关注内存是否有\0,如果没有\0,,就会持续往后找,可能会越界 4、返回值为size_t类型无符号整形 |
二、数组和指针笔试题解析
1、一维数组
#include<stdio.h>
int main()
{
int a[] = { 1,2,3,4 };
printf("%zd\n", sizeof(a));
//sizeof里面单独出现数组名,数组名代表整个数组的长度,为16字节
printf("%zd\n", sizeof(a + 0));
//sizeof里面没有单独出现数组名,数组名代表首元素地址,首元素地址 a + 0,等于&a[0],是地址4/8个字节
printf("%zd\n", sizeof(*a));
//sizeof里没有单独出现数组名,数组名代表首元素地址,首元素地址解引用,等于 a[0] == 1, 结果为4个字节
printf("%zd\n", sizeof(a + 1));
//首元素地址 &a[0] +1 ,等于 &a[1], 是地址大小为 4 / 8个字节
printf("%zd\n", sizeof(a[1]));
//a[1]等于 *(a + 1) ,a[1]代表数组第二个元素 2, 2的类型为int,大小为4
printf("%zd\n", sizeof(&a));
//&a,取地址数组名代表整个数组的地址,是地址大小为4/8个字节
printf("%zd\n", sizeof(*&a));
//&a,取地址数组名代表整个数组的地址,*&a,解引用整个数组的地址,代表整个数组的大小,类型为 int[4],大小为16个字节
printf("%zd\n", sizeof(&a + 1));
//&a,取地址数组名代表整个数组的地址,&a + 1,代表整个数组后面的地址,是地址4/8个字节
printf("%zd\n", sizeof(&a[0]));
//&a[0],取地址元素,是地址4/8个字节
printf("%zd\n", sizeof(&a[0] + 1));
//&a[0]+1,等于&a[1],是第二个元素的地址,是地址4/8个字节
return 0;
}
2、字符数组
代码1:
#include<stdio.h>
int main()
{
char arr[] = { 'a','b','c','d','e','f' };
printf("%d\n", sizeof(arr));
//sizeof里面单独出现数组名代表整个数组的大小大小为6个字节
printf("%d\n", sizeof(arr + 0));
//arr+0,代表&a[0]首元素地址,是地址4/8个字节
printf("%d\n", sizeof(*arr));
//数组名代表首元素地址,*arr 是数组第一个元素 'a',类型为char 大小为1个字节
printf("%d\n", sizeof(arr[1]));
//arr[1]数组中的二个元素'b',类型为char,大小为1个字节
printf("%d\n", sizeof(&arr));
//&arr代表整个元素的地址,是地址大小为4/8个字节
printf("%d\n", sizeof(&arr + 1));
//&arr + 1,个个数组的地址加1,数组的末尾地址,是地址大小4/8个字节
printf("%d\n", sizeof(&arr[0] + 1));
//&arr[0]+1,是数组中第二个元素的地址,&arr[1],是地址大小4/8个字节
return 0;
}
代码2:
#include<stdio.h>
int main()
{
char arr[] = { 'a','b','c','d','e','f' };
printf("%zd\n", strlen(arr));
//字符串后面没有\0,随机值
printf("%zd\n", strlen(arr + 0));
//首元素地址,没有结束标志\0,随机值
//printf("%zd\n", strlen(*arr));
//是首元素'a',把字符'a',97当成地址访问,崩溃
//printf("%zd\n", strlen(arr[1]));
//把第二个元素'b',98当成地址访问,崩溃
printf("%zd\n", strlen(&arr));
//整个数组的地址,起始地址跟首元素地址一样,随机值
printf("%zd\n", strlen(&arr + 1));
//整个数组的地址加一,指向的是&arr[7],越界,随机值
printf("%zd\n", strlen(&arr[0] + 1));
//二个元素的地址&a[1],没有\0结束,随机值
return 0;
}
代码3:
#include<stdio.h>
int main()
{
char arr[] = "abcdef";
printf("%zd\n", sizeof(arr));
//数组名单独出现在sizeof里面,数组名代表整个数组的大小,整个数组后面隐藏了一个\0,大小为7个字节
printf("%zd\n", sizeof(arr + 0));
//首元素地址,是地址大小为4/8个字节
printf("%zd\n", sizeof(*arr));
//首元素,大小为1个字节
printf("%zd\n", sizeof(arr[1]));
//第二个元素'b',大小1个字节
printf("%zd\n", sizeof(&arr));
//&数组名,代表整个数组的地址,是地址大小为4/8
printf("%zd\n", sizeof(&arr + 1));
//整个数组的地址加一,还是地址,大小为4/8
printf("%zd\n", sizeof(&arr[0] + 1));
//第二个元素的地址,是地址大小为4/8
return 0;
}
代码4:
#include<stdio.h>
#include<string.h>
int main()
{
char arr[] = "abcdef";//后面自动加了\0
printf("%zd\n", strlen(arr));
//数组名代表首元素地址,\0之前有 6 个字符
printf("%zd\n", strlen(arr + 0));
//首元素地址,6
//printf("%zd\n", strlen(*arr));
//'a'的值97当成地址访问,崩溃
//printf("%zd\n", strlen(arr[1]));
//'b'的值当成地址访问,崩溃
printf("%zd\n", strlen(&arr));
//&数组名代表整个数组的地址,传参会形参接收用的是char*,就从首元素访问找\0,6
printf("%zd\n", strlen(&arr + 1));
//真个数组的地址加一指向的是数组后的地址,随机值
printf("%zd\n", strlen(&arr[0] + 1));
//第二个元素的地址找\0, 5
return 0;
}
代码5:
#include<stdio.h>
int main()
{
char* p = "abcdef";//指针指向常量字符串,首字符的地址
printf("%zd\n", sizeof(p));
//指针变量的大小,char*,4/8
printf("%zd\n", sizeof(p + 1));
//b字符的地址,是地址4/8
printf("%zd\n", sizeof(*p));
//首字符'a',大小为char 1个字节
printf("%zd\n", sizeof(p[0]));
//p[0] = *(p+0),首字符'a',大小1
printf("%zd\n", sizeof(&p));
//p变量的地址,是地址4/8
printf("%zd\n", sizeof(&p + 1));
//地址加一还是地址,是地址4/8
printf("%zd\n", sizeof(&p[0] + 1));
//首字符的地址加一,变成第二个字符的地址,是地址4/8
return 0;
}
代码6:
#include<stdio.h>
int main()
{
char* p = "abcdef";//后面有\0
printf("%zd\n", strlen(p));
//首字符地址,结果为 6
printf("%zd\n", strlen(p + 1));
//第二个字符地址,5
//printf("%zd\n", strlen(*p));
//字符’a'被当成地址访问崩溃
//printf("%zd\n", strlen(p[0]));
//等于*(p+0),首字符被当成地址访问,崩溃
printf("%zd\n", strlen(&p));
//变量p的地址,往后找\0,随机值
printf("%zd\n", strlen(&p + 1));
//变量p的地址加一,随机值
printf("%zd\n", strlen(&p[0] + 1));
//第二个字符'b'的地址,5
return 0;
}
3、二维数组
#include<stdio.h>
int main()
{
int a[3][4] = { 0 };
printf("%zd\n", sizeof(a));
//整个数组的大小,12个int类型的元素,48
printf("%zd\n", sizeof(a[0][0]));
//第一行第一列元素,int类型,4
printf("%zd\n", sizeof(a[0]));
//第一行地址,代表整行的大小类型为int[4],16
printf("%zd\n", sizeof(a[0] + 1));
//第一行,第二列地址, 是地址 4 /8
printf("%zd\n", sizeof(*(a[0] + 1)));
//第一行第二列元素,int类型 4
printf("%zd\n", sizeof(a + 1));
//第一行地址加一,第二行地址 ,是地址 4 /8
printf("%zd\n", sizeof(*(a + 1)));
//第二行地址,第二行大小,16
printf("%zd\n", sizeof(&a[0] + 1));
//第二行地址是地址 4/8
printf("%zd\n", sizeof(*(&a[0] + 1)));
//第二行大小,16
printf("%zd\n", sizeof(*a));
//第一行地址,16
printf("%zd\n", sizeof(a[3]));
//第三行地址,16
return 0;
}