目录
一. 字符指针
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);
}
}
}
}
标签:03,arr,进阶,int,void,char,数组,指针
From: https://www.cnblogs.com/Deng-S/p/17500266.html