【C语言】3天速刷C语言(指针进阶)

时间: 2024-11-10 admin IT培训

【C语言】3天速刷C语言(指针进阶)

【C语言】3天速刷C语言(指针进阶)

字符指针

在指针类型中我们知道有一种指针类型为字符指针char*;

一般使用:

int main()
{char ch = 'w';char *pc = &ch;*pc = 'w';return 0;
}

还有一种使用方式:

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

代码char* pstr = “hello bit.”;特别容易让我们以为是把字符串hello bit 放到字符指针pstr里面,但是本质是把字符串首字符的地址放到了pstr中。

指针数组

指针数组就是一个存放指针的数组。

数组指针

数组指针的定义

数组指针一定是指针!

实例:int (*p)[10];

*p被括号括起来优先级高于数组,指向的是一个大小为10的整型数组。所以p是一个指针指向一个数组,顾名思义数组指针。正常情况下[]优先级高于*,一定要加上括号才可以命名数组指针。

&数组名VS数组名

&arr表示的是数组的地址,而不是数组首元素的地址。

数组地址+1会跳过整个数组的大小,而首元素的地址+1只是跳过一个类型。

数组指针的使用

#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;
}

函数指针

看一段代码先

#include <stdio.h>
void test()
{printf("hehe\n");
}
int main()
{printf("%p\n", test);printf("%p\n", &test);return 0;
}

输出两个地址

这俩地址都是test的地址,那我们想要把函数保存起来该咋弄?

首先能给存储地址就得是指针,存储函数的地址,就得是函数指针!(给这给这呢)

明确一个概念:函数指针是指针!

void (*fun)();

指针的优先级比较低,所以还是要给他括起来。

函数指针数组

数组是存放一个相同类型数据的存储空间,比如指针数组:

int *arr[100];

数组的每个元素都是int*;

那么要把函数的地址村到一个数组中去,那这个数组就叫函数指针数组,函数指针数组又是如何定义的呢?

int (*parr[100])();

数组的内容是 int (*)();函数指针!

函数指针数组的用途:转移表

例子:计算器

#include <stdio.h>
int add(int a, int b)
{return a + b;
}
int sub(int a, int b)
{return a - b;
}
int mul(int a, int b)
{return a*b;
}
int div(int a, int b)
{return a / b;
}
int main()
{int x, y;int input = 1;int ret = 0;int(*p[5])(int x, int y) = { 0, add, sub, mul, div }; //转移表while (input){printf( "*************************\n" );printf( " 1:add           2:sub \n" );printf( " 3:mul           4:div \n" );printf( "*************************\n" );printf( "请选择:" );scanf( "%d", &input);if ((input <= 4 && input >= 1)){printf( "输入操作数:" );scanf( "%d %d", &x, &y);ret = (*p[input])(x, y);}elseprintf( "输入有误\n" );printf( "ret = %d\n", ret);}return 0;
}

指向函数的指针数组的指针

这里开始可以根据名字自己写一下了

从后往前看

指针:(*)->
指针数组的指针:(*(* arr[100]))->
指向函数:int (*(*arr[100]))();

如果能根据名字有着清晰思路并且把它的形状显示出来,那么对于任何形式的指针、数组、函数的排列你都没啥问题了!

回调函数

回调函数就是一个通过函数指针调用的函数,如果你把函数的指针(地址)作为参数传给里那个一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或者条件发生时由另外的一方调用的,用于对该事件或条件进行相应。

#include <stdio.h>
//qosrt函数的使用者得实现一个比较函数
int int_cmp(const void * p1, const void * p2)
{return (*( int *)p1 - *(int *) p2);
}
int main()
{int arr[] = { 1, 3, 5, 7, 9, 2, 4, 6, 8, 0 };int i = 0;qsort(arr, sizeof(arr) / sizeof(arr[0]), sizeof (int), int_cmp);for (i = 0; i< sizeof(arr) / sizeof(arr[0]); i++){printf( "%d ", arr[i]);}printf("\n");return 0;
}

运用回调函数实现qsort函数(冒泡)

#include <stdio.h>
int int_cmp(const void * p1, const void * p2)
{return (*( int *)p1 - *(int *) p2);
}
void _swap(void *p1, void * p2, int size)
{int i = 0;for (i = 0; i< size; i++){char tmp = *((char *)p1 + i);*(( char *)p1 + i) = *((char *) p2 + i);*(( char *)p2 + i) = tmp;}
}
void bubble(void *base, int count , int size, int(*cmp )(void *, void *))
{int i = 0;int j = 0;for (i = 0; i< count - 1; i++){for (j = 0; j<count-i-1; j++){if (cmp ((char *) base + j*size , (char *)base + (j + 1)*size) > 0){_swap(( char *)base + j*size, (char *)base + (j + 1)*size, size);}}}
}
int main()
{int arr[] = { 1, 3, 5, 7, 9, 2, 4, 6, 8, 0 };//char *arr[] = {"aaaa","dddd","cccc","bbbb"};int i = 0;bubble(arr, sizeof(arr) / sizeof(arr[0]), sizeof (int), int_cmp);for (i = 0; i< sizeof(arr) / sizeof(arr[0]); i++){printf( "%d ", arr[i]);}printf("\n");return 0;
}