1. sizeof和strlen的对比
1.1 sizeof
在学习操作符的时候,我们学习了 sizeof , sizeof 计算变量所占内存内存空间大小的,单位是字节,如果操作数是类型的话,计算的是使⽤类型创建的变量所占内存空间的大小。
sizeof 只关注占用内存空间的大小,不在乎内存中存放什么数据。
sizeof是操作符 不是函数
int main() {
int a = 10;
printf("%zd\n", sizeof(int));
printf("%zd\n", sizeof(a));
int arr[10] = { 0 };//里面放了什么数据不会影响
printf("%zd", sizeof(arr)); //只关注内存空间大小
}
1.2 strlen
-
strlen库函数,求字符串的长度,只能针对字符串(字符数组)
-
统计的是从 strlen 函数的参数 str 中这个地址开始向后, \0 之前字符串中字符的个数。strlen 函数会⼀直向后找 \0 字符,直到找到为止,所以可能存在越界查找。
int main() {
char arr[] = { 'a','b','c' }; //char 一个字符一个字节
char arr1[] = "abc";
int arr2[] = { 1,2 };//int 一个整形4个字节
//strlen函数 计算数组的元素个数(字符串)
printf("%zd\n", strlen(arr));
printf("%zd\n", strlen(arr1));
//sizeof 不关注里面存的数据 只关注数组的大小
printf("%zd\n", sizeof(arr));//3
printf("%zd\n", sizeof(arr1));//4 把\0也也统计了
printf("%zd\n", sizeof(arr2));//8
return 0;
}
1.3 sizeof和strlen比较
sizeof | strlen |
---|---|
1. sizeof是操作符 | 1.strlen是库函数,使⽤需要包含头⽂件 string.h |
2. sizeof计算操作数所占内存的大小,单位是字节 | 2. srtlen是求字符串⻓度的,统计的是 \0 之前字符的个数 |
3.不关注内存中存放什么数据 | 3. 关注内存中是否有 \0 ,如果没有 \0 ,就会持续往后找,可能越界 |
2..数组和指针笔试题解析
2.1 ⼀维数组
整形的地址, -->(&a) 是地址都是4(x86)/8(x64)
arr 只有在-->sizeof(arr) 和 &arr的时候 不是表示首字元素的地址
sizeof(arr) ---> 整个数组的大小,单位是字节
&arr ---> 整个数组的地址 -->> 4 或者8
sizeof(arr+0) 因为他不是 sizeof(arr) 这种形式 所以它代表的是首元素地址 +0 也一样
int main() {
int a[] = { 1,2,3,4 };
printf("%zd\n", sizeof(a));
printf("%zd\n", sizeof(a + 0));
printf("%zd\n", sizeof(*a));
printf("%zd\n", sizeof(a + 1));
printf("%zd\n", sizeof(a[1]));
printf("%zd\n", sizeof(&a));//4 或者 8
printf("%zd\n", sizeof(*&a));//16
printf("%zd\n", sizeof(&a + 1));//4 或者 8
printf("%zd\n", sizeof(&a[0]));//4 或者 8
printf("%zd\n", sizeof(&a[0] + 1));//4 或者 8
}
-
看如下解析
2.2字符数组
2.2.1代码1
char arr[] = {'a','b','c','d','e','f'};
printf("%d\n", sizeof(arr));//整个数组的大小6个元素 6个字节
printf("%d\n", sizeof(arr+0));// 首元素地址4/8
printf("%d\n", sizeof(*arr));// 首元素大小1
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
2.2.2代码2
字符数组 strlen函数找不到\0 输出随机值
int main() {
char arr[] = { 'a','b','c','d','e','f' };
printf("%zd\n", strlen(arr));
printf("%zd\n", strlen(arr + 0));
printf("%zd\n", strlen(*arr));
printf("%zd\n", strlen(arr[1]));
printf("%zd\n", strlen(&arr));
printf("%zd\n", strlen(&arr + 1));
printf("%zd\n", strlen(&arr[0] + 1));
}
2.2.3代码3
- char arr[] = "abcdef";
- 数组中存放的是{a,b,c,d,e,f,\0}
int main() {
char arr[] = "abcdef";
//{ a b c d e f \0}
printf("%zd\n", sizeof(arr));//7
printf("%zd\n", sizeof(arr + 0));//4/8
printf("%zd\n", sizeof(*arr));//1
printf("%zd\n", sizeof(arr[1]));//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;
}
2.2.4代码4
printf("%d\n", strlen(&arr));
&arr 的类型是 char (*) [7]
strlen函数接受的类型是 (const char* str) &arr传给strlen的话会进行强制转换,从第一个元素开始数,最后输出也是6
printf("%d\n", strlen(&arr + 1));
&arr+1 直接跳到数组的最后个元素,从该位置开始往后数,不知道后面有啥元素就返回一个随机
int main() {
char arr[] = "abcdef";
//arr 是首元素地址 strlen从第一个元素往后统计个数 一直到\0
printf("%d\n", strlen(arr)); //6
printf("%d\n", strlen(arr + 0));//6
//printf("%d\n", strlen(*arr)); 得到一个元素'a' 找97的字符个数,程序报错
//printf("%d\n", strlen(arr[1]));'b',程序报错
printf("%d\n", strlen(&arr));
printf("%d\n", strlen(&arr + 1));
printf("%d\n", strlen(&arr[0] + 1));//第二个元素开始数 5
}
2.2.5代码5
p[0] 等价于 *(p+0)
int main() {
char* p = "abcdef";
printf("%zd\n", sizeof(p));
printf("%zd\n", sizeof(p + 1));
printf("%zd\n", sizeof(*p));
printf("%zd\n", sizeof(p[0]));
printf("%zd\n", sizeof(&p));
printf("%zd\n", sizeof(&p + 1));
printf("%zd\n", sizeof(&p[0] + 1));
}
2.2.6代码6
&p[0] 等价于 & * (p+0) 等价于 p
所以strlen(&p[0]+1) 输出 5
char *p = "abcdef";
printf("%d\n", strlen(p));
printf("%d\n", strlen(p+1));
printf("%d\n", strlen(*p));
printf("%d\n", strlen(p[0]));
printf("%d\n", strlen(&p));
printf("%d\n", strlen(&p+1));
printf("%d\n", strlen(&p[0]+1));
2.3二维数组
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]));
注意:a[3] 数组越界,但是sizeof内部的表达式不会真实计算,只会看它的类型int [4],所以只计算4个整形元素的大小 16个字节
如果不懂我们在再看看以下列子,他输出的是什么呢?
答案是4 因为sizeof内部不进行计算,只会看a的类型,a是整形所以是4个字节
int main() {
int a = 3;
int b = 3;
printf("%zd", sizeof(a = b + 3));
}
3.指针运算笔试题解析
3.1题目1
#include <stdio.h>
int main()
{
int a[5] = { 1, 2, 3, 4, 5 };
int* ptr = (int*)(&a + 1); //int(*) 强制类型转换
printf("%d,%d", *(a + 1), *(ptr - 1)); //输出 2 5
return 0;
}
3.2题目2
-
注意:
指针加1==>跳过一个指针类型大小
整数加1==>那就是加上一个1
//在X86环境下
//假设结构体的⼤⼩是20个字节
//程序输出的结果是啥?
struct Test
{
int Num;
char* pcName;
short sDate;
char cha[2];
short sBa[4];
}* p = (struct Test*) 0x100000;
int main()
{
printf("%p\n", p + 0x1);
printf("%p\n", (unsigned long)p + 0x1);//强制转换成一个整数
printf("%p\n", (unsigned int*)p + 0x1);//强制转换成整数类型指针
return 0;
}
- 为了让我们更好的理解以上代码,我们拆分如下
struct Test { int Num; char* pcName; short sDate; char cha[2]; short sBa[4]; }* 这个代表的是结构体指针的类型
p是指针变量
(struct Test*) 0x100000 0x100000代表的是一个八进制数,整形 (struct Test*) 强制类型转换成 结构体指针类型
3.3题目3
我们是不是觉得他是一个三行两列的二维数组,其实并不是
我们数组赋值时用的是{ },并非( ), ( )代表的是括号表达式,从左向右计算,最终结果取右边的数值 例如(0,1) ==> 1
所以该数组的是 {1 , 3 , 5}
所以p[0] 输出 1
#include <stdio.h>
int main()
{
int a[3][2] = { (0, 1), (2, 3), (4, 5) };
int* p;
p = a[0];
printf("%d", p[0]);
return 0;
}
3.4题目4
地址 ➖ 地址 = 元素个数 小地址减去大地址 取负数
-4在内存中以补码形式保存
%p 打印16进制的地址,输出就是内存中保存 的-4的补码 ==>FF FF FF FC
%d 打印原码 有符号数 -4
//假设环境是x86环境,程序输出的结果是啥?
#include <stdio.h>
int main()
{
int a[5][5];
int(*p)[4];
p = a;
printf( "%p,%d\n", &p[4][2] - &a[4][2], &p[4][2] - &a[4][2]);
return 0;
}
3.5题目6
-
(*(aa+1)) 等价于 aa[1] 第一行首元素的地址+1 然后解引用等于 6
#include <stdio.h>
int main()
{
int aa[2][5] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
int *ptr1 = (int *)(&aa + 1);
int *ptr2 = (int *)(*(aa + 1));
printf( "%d,%d", *(ptr1 - 1), *(ptr2 - 1)); //10 5
return 0;
}
3.6题目6
#include <stdio.h>
int main()
{
char *a[] = {"work","at","alibaba"};
char**pa = a;
pa++;
printf("%s\n", *pa);
return 0;
}
3.7题目7
#include <stdio.h>
int main()
{
char *c[] = {"ENTER","NEW","POINT","FIRST"};
char**cp[] = {c+3,c+2,c+1,c};
char***cpp = cp;
printf("%s\n", **++cpp);
printf("%s\n", *--*++cpp+3);
printf("%s\n", *cpp[-2]+3);
printf("%s\n", cpp[-1][-1]+1);
return 0;
}
-
注意: 一开始 ++cpp 这个运算 cpp自身的值发生改变 后面的结果会受到影响
-
第一个输出
-
第二个输出
-
第三个输出
-
第四个输出