主要内容:
1. 字符指针
1.字符指针
指针类型为字符指针char*;
一般使用:
int main()
{
char ch='w';
char *pc=&ch;
*pc='w';//给指针pc解引用
return 0;
}
还有一种使用方式如下;
int main()
{
const char* pstr="hello";//这里不是把hello整个字符串放到pstr指针变量里,而是把字符串的首字符的地址放到pstr中。
printf("%s\n",pstr);//拿到首字符的地址,就可以打印整个字符,直到遇到\0,打印停止。
return 0;
}
例题分析:
#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
因为str1与str2是两个数组的数组名,数组名表示地址,所以两个数组地址不一样,即str1与str2不一样;str3与str4是两个字符串指针,且str3与str4指向的是同一个常量字符串。c/c++会把常量字符串存储到单独的一个内存区域,当几个指针指向同一个字符串的时候,他们实际指向同一块内存。但是用相同的常量字符串去初始化不同的数组的时候会开辟出不同的内存块。所以,1与2不同,3与4相同。
2.指针数组
3.数组指针
3.1 数组指针的定义:指向一个数组的指针
p1是一个整形指针数组,数组里面存放了十个整形指针。p2是一个数组指针,指向的是一个大小为10个整形的数组// 这里要注意: [] 的优先级要高于 * 号的,所以必须加上()来保证 p 先和 * 结合。
3.2 &数组名VS数组名
&arr和arr的值是相同的,但是意义是不一样的。&arr表示数组地址,而不是数组数组首元素的地址。int arr[10] = { 0 } ,&arr的类型是:int(*)[10],是一个数组指针类型,给数组的地址加一,就会跳过整个数组。数组名表示首元素的地址。
3.3 数组指针的使用
数组指针指向的是数组,那数组指针中存放的就应该是数组的地址。
补充-----eg:arr[3][5] 取地址数组名表示整个数组的地址。数组名arr,表示首元素地址;但是二维数组的首元素是二维数组的第一行,所以,调用函数的时候传参时,传二维数组的数组名,其实相当于第一行的地址,是一维数组的地址,可以用数组指针来接收。
所以,在接收的时候可以有两种方式
1.void print_arr1(int arr[3][5], int row, int col)
2.void print_arr2 ( int ( * arr )[ 5 ], int row , int col )
补2:对于整形数组的打印不能一次性全部打印,因为没有结束标志,只有字符串数组才能得到首元素地址然后才能一次性全部打印。
补3:如果有int arrr[10], 将 int(*p)[10]=arr进行强制类型转换
int arrr[10] arrr的类型是int*; int(*p)[10]的p的类型是int(*)[10],所以强制类型转化的结果为int(*p)[10]=(int(*)[10])arr。 强转要放在括号里。
4.数组参数、指针参数
4.1一维数组传参
#include <stdio.h>void test ( int arr []) //可以,只说明类型,不说明大小也可以{}void test ( int arr [ 10 ]) //可以,大小类型均已说明。前两种是数组传参数组接收{}void test ( int* arr ) //可以,传入的参数是地址可用指针接收。第三种是数组传参指针接收。{}void test2 ( int* arr [ 20 ]) //可以,类型是int*[],可不写大小。{}void test2 ( int** arr ) //可以,传入指针的地址可以用二级指针接收{}int main (){int arr [ 10 ] = { 0 };int*arr2[20] = {0}; //指针数组,数组的每个元素的类型都是int*
test ( arr );test2 ( arr2 ); //传入数组名表示首元素地址,所以传入的是指针的地址}
4.2二维数组传参
补:int*arr[3][3]={1};int p=**arr;printf("%d",p);//arr是二维数组的数组名,表示首元素地址,即第一行的地址,所以,*arr表示第一行为arr[0],arr[0]为第一行数组的数组名,表示首元素的地址,即第一个元素的地址,所以**arr为arr[0][0]为1.
4.3一级指针传参
指针传参指针接收
当一个函数的参数部分为一级指针的时候,函数能接收什么参数?void test1 ( int * p ){}int a=10;int *p=&a;int arr[10];test(arr);//地址test(&a);//地址test(p);//指针
4.4二级指针传参
二级指针传参二级指针接收
5.函数指针
int add(int x,int y)
{
return x+y;
}
int main()
{
int(*pf)(int,int)=&add;
int ret=(*pf)(2,3);//函数调用
//pf是一个存放函数地址的指针变量--函数指针
//&函数名和函数名都是函数的地址
eg:
//0被当作函数的地址,再进行接应用,对函数进行调用。
void (* signal(int , void(*)(int) ) ) (int);-------其实可以写为void(*)(int) singal(int,void(*)(int))//该代码是一次函数的声明。声明的函数名字叫singal,此函数有两个参数,第一个是int类型,第二个是函数指针类型,该函数指针能够指向的那个函数的参数是int返回类型是void。singal函数的返回类型是一个函数指针,该函数指针能够指向的那个函数的参数是int,返回类型是void.
6.函数指针数组
#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);
}
else
printf( "输入有误\n" );
printf( "ret = %d\n", ret);
}
return 0;
}
将函数的地址存到函数指针数组中,是对switch case语句的优化,避免冗长。
7.指向函数指针数组的指针
int main()
{
int arr[10];
int (*pa)[10]=&arr;//数组指针
int(*pf)(int,int);//函数指针
int (*pf[5])(int,int);//函数指针数组
int(*(*ppf)[5](int,int)=&pf;//指向函数指针数组的指针
8.回调函数(补充void*用法)
回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。
例如:使用qsort函数
void qsort(void base,//数组地址
size_t num,//元素个数
size_t width,//一个元素占的字节数
int (*cmp)(const void* elem1,//需要比较的第一个元素的地址
const void*elme2)//第二个元素的地址
);
//进行比较
int cmp_int(const void*e1,const void*e2)//参数和返回类型与规定的一致
{
//由于void*不能直接用,所以要先进行类型转换
return (*(int*)e1-*(int*)e2);
//返回值是 e1<e2 小于0 相等返回等于0 大于返回大于0
int main()
{
int arr[]={9,8,7,6,5,4,3,2,1,0};
int sz=sizeof(arr)/sizeof(arr[0]);
qsort(arr,sz,sizeof(arrr[0]),cmp_int);
int i=0;
for(i=0,i<sz,i++)
{
printf("%d",arr[i]);
}
return 0;
}
//补充:
//因为不知道会用qsort函数去比较什么类型的数据,void* 是无具体类型的指针,
int a=10;
float f=5.5f;
int* p=&a;//可以
//p=&f;//类型不兼容,p是int,f是float
void* pp=&f;//可以
pp=&a;//可以,任意谁的地址都可以放到pp中,是一个通用指针,无具体类型
void* 的指针是没办法直接解引用的,所以,在用的时候需要先进行类型转换