C语言进阶之旅 (11.5)指针下 提升篇

文章目录

  • 题1
  • 题2(函数传参数)
    • 一维数组
    • 二维数组传参
  • 题3 计算器(函数数组指针)
  • 题4 回调函数(qsort)
  • 题 5
    • 1
      • 解读
    • 2
      • 解读
    • 3
    • 4
    • 5
  • 题 6
  • 题 7
  • 题8
  • 题9
  • 题 10
  • 题 11
  • 题12
  • 总结

题1

  • 判断字符串是否相等
  • 易错点,内存如何存储常量字符串
#include 
int main() {
     
    char str1[] = "hello bit.";
    char str2[] = "hello bit.";
    char *str3 = "hello bit.";
    char *str4 = "hello bit.";
    if(str1 ==str2)
        printf("str1 and str2 are same\n");
else
        printf("str1 and str2 are not same\n");
    if(str3 ==str4)
        printf("str3 and str4 are same\n");
else
        printf("str3 and str4 are not same\n");
    return 0;
}

图解:
C语言进阶之旅 (11.5)指针下 提升篇_第1张图片

运行结果:
C语言进阶之旅 (11.5)指针下 提升篇_第2张图片

题2(函数传参数)

一维数组

  • 这里的易错点,搞清楚传的是啥,用啥可以接收
  • 解释写在代码里
#include 
void test(int arr[])//ok?
{
     }//数组传数组接收,没毛病
void test(int arr[10])//ok?
{
     }//这里也是数组,没毛病,可写可不写,
void test(int *arr)//ok?
{
     }//数组名就是首元素地址,指针接收也没毛病
void test2(int *arr[20])//ok?
{
     }//数组指针,每个元素都是指针,用数组指针接收也没毛病
void test2(int **arr)//ok?
{
     }//传过来是元素地址,里面每个元素都是指针,那么二级指针接收似乎也没毛病
int main()
{
     
    int arr[10] = {
     0};
    int *arr2[20] = {
     0};
    test(arr);
    test2(arr2);
}

二维数组传参

void test(int arr[3][5])//ok? 
{
     }//二维数组传,二维数组接收,perfect
void test(int arr[][])//ok? 
{
     }//err省行不剩列
void test(int arr[][5])
{
     }//这个就没问题
void test (int *arr)
{
     }//err,二维数组指针,你用指针怎么存的下
void test (int *arr[5])
{
     }//*先和方括号结合了他是数组指针,每个元素是int*
void test(int (*arr)[5])//ok?
 {
     }//指针数组接收没毛病,
void test(int **arr)//ok?
{
     }//err,传过来的参数就不是二级指针咋他怎么接收?

int main()
 {
     
    int arr[3][5] = {
     0};
    test(arr); 
}


题3 计算器(函数数组指针)

  • 该计算器(只有加减乘除的供能,只能操作俩个操作数)
  • 具体思路
  • 1:应为操作数都是一样,返回类型也是一样的,把地址给指针,然后存到数组里面方便调用
  • 然后利用input输入的值进行对函数的调用
    C语言进阶之旅 (11.5)指针下 提升篇_第3张图片

代码

#include
void menu()
{
     
	printf("##################################\n");
	printf("###1:加 2:减 3:乘 4:除 0:退出#####\n");
	printf("##################################\n");

}
int Add(int x, int y)//加
{
     
	return x + y;
}
int Sub(int x, int y)//减
{
     
	return x - y;
}
int Mul(int x, int y)//乘
{
     
	return x * y;
}
int Div(int x, int y)//除
{
     
	return x / y;
}
int main()
{
     
	int input = 0;
	
	int ret = 0;
	int x=0;
	int y = 0;
	do
	{
     
		int(*parr[5])(int, int) = {
      0,Add,Sub,Mul,Div };
		menu();
		printf("选择");
		scanf("%d", &input);
		if (input >= 1 && input<=4)
		{
     
			printf("输入俩个操作数:<");
			scanf("%d%d", &x, &y);
			ret = parr[input](x, y);
			printf("%d\n", ret);
		}
		else if(input<0||input>4)
		{
     
			printf("请带上眼镜看选项\n");
		}
		else
		{
     
			printf("退出");
			break;
		}
	} while (input);
	
}

图解:函数数组内部
C语言进阶之旅 (11.5)指针下 提升篇_第4张图片

精髓所在就在这里哈哈哈
C语言进阶之旅 (11.5)指针下 提升篇_第5张图片


题4 回调函数(qsort)

  • 在冒泡排序基础上排序

冒泡排序:
正序排序
这个是基础算发:
第一个元素小于第二就交换,然后依次后面的比知道正序为止
元素个数有多少个就排序多少次
类似爬那种金字塔类似,下面比较宽就需要多走一些,上面越来窄,走的也少
C语言进阶之旅 (11.5)指针下 提升篇_第6张图片


  • 那么看看他如何实现的
  • 末尾有详细大致介绍
  • sqr他里面有三个4个参数
  • 1:void* base 指针类型,他不知道你要排序啥类型的数组
  • 2:sizet num数组有多少个元素
  • 3:sizet size 每个元素是多大
  • 4:int (*compar)(const void* 1,const void* 2); //该函数的精髓之一,直接传入第一第二的元素相减,如果大0,那么就交换,小于则不交换,如果等于也不交换
  • 这里就是回调函数了,我这个函数的结果会影响qsort函数
#include

//该函数的在冒泡函数基础上进行
//
//
int comp(void*p1,void*p2)
{
     
	return *(int*)p1 - *(int*)p2;
}
void swap(char*a,char*b,int typ)
{
     
	//这里你不知道他是啥类型的,所以直接一个字节一个字节的交换,交换到那个类型的长度
	int i = 0;
	for ( i = 0; i < typ; i++)
	{
     
		int tmp = *a;
		*a = *b;
		*b = tmp;//err
		a++;
		b++;
	}
}
void bubble(void *basr,//指针
	         int sz,//元素个数
	         int typ,//元素类型
	         int (*comp)(const void*,const void*))
{
     
	int i = 0;

	for ( i = 0; i < sz-1; i++)
	{
     
		int j = 0;
		for ( j = 0; j < sz-1-i; j++)
		{
     
			//这里吗也不知道你啥类型的用char,他可以访问最少的字节,然后+上他那个类型,他就等于那个类型了
			
			if (comp((char*)basr + j * typ , (char*)basr+(j + 1) * typ) > 0)
			{
     
			     //交换
				swap((char*)basr + j * typ, (char*)basr + (j + 1) * typ, typ);
			}
		}
	}
}
int main()
{
     

	int arr[] = {
      9,8,7,6,5,4,3,2,1 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	
	bubble(arr,sz,sizeof(arr[0]),comp);
	//打印
	int i = 0;
	for ( i = 0; i < sz-1; i++)
	{
     
		printf("%d", arr[i]);
	}
}

解析这个代码:
在这里插入图片描述

C语言进阶之旅 (11.5)指针下 提升篇_第7张图片

题 5

1

  1. 解释在代码后面
  2. 数组在&地址或sizof内部的时候是整个数组,别的时候是数组名
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));//这里首元素地址加1arr[1] 也是地址 4/8

解读

  • printf("%d\n", sizeof(a));
    16—>数组单独放在sizeof里面
  • printf("%d\n", sizeof(a + 0));
  • printf("%d\n", sizeof(a + 1));
    4/8---->他先加了后面的0/1,那么就是数组名,就是地址
  • printf("%d\n", sizeof(*a));
    4—>首元素里面的元素的类型
  • printf("%d\n", sizeof(a[1]))
    4—>算的是数组第二个元素的类型
  • printf("%d\n", strlen(&arr));
    4/8—>&arr就是地址吗
  • printf("%d\n", sizeof(* &a));
    16---->计算整个数组的元素类型
  • printf("%d\n", sizeof(&a + 1));
    4/8—>整个数组地址加一,还是地址
  • printf("%d\n", sizeof(&a[0]));
    4/8—>首元素地址
  • printf("%d\n", sizeof(&a[0] + 1));
    4/8—>第二个元素的地址

解析这条代码的能从布局

printf("%d\n", sizeof(&a + 1))
好丑哈哈哈
C语言进阶之旅 (11.5)指针下 提升篇_第8张图片

2

  • strlen 结束标志是\0
  • 接收的参数是const char *
  • 模拟实现strlen

	字符数组
	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));

	
	printf("%d\n", sizeof(arr));
	printf("%d\n", sizeof(arr + 0));
	printf("%d\n", sizeof(*arr));
	printf("%d\n", sizeof(arr[1]));
	printf("%d\n", sizeof(&arr));
	printf("%d\n", sizeof(&arr + 1));
	printf("%d\n", sizeof(&arr[0] + 1));

解读

  • printf("%d\n", strlen(arr));
    随机值—>这里没有\0
  • printf("%d\n", strlen(arr + 0))
    随机值—>这里没有\0,
  • printf("%d\n", strlen(*arr));
    err --> strlen接收是char *,你着指针数组过来凑啥热闹,类型不匹配
  • printf("%d\n", strlen(arr[1]));
    err —>同样类型不匹配,砸场子
  • printf("%d\n", strlen(&arr));
    随机值—>&arr和a地址一样,不过意义不一样,但是strlen把他直接看成首元素地址
  • printf("%d\n", strlen(&arr + 1));
    随机值—>首元素加了一个数组的元素的个数
  • printf("%d\n", strlen(&arr[0] + 1));
    随机值—>首元素加了一个元素个数
  • printf("%d\n", sizeof(&arr));
    4/8. —>取地址,那么它就是地址


  • printf("%d\n", sizeof(arr));
    6–>计算元素个数
  • printf("%d\n", sizeof(arr + 0));
    4/8 —>他先和后面的0加,那么就是地址
  • printf("%d\n", sizeof(*arr));
    1 —>解引用找到首元素的地址
  • printf("%d\n", sizeof(arr[1]));
    1—>先和[]结合是数组,里面是第二个元素
  • printf("%d\n", sizeof(&arr + 1));
    4/8---->地址加1还是地址
  • printf("%d\n", sizeof(&arr[0] + 1));//地址4/8
    4/8 ---->取出数组手元素的地址加1还是地址

char arr的内存
C语言进阶之旅 (11.5)指针下 提升篇_第9张图片

3

  • 字符串末尾是\0
  • 这儿就在解读了
	char arr[] = "abcdef";
	
	printf("%d\n", strlen(arr));//6
	
	printf("%d\n", strlen(arr + 0));//6
	
	printf("%d\n", strlen(*arr));//err
	
	printf("%d\n", strlen(arr[1]));//err
	
	printf("%d\n", strlen(&arr));//6
	
	printf("%d\n", strlen(&arr + 1));//随机值,加了一个数组的元素个数
	
	printf("%d\n", strlen(&arr[0] + 1));//5,首元素地址加1



 
	printf("%d\n", sizeof(arr));//7,sizeof会算\0
	
	printf("%d\n", sizeof(arr + 0));//7
	
	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));//取地址加1 4/8
	
	printf("%d\n", sizeof(&arr[0] + 1));//首元素地址加1 4/8

4

  • p指向的是a的地址,abcdef是常量字符串不可更该
char* p = "abcdef";

	printf("%d\n", strlen(p));//6
	
	printf("%d\n", strlen(p + 1));//5
	
	printf("%d\n", strlen(*p));//err
		
	printf("%d\n", strlen(p[0]));//err
	
	printf("%d\n", strlen(&p));//6
	
	printf("%d\n", strlen(&p + 1));//随机值
	
	printf("%d\n", strlen(&p[0] + 1));//5




	printf("%d\n", sizeof(p));// 7
	
	printf("%d\n", sizeof(p + 1));//指针 4/8
	
	printf("%d\n", sizeof(*p));// 1
	
	printf("%d\n", sizeof(p[0]));//1
	
	printf("%d\n", sizeof(&p));//地址 4/8
	
	printf("%d\n", sizeof(&p + 1));//地址 4/8
	
	printf("%d\n", sizeof(&p[0] + 1));// 地址 4/8

解析一段代码:
这里&加1和上面的不太一样,上面取地址加1是加了一个数组的元素个数
这个&p+1就是p的地址加了1
在这里插入图片描述
C语言进阶之旅 (11.5)指针下 提升篇_第10张图片

5

  • 二维数组,一行等于一个元素
int a[3][4]={
     0};

printf("%d\n",sizeof(a));//整个数组 48

printf("%d\n",sizeof(a[0][0]));//第一个元素 4

printf("%d\n",sizeof(a[0]));//第一行 16

printf("%d\n",sizeof(a[0]+1));//首元素地址 4/8

printf("%d\n",sizeof(*(a[0]+1)));//这里找到的是第一行第二个元素 4

printf("%d\n",sizeof(a+1));//第二行的地址 4/8

printf("%d\n",sizeof(*(a+1)));//第二列 16

printf("%d\n",sizeof(&a[0]+1));//地址 4/8

printf("%d\n",sizeof(*(&a[0]+1))); //4

printf("%d\n",sizeof(*a));//a就是首元素地址,16

printf("%d\n",sizeof(a[3]));//16

图解

  • printf("%d\n",sizeof(a[0]));//第一行 16

C语言进阶之旅 (11.5)指针下 提升篇_第11张图片>printf("%d\n",sizeof(*(a[0]+1)));//这里找到的是第一行第二个元素 4
C语言进阶之旅 (11.5)指针下 提升篇_第12张图片
printf("%d\n",sizeof(*(a[0]+1)));//这里找到的是第一行第二个元素 4

  • printf("%d\n",sizeof(a[3]));//16
  • sizeof是不参与运算的,他只求元素类型,不会访问内存
  • 栗子:
  • 我在路上看到一个女的,我第一反应肯定觉得她是女的,我不去深入了解那么他就是女的,假如我上去要了微信他一说话,女装大佬想了想
    C语言进阶之旅 (11.5)指针下 提升篇_第13张图片

题 6

int main() {
     
    int a[5] = {
      1, 2, 3, 4, 5 };
    int *ptr = (int *)(&a + 1);
    printf( "%d,%d", *(a + 1), *(ptr - 1));
    return 0;
}

C语言进阶之旅 (11.5)指针下 提升篇_第14张图片

题 7

  • 结构体大小是20
struct Test
{
     
	int Num;
	char* pcName;
	short sDate;
	char cha[2];
	short sBa[4];
}*p;
//假设p 的值为0x100000。 如下表表达式的值分别为多少? int main()
{
     
	printf("%p\n", p + 0x1);//0x100014
	printf("%p\n", (unsigned long)p + 0x1);//100001
	printf("%p\n", (unsigned int*)p + 0x1);//100004
	return 0;
}

图解

  • printf("%p\n", p + 0x1);
    C语言进阶之旅 (11.5)指针下 提升篇_第15张图片
  • printf("%p\n", (unsigned long)p + 0x1);
    内存看他就是以无符号看待
    C语言进阶之旅 (11.5)指针下 提升篇_第16张图片
  • printf("%p\n", (unsigned int*)p + 0x1);
    内存看他是以无符整型指针看待
    C语言进阶之旅 (11.5)指针下 提升篇_第17张图片

题8

  • 结果是:4,2
int main() {
     
    int a[4] = {
      1, 2, 3, 4 };
    int *ptr1 = (int *)(&a + 1);//加整个地址
    int *ptr2 = (int *)((int)a + 1);//首元素加1
    printf( "%x,%x", ptr1[-1], *ptr2);
    
    return 0;
}

图解:
C语言进阶之旅 (11.5)指针下 提升篇_第18张图片

解析这段代码

int *ptr1 = (int *)(&a + 1);
&a是整个数组的地址那么要存他就得 用int (*)a[5],然后给ptr的话,‍♂️
所以强制类型转换成int *

题9

  • 看清楚里面是括号,括号,括号
  • 那么他的参数就是1,3,5,
#include 
int main() {
     
    int a[3][2] = {
      (0, 1), (2, 3), (4, 5) };
    int *p;
    p = a[0];
    printf( "%d", p[0]);
return 0; }

题 10

  • 二维数地址给p,可以接收,但是他是看待数组的方式是4个一行
  • 指针减指针得到的是元素个数
  • 结果:
  • 4,-4
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;
}

蓝色是p,红色是a
在这里插入图片描述

题 11

  • 存的是常量字符串,那么系统就会在内存中各自开辟一块空间
  • a是数组名,里面存的是每个字符串的地址
  • 结果:
  • at
int main()
{
     
int a[]={
     "work","at","alibaba"};
char **pa =a;
pa++;
printf("%s",*pa);
}

C语言进阶之旅 (11.5)指针下 提升篇_第19张图片

题12

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;
}
  • printf("%s\n", **++cpp);
    前置加加,然后在解引用
    C语言进阶之旅 (11.5)指针下 提升篇_第20张图片

printf("%s\n", *--*++cpp+3);
优先级
解读:

  • ++cpp,在上面的基础加1
  • *++cpp
  • *–*cpp
  • *–*cpp+3
    C语言进阶之旅 (11.5)指针下 提升篇_第21张图片

printf("%s\n", *cpp[-2]+3);==(*(*p)-2)+3

  • 先和[]结合cpp-2
    在解引用cpp
    在加3
    C语言进阶之旅 (11.5)指针下 提升篇_第22张图片

printf("%s\n", cpp[-1][-1]+1);==((cpp-1)-1)+1
cpp-1
解引用cpp
cpp-1找到n的地址
n在+1
C语言进阶之旅 (11.5)指针下 提升篇_第23张图片

总结

  • ok,到了这里那么指针就学完了
  • 上面的题需要好好吸收,吸收,吸收
  • 数组指针和指针数组区分
  • 就看里面的名字和谁先结合,如果和[]那么就是指针数组,如果和*结合就是数组指针,先和谁结合那个结合名次就放在后面

有错请直接指出,评论区,私信或qq(1696912943)

持续更新………………

你可能感兴趣的:(c语言,指针)