指针(6)

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比较

sizeofstrlen
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自身的值发生改变 后面的结果会受到影响

  • 第一个输出

  • 第二个输出

  • 第三个输出

  • 第四个输出

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值