03-指针进阶

一. 字符指针

1.1 使用方式一

  • 操作字符
int main()
{
 char ch = 'w';
 char *pc = &ch;
 *pc = 'p';
 return 0;
}

1.2 使用方式二

  • 标识字符串: 这里值得注意的是, "hello bit"是把h的地址给到pstr, 并且"hello bit."是一个字符串常量保存在静态区中其值是不能修改的, 使用const可以将运行时错误变成编译时错误. 使错误能更好的被发现
#include <stdio.h>

int main()
{
 const char* pstr = "hello bit.";//这里是把一个字符串放到pstr指针变量里了吗?
 printf("%s\n", pstr);
 return 0;
}

1.3 面试考点

  • 数组的创建是在栈区, str1和str2是两个不同的变量. 而str3和str4保存的地址都是相同的, 即"hello bit."的首字符的地址.
#include <stdio.h>
int main()
{
 char str1[] = "hello bit.";
 char str2[] = "hello bit.";
 const char *str3 = "hello bit.";
 const 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;
}

/*
运行结果: 
str1 and str2 are not same
str3 and str4 are same
*/

二. 数组指针

2.1 数组指针的表示形式

  • 需要和指针数组的概念做区分, 数组指针是一个指针指向数组的指针, 二指针数组是数组用于保存指针的数组.
int* p[10];    //这里p先和[]结合, 表示数组. 然后数组元素的类型时int*
int (*p)[10];  //这里p先和*结合为*p表示指针, 指针指向一个数组[]该数组大小10个元素, 且元素类型为int

2.2 数组指针的使用

  • 通常应用在操作二维数组的情景中, 需要注意的是二级指针是无法操作二维数组的, 以a[i][j]为例. 32位机上指针+1永远跳过4个字节, 而二维数组中a[i + 1]会跳过j*4个字节大小的空间. 二级指针无法满足二维数组特性.
//用法一:
#include <stdio.h>
int main()
{
 int arr[10] = {1,2,3,4,5,6,7,8,9,0};
 int (*p)[10] = &arr;//把数组arr的地址赋值给数组指针变量p
 //但是我们一般很少这样写代码
 return 0;
}

//用法二:
#include <stdio.h>
void print_arr1(int arr[3][5], int row, int col)
{
 int i = 0;
 for(i=0; i<row; i++)
 {
 for(j=0; j<col; j++)
 {
 printf("%d ", arr[i][j]);
 }
 printf("\n");
 }
}
void print_arr2(int (*arr)[5], int row, int col)
{
 int i = 0;
 for(i=0; i<row; i++)
 {
 for(j=0; j<col; j++)
 {
 printf("%d ", arr[i][j]);
 }
 printf("\n");
 }
}
int main()
{
 int arr[3][5] = {1,2,3,4,5,6,7,8,9,10};
 print_arr1(arr, 3, 5);
 //数组名arr,表示首元素的地址
 //但是二维数组的首元素是二维数组的第一行
 //所以这里传递的arr,其实相当于第一行的地址,是一维数组的地址
 //可以数组指针来接收
 print_arr2(arr, 3, 5);
 return 0;
}

2.3 内容拓展

  • 试着解释int (*p[10])[5];的含义
    int(*p[10])[5];                  //大小为10的数组其数组元素为数组指针,指向大小为5的整形数组.
               
	int arr[5] = { 1, 2, 3, 4, 5 };  

	p[0] = &arr;                     //p[0]是数组指针, 将数组arr的地址给p[0];

	printf("%d", *(*p[0]));          //这里*(p[0])也就相当于*(&arr), 得到arr首元素地址, 然后*(*p[0])相当于*arr得到arr[0];

三. 函数指针

3.1 区分函数指针和指针函数

  • 首先看变量先与哪个部分结合, 本质就是什么.
void* func1();    //这里func1与()结合表示一个函数, 该函数类型为void*, 表示返回值为void* 的函数。 (返回类型为指针)
void (*func2)();  //这里func2与*结合为*func2表示一个指针, 指针指向一个返回值为void的函数void ();

3.2 看两个有趣的代码

  • 及时两段代码的含义
//代码一
(*(void (*)())0)();  //首先是将0强制类型转换为(一个指向void类型的函数的指针类型), 此时0就是一个函数地址, 然后*()0, 就是找到地址为0的这个函数去调用.
//代码二
void (*signal(int , void(*)(int)))(int);

3.2 函数指针数组

  • 要将函数地址放进一个数组中, 该数组如何定义
int (*p[10])();  // 首先p是一个数组, 数组元素都是指针, 指向返回值类型为int的函数.

四. 回调函数

4.1 什么是回调函数

  • 将函数A作为参数传递给函数B当B被调用时去回调函数A, 此时A就被称为回调函数, 该机制称为回调机制.
void testA(){};

void testB(void (*pf)()){};

int main()
{
  testB(&testA); //将函数A的地址作为参数传递给函数B

return 0;
}

4.2 应用案例, 实现qsort可满足任意类似的数组进行冒泡排序

#include<stdio.h>

void myQSort(void* arrAdd, int arrSize, int arrWidth, void (*cmp)(void* e1, void* e2));
int cmpFunctionInt(void* e1, void* e2);
void changeAdd(char* e1, char* e2, int width);

int main()
{
	int arr[] = { 1, 3, 5, 2, 4, 8, 9, 11, 6, 14, 7, 12, 13, 10 };
	int sz = sizeof(arr) / sizeof(int);

	myQSort(arr, sz, sizeof(int), cmpFunctionInt);

	for (int i = 0; i < sz; i++)
	{
		printf("%d, ", arr[i]);
	}

	return 0;
}

void changeAdd(char* e1, char*e2, int width)
{
	char e;
	for (int i = 0; i < width; i++)
	{
		e = *e1;
		*e1 = *e2;
		*e2 = e;
		e1 ++;
		e2 ++;
	}
}

int cmpFunctionInt(void* e1, void* e2)
{
	return (int*)e1 - (int*)e2;
}

void myQSort(void* arrAdd, int arrSize, int arrWidth, void (*cmp)(void* e1, void* e2))
{

	for (int i = 0; i < arrSize; i++)
	{
		for (int j = i; j < arrSize - 1; j++)
		{
			if (*((char*)arrAdd + j * arrWidth) > *((char*)arrAdd + (j + 1) * arrWidth))
			{
				changeAdd((char*)arrAdd + j * arrWidth, (char*)arrAdd + (j + 1) * arrWidth, arrWidth);
			}
		}
	}
}
posted @   一步一磕头的菜鸡  阅读(11)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
点击右上角即可分享
微信分享提示