C语言——指针(进阶)

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C语言——指针(进阶)相关的知识,希望对你有一定的参考价值。

  • 字符指针
  • 数组指针
  • 指针数组
  • 数组传参和指针传参
  • 函数指针
  • 函数指针数组
  • 指向函数指针数组的指针
  • 回调函数


一:字符指针

指针类型中字符指针     char* 

#include<stdio.h>
int main()

char* pa = "good bye";
//printf("%c\\n",*pa);//本质是把字符串的首字符的地址存储在pa中

char* pa = "good bye";
char arr[] = "good bye";
printf("%s\\n",pa);
printf("%s\\n",arr);
return 0;

例题:

#include <stdio.h>
int main()

char str1[] = "game";
char str2[] = "game";
//两个不同数组,新创造的空间不同
const char* str3 = "computer";
const char* str4 = "computer";
//常量字符串是不能改的,只会存一份,所以两个指针变量都指向同一个地址
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


二:数组指针(指向数组的指针)

1.数组指针

#include<stdio.h>
int main()

int a = 10;
int* pa = &a;//整形指针

char b = q;
char* pb = &b;//字符指针

int arr[5] = 1,2,3,4,5;
int (*parr)[5] = &arr;//由于[]的优先级高于*,得带括号

从parr处开始,先与*结合,说明P 是一个指针  然后再与[]结合,说明指针所指向的内容是一个数组,然后再与int 结合,说明数组里的元素是整型的.所以parr 是一个指向由整型数据组成的数组的指针

(怎么判断呢?    看变量先与谁结合

2:&数组名和数组名

C语言——指针(进阶)_数组

差分别为4 ,40。

&arr取的是整个数组的地址,而arr是数组首元素的地址

3:应用

//二维数组
#include<stdio.h>
void print1(int arr[3][5], int m, int n)

int i = 0;
int j = 0;
for (i = 0; i < m; i++)

int j = 0;
for (j = 0; j < n; j++)

printf("%d ", arr[i][j]);

printf("\\n");


//数组指针
void print2(int(*arr)[5], int r, int c)

int i = 0;
for (i = 0; i < r; i++)

int j = 0;
for (j = 0; j < c; j++)

printf("%d ", *(*(arr + i) + j));

printf("\\n");


int main()

int arr[3][5] = 1,2,3,4,5,2,3,4,5,6,3,4,5,6,7 ;
print1(arr, 3, 5);
print2(arr, 3, 5);
return 0;

//print1,2
//1 2 3 4 5
//2 3 4 5 6
//3 4 5 6 7

注意:

int(*parr[10])[5];
//首先parr[10]是个数组,去掉parr[10]后为指向的类型
//parr是以个存放数组指针的数组,能存放10个数组指针
//每个数组指针都能指向一个数组,数组有五个元素,均为int类型


三:指针数组(是一个存放指针的数组

#include<stdio.h>
int main()

//指针数组-数组中存放指针(地址)
int a = 10;
int b = 20;
int c = 30;
int d = 40;
int* arr[5] = &a,&b,&c,&d;
int i = 0;
for (i=0;i<4;i++)

printf(" %d\\n ", *(arr[i]));

#include<stdio.h>
int main()

int a1[] = 1,2,3,4,5 ;
int a2[] = 2,3,4,5,6 ;
int a3[] = 3,4,5,6,7 ;
int* arr[3] = a1,a2,a3 ;//代表各数组首元素的地址
int i = 0;
for (i=0;i<3;i++)//行

int j = 0;
for (j=0;j<5;j++)//列

printf("%d ", *(arr[i] + j));
//可以写成 printf("%d ", arr[i][j]);

printf("\\n");

return 0;

//1 2 3 4 5
//2 3 4 5 6
//3 4 5 6 7


四:数组传参和指针传参

1:一维数组传参

#include <stdio.h>
void test1(int arr[10])//可以

void test1(int arr[])//可以,元素个数可以省略

void test1(int* arr)//可以,指针


void test2(int* arr[20])//可以,存放int* 的整型指针数组

void test2(int** arr)//可以,二级指针

int main()

int arr1[10] = 0;
int* arr2[10] = 0;//存放int*的数组
test1(arr1);

test2(arr2); //指向int* 的首元素地址


2:二维数组传参

实参     只用填数组名 就行

形参可以为   二维数组  或 指针

//二维数组
void test(int arr[3][5])//可以

void test(int arr[][])//错误。行可省略,列是不能省的

void test(int arr[][5])//可以

//指针
void test(int* arr)//不行。接收第一行的地址,第一行是5个整形的数组,不能用指针接收

void test(int* arr[5])//不行。这是指针数组,得要整型数组指针才行

void test(int(*arr)[5])//可以。为整型数组指针

void test(int** arr)//不行。

int main()

int arr[3][5] = 0 ;
test(arr);
return 0;


3:一级指针传参

#include <stdio.h>
void print(int* pstr, int sz) //用一级指针接收

int i = 0;
for (i = 0; i < sz; i++)

printf("%d ", *(pstr + i));



void test(char* p)


int main()

int arr[7] = 2,0,2,2,10,0,2 ;
int* p = arr;
int sz = sizeof(arr) / sizeof(arr[0]);
print(p, sz);//p是一级指针

char ch = a;
test(&ch);//char*
//char* p1 = &ch;
//test(p1);
return 0;


4:二级指针传参

#include <stdio.h>
void test(int** pstr) //二级指针接收

printf("num = %d\\n", **pstr);//a的值

int main()

int a = 10;
int* pa = &a;//pa是一级指针
int** ppa = &pa;//ppa是二级指针
test(ppa);//二级指针传参

test(&pa);取一级指针的地址就是二级指针

int* arr[10] = 0;
test(arr);//也可以,传存放一级指针的数组
//,传的是整形指针数组的首元素的地址,而首元素为int*类型,结果为二级指针传参
return 0;


五:函数指针(存放函数地址的指针)

&函数名——取出函数的地址

注意:数组名 != &数组名

         函数名   == &函数名

                              int (*pf)(int,int) = &Add;

#include<stdio.h>
int Add(int x,int y)

return x + y;

int main()

printf("%p\\n", Add);
printf("%p\\n", &Add);
//地址相同,意义一样,无区别

int (*pf)(int,int) = &Add;// 函数指针中,由于()优先级高于*,得带括号
int ret = (*pf)(7,5);//通过函数指针调用函数.1
//int ret = pf(7,5);//2
//int ret = Add(7,5);//3
//1,2,3都一样。*的作用不大,可有可无,但只能在函数指针中这样
//int ret = *pf(7,5);//这样是不行的,等于对函数的结果12进行解引用。若加*得括起来
printf("%d\\n",ret);//12
return 0;

例子:

#include<stdio.h>
void test(char* str)


int main()

void (*pt)(char*) = &test;//与函数要对应
return 0;


六:函数指针数组(存放函数指针的数组

它可以存放多个参数相同,返回类型相同 的函数地址

                          int (*arr[3])(int, int) = Add,Sub,Mul;

#include<stdio.h>
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 main()

//parr就是 函数指针数组
int (*parr[3])(int, int) = Add,Sub,Mul;
return 0;


写一个计算器(加,减,乘,除):

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

#include<stdio.h>
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;


void menu()

printf("********************************\\n");
printf("**** 1.Add 2.Sub ****\\n");
printf("**** 3.Mul 4.Div ****\\n");
printf("**** 0.exit ********\\n");
printf("********************************\\n");

int main()

int input = 0;
do
menu();//菜单
//pfArr是函数指针数组
//转移表
int (*pfArr[5])(int, int) = NULL, Add, Sub, Mul, Div ;//

int x = 0;
int y = 0;
int ret = 0;
printf("请选择:>");
scanf("%d",&input);
if(input>=1 && input<=4)

printf("请输入2个数:>");
scanf("%d %d", &x, &y);
ret = (*pfArr[input])(x, y);
printf("%d\\n",ret);

else if(input == 0)

printf("退出程序\\n");

else

printf("选错了,重新选择");

while(input);
return 0;

,

七:指向函数指针数组指针

int(*p)(int,int);//函数指针
int(* p2[4])(int,int);//函数指针的数组

int(*(*p3)[4])(int,int);//取出函数指针数组的地址
//p3是一个指向函数指针数组的指针

补充:int arr[5];

数组元素类型:去掉数组名和元素个数 , 剩下的就是——>int

数组类型   :仅去掉数组名                        ——>int[5]     

   

八:回调函数

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


回调函数应用例子:

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;


void menu()

printf("***************************\\n");
printf("***** 1.add 2. sub ****\\n");
printf("***** 3.mul 4. div ****\\n");
printf("***** 0.exit ****\\n");
printf("***************************\\n");

//回调函数
int Cald(int (*pf)(int, int))

int x = 0;
int y = 0;
printf("请输入2个值:>");
scanf("%d %d", &a, &b);
return pf(x,y);


int main()

int input = 0;
int x = 0;
int y = 0;
int ret = 0;
do

menu();
printf("请选择:>");
scanf("%d", &input);
switch (input)

case 1:
ret = Cald(Add);//把Add函数指针传过去
//Add函数并不是直接调用的,而是通过函数指针调用的
printf("%d\\n", ret);
break;
case 2:
ret = Cald(Sub);//把Sub函数指针传过去
printf("%d\\n", ret);
break;
case 3:
ret = Cald(Mul);//把Mul函数指针传过去
printf("%d\\n", ret);
break;
case 4:
ret = Cald(Div);//把Div函数指针传过去
printf("%d\\n", ret);
break;
case 0:
printf("退出程序\\n");
break;
default:
printf("选错了,重新选择\\n");
break;

while (input);

qsort 库函数(进行快速排序的实现)

(得引用头文件    stdlib.h  )

void qsort (void* base,//void*能接收任意类型的地址,应用更加广泛;base中存放的是 待排序的数据里的第一个对象的地址
size_t num,//元素个数
size_t size,//一个元素占几个字节
int (*compar)(const void*,const void*)//用来比较待排序数据中的2个元素的函数
);

//
注意:int compareMyType (const void * a, const void * b)

if ( *(MyType*)a < *(MyType*)b ) return -1;
if ( *(MyType*)a == *(MyType*)b ) return 0;
if ( *(MyType*)a > *(MyType*)b ) return 1;

例子:用qsort函数进行排序

#include<stdio.h>
#include<stdlib.h>

int compar(const void* d1, const void* d2)

return *(int*)d1 - *(int*)d2 ;


void print_arr(int arr[],int sz)

int i = 0;
for(i=0;i<sz;i++)

printf("%d\\n",arr[i]);

printf("\\n");

int main()

int arr[10] = 9,8,7,6,5,4,3,2,1,0 ;
int sz = sizeof(arr)/sizeof(arr[0]);
qsort(arr,sz, sizeof(arr[0]), compar);//排序
print_arr(arr, sz);
return 0;


以后继续补充qsort函数内容



以上是关于C语言——指针(进阶)的主要内容,如果未能解决你的问题,请参考以下文章

C语言进阶笔记深入了解进阶指针

C语言进阶笔记深入了解进阶指针

C语言进阶笔记深入了解进阶指针

C语言进阶笔记深入了解进阶指针

C语言进阶——指针进阶(字符指针指针数组数组指针)

C语言进阶5——指针的进阶