1. sizeof 和 strlen 的对比
1.1 sizeof
sizeof 计算变量所占用内存空间大小的,单位是字节,如果操作数是类型的话,计算的是使用类型创建的变量所占用空间的大小。
sizeof 只关注占用内存空间的大小,不在乎内存中存放了什么数据。
比如:
1.2 strlen
strlen 是C语言库函数,功能是求字符串长度。函数原型如下:
size_t strlen (const char* str);
strlen 统计的是从 strlen 函数的参数 str 中这个地址开始向后,\0 之前字符串中字符的个数。
strlen 函数会一直向后找 \0 字符,知道找到为止,所以可能存在越界查找。
1.3 sizeof 和 strlen 的对比
sizeof:
(1)sizeof是操作符;
(2)sizeof计算操作数所占内存大小,单位是字节;
(3)不关注内存中存放的是什么数据;
(4)sizeof不挑类型。
strlen:
(1)strlen是库函数,使用需要包含头文件 string.h ;
(2)strlen是求字符串长度的,统计的是\0之前字符的个数;
(3)关注的内存中是否有\0,如果没有,就会往后找,可能越界;
(4)只能针对字符串。
2. 数组和指针笔试题解析
2.1 一维数组
#include <stdio.h>
int main()
{
//数组名一般表示的是数组首元素的地址
//例外:1. sizeof(数组名) —— 数组名表示整个数组,计算的是整个数组的大小,单位是字节
// 2. &(数组名) —— 数组名表示整个数组,取出的是数组的地址
int a[] = { 1, 2, 3, 4 };//a数组有4个元素,每个元素是int类型的数据
printf("%d\n", sizeof(a)); //16 - 计算的是整个数组的大小
printf("%d\n", sizeof(a + 0)); //4/8 - a表示的是首元素的地址,a+0还是首元素的地址
printf("%d\n", sizeof(*a)); //4 - a表示的是首元素的地址,*a就是首元素
printf("%d\n", sizeof(a + 1)); //4/8 - a表示的是首元素的地址,a+1表示的是第二个元素的地址
printf("%d\n", sizeof(a[1])); //4 - a[1]是数组第二个元素
printf("%d\n", sizeof(&a)); //4/8 - 取出的是数组的地址,数组的地址也是地址
printf("%d\n", sizeof(*&a)); //16 - sizeof(a)
printf("%d\n", sizeof(&a + 1)); //4/8 - 是跳过整个数组后的一个地址,是地址
printf("%d\n", sizeof(&a[0])); //4/8 - &a[0]是数组第一个元素的地址
printf("%d\n", sizeof(&a[0] + 1));//4/8 - &a[0]+1等价于a+1,表示的是第二个元素的地址
return 0;
}
2.2 字符数组
#include <stdio.h>
int main()
{
char arr[] = { 'a', 'b', 'c', 'd', 'e', 'f' };//arr数组中有6个元素
printf("%d\n", sizeof(arr)); //6 - 计算的是整个数组的大小
printf("%d\n", sizeof(arr+0)); //4/8 - 第一个元素的地址
printf("%d\n", sizeof(*arr)); //1 - *arr是首元素,计算的就是首元素的大小
printf("%d\n", sizeof(arr[1])); //1 - 是第二个元素
printf("%d\n", sizeof(&arr)); //4/8 - 取出整个数组的地址,是地址
printf("%d\n", sizeof(&arr+1)); //4/8 - 是跳过整个数组后的一个地址,是地址
printf("%d\n", sizeof(&arr[0]+1));//4/8 - 等价于arr+1,是第二个元素的地址
return 0;
}
#include <stdio.h>
#include <string.h>
int main()
{
char arr[] = { 'a', 'b', 'c', 'd', 'e', 'f' };
//找\0
printf("%d\n", strlen(arr)); //随机值
printf("%d\n", strlen(arr+0)); //随机值
printf("%d\n", strlen(*arr)); //err —— *arr -> 'a' -> 97 ?
printf("%d\n", strlen(arr[1])); //err —— arr[1] -> 'b' -> 98 ?
printf("%d\n", strlen(&arr)); //随机值
printf("%d\n", strlen(&arr+1)); //随机值
printf("%d\n", strlen(&arr[0]+1));//随机值
return 0;
}
#include <stdio.h>
int main()
{
char arr[] = {"abcdef"};//arr数组中有7个元素
printf("%d\n", sizeof(arr)); //7 - 计算的是整个数组的大小
printf("%d\n", sizeof(arr + 0)); //4/8 - 第一个元素的地址
printf("%d\n", sizeof(*arr)); //1 - *arr是首元素,计算的就是首元素的大小
printf("%d\n", sizeof(arr[1])); //1 - 是第二个元素
printf("%d\n", sizeof(&arr)); //4/8 - 取出整个数组的地址,是地址
printf("%d\n", sizeof(&arr + 1)); //4/8 - 是跳过整个数组后的一个地址,是地址
printf("%d\n", sizeof(&arr[0] + 1));//4/8 - 等价于arr+1,是第二个元素的地址
return 0;
}
#include <stdio.h>
#include <string.h>
int main()
{
char arr[] = {"abcdef"};
//找\0
printf("%d\n", strlen(arr)); //6 - arr是首元素地址
printf("%d\n", strlen(arr + 0)); //6 - arr+0是首元素地址
printf("%d\n", strlen(*arr)); //err —— *arr -> 'a' -> 97 ?
printf("%d\n", strlen(arr[1])); //err —— arr[1] -> 'b' -> 98 ?
printf("%d\n", strlen(&arr)); //6 - &arr虽然是数组的地址,但也是指向数组的其实位置
printf("%d\n", strlen(&arr + 1)); //随机值
printf("%d\n", strlen(&arr[0] + 1));//5 - 是第二个元素的地址
return 0;
}
#include <stdio.h>
#include <string.h>
int main()
{
char* p = "abcdef";
printf("%zd\n", sizeof(p)); //4/8 - 计算的是指针变量的大小
printf("%zd\n", sizeof(p + 1)); //4/8 - 表示的是'b'的地址,是地址
printf("%zd\n", sizeof(*p)); //1 - *p就是'a',大小是1个字节
printf("%zd\n", sizeof(p[0])); //1 - p[0] --> *(p+0) --> *p
printf("%zd\n", sizeof(&p)); //4/8 - 是指针变量p的地址
printf("%zd\n", sizeof(&p + 1)); //4/8 - &p+1是指针变量后面的空间,是地址
printf("%zd\n", sizeof(&p[0] + 1));//4/8 - 是'b'的地址,是地址
return 0;
#include <stdio.h>
#include <string.h>
int main()
{
char* p = "abcdef";
//a b c d e f \0
printf("%zd\n", strlen(p)); //6
printf("%zd\n", strlen(p + 1)); //5
printf("%zd\n", strlen(*p)); //err
printf("%zd\n", strlen(p[0])); //err - p[0] --> *(p+0) --> *p
printf("%zd\n", strlen(&p)); //随机值
printf("%zd\n", strlen(&p + 1)); //随机值
printf("%zd\n", strlen(&p[0] + 1));//5
return 0;
}
2.3 二维数组
#include <stdio.h>
#include <string.h>
int main()
{
int a[3][4] = { 0 };
printf("%d\n", sizeof(a)); //12*4 = 48个字节,整个数组
printf("%d\n", sizeof(a[0][0])); //4
printf("%d\n", sizeof(a[0])); //4*4 = 16个字节 是第一行这个一维数组的数组名
printf("%d\n", sizeof(a[0]+1)); //4/8 表示a[0][1]的地址
printf("%d\n", sizeof(*(a[0] + 1))); //4 表示a[0][1],大小4个字节
printf("%d\n", sizeof(a + 1)); //4/8 这里的a是数组首元素的地址,应该是第一行的地址,a+1是第二行的地址
printf("%d\n", sizeof(*(a + 1))); //4*4 = 16个字节 表示的是第二行一维数组的数组名,计算的是第二行数组的大小
printf("%d\n", sizeof(&a[0] + 1)); //4/8 &a[0]是第一行的地址,则&a[0]+1就是第二行的地址
printf("%d\n", sizeof(*(& a[0] + 1)));//16 访问的是第二行,计算的是第二行的大小
printf("%d\n", sizeof(*a)); //16 a是第一行的地址,所以*a是第一行
printf("%d\n", sizeof(a[3])); //16 因为sizeof内部的表达式不会真实计算,所以不存在越界,计算的是第四行的-16
return 0;
}