指针数组
基本介绍
要让数组的元素 指向 int 或其他数据类型的地址(指针)。可以使用
指针数组
指针数组的定义
数据类型 *指针数组名[大小]
1)比如:int *ptr[3];
2)ptr声明为一个指针数组
3)由 3 个整数指针组成。因此,ptr中的每个元素,都是一个指向 int 值的指针
void main(){
char* pStr = "hello word!";//定义一个字符指针指向一个字符串
char* books[] = {//定义一个指向字符的指针数组来存储字符串列表,指针数组的元素指向每个字符串的首地址
"hello wawa",
"hello haha",
"hello henhen",
"hello hihi",
};
int i,bookslen;
bookslen = sizeof(books)/sizeof(books[0]);
for(i=0;i<bookslen;i++){
printf("books[%d] = %s,第九个字符 = %c\n",i,books[i],*(books[i]+8));
//输出的内容是books[%d] = 字符串,第九个字符 = 字符,字符串的输出直接就是books[i](地址)
//反观数组也是如此printf("%s",arr);%s表明输出字符串,arr退化为指针为字符数组首地址
//而给首地址加上”*“,通过取值符号取出首地址的字符,通过加减地址可以取出组成字符串的其他字符
//字符串中字符的输出则需要带上”*“即*(books[]+...)
}
//字符指针与这里指向字符的指针数组里面的元素是一样的
printf("pStr = %s\n",pStr);//输出字符串
printf("pStr = %c\n",*pStr);//输出首字符
printf("pStr = %p\n",pStr);//输出首地址
printf("pStr = %p\n",pStr+1);//输出次地址
printf("pStr = %c\n",*(pStr+1));//输出次字符
printf("pStr = %p\n",pStr+2);
}
返回指针的函数
C语言 允许函数的返回值是一个指针(地址),这样的函数称为指针函数。
指针函数注意事项和细节
1)用指针作为函数返回值时需要注意,函数运行结束后会销毁在它内部
定义的所有局部数据,包括局部变量、局部数组和形式参数,函数返回的
指针不能指向这些数据
2)函数运行结束后会销毁该函数的所有局部数据,这里所谓销毁并不是将
局部数据所占用的内存全部清零,而是程序放弃对它的使用权限,后面的代
码可以使用这块内存(此内存被开辟在栈中,后面的函数即可能会使用)
3)C语言不支持在调用函数时返回局部变量的地址,如果确实有这样的需求
,需要定义局部变量为static变量(这里static变量会被存放在静态数据区,
不会被改变故即使栈中函数数据销毁,对static变量也没有任何影响)
#include<stdio.h>
int *func(){
int n = 100;//局部变量,在func返回时,就会销毁
return &n;
}
int main(){
int* p = func();//返回指针
int n;
printf("~~~~~~~~~~~~~~");
//函数后边跟个其他函数就会占用栈中销毁func()数据后的内存,从而输出不了100
//如果没有任何函数跟在后面,那么仍然可以输出100,因为数据只是使用权限没有了,并没有清零
n = *p;
printf("\nvalue = %d\n",n);//是否输出100?不一定
return 0;
}
函数指针
基本介绍
1)一个函数总是占用一段连续的内存区域,函数名在表达式中有时也会被
转换为函数所在的内存区域的首地址,这和数组名非常类似。
2)把函数的这个首地址(或称入口地址)赋予一个指针变量,使指针变量指向函数所在的内存区域,然后通过指
针变量就可以找到并调用该函数。这种指针就是**函数指针**
函数指针定义
returnType(*pointerName)(param list);
1)returnType 为函数指针指向的函数返回值类型
2)pointerName 为函数指针名称
3)param list 为函数指针指向的函数的参数列表
4)参数列表中可以同时给出参数的类型和名称,也可以只给出参数的类型,省略参数的名称
5)注意()的优先级高于 * ,第一个括号不能省略,如果写作 returnType
*pointerName(param list),它表明函数的返回值类型为returnType *
#include<stdio.h>
//说明
//1.max 函数
//2.接受两个int,返回较大数
int max(int a,int b){
return a>b?a:b;
}
int main(){
int x,y,maxVal;
//说明 函数指针
//1.函数指针的名字 pmax
//2.int 表示该函数指针指向的函数是返回int类型
//3.(int,int)表示 该函数指针指向的函数形参是接受两个int
//4.在定义函数指针时,也可以写上形参名 int(*pmax)(int x,int y)=max;
int(*pmax)(int,int) = max;
printf("Input two numbers");
scanf("%d %d",&x,&y);
//(*pmax)(x,y)通过函数指针去调用 函数max
maxVal = (*pmax)(x,y);
printf("Max value:%d pmax=%p pmax本身的地址=%p\n",maxVal,pmax,&pmax);
}
回调函数
1)函数指针变量可以作为某个函数的参数来使用的,回调函数就是一个通
过函数指针调用的函数
2)简单的讲:回调函数是由别人的函数执行时调用你转入的函数(通过函
数指针完成)
应用举例
#include<stdio.h>
#include<stdlib.h>
//回调函数
//1.int(*f)(void)
//2.f 就是函数指针,它可以接收的函数是(返回int,没有形参的函数)
//3.f 在这里被initArray 调用,充当了回调函数角色
void initArray(int *array,int arraySize,int(*f)(void)){
int i;
//循环 10
for(i=0;i<arraySize;i++){
array[i] = f();//通过函数指针调用了 getNextRandomValue函数
}
}
//获取随机值
int getNextRandomValue(void){
return rand();//rand 系统函数,会返回一个随机整数
}
int main(){
int myarray[10],i;//定义一个数组和 int
//说明
//1.调用initArray函数
//2.传入了一个函数名getNextRandomValue(地址),需要使用函数指针接受
initArray(myarray,10,getNextRandomValue);
//输出赋值后的数组
for(i=0;i<10;i++){
printf("%d ",myarray[i]);
}
printf("\n");
return 0;
}
回调函数注意事项
1)p是指向函数的指针变量,它只能指向函数的入口处而不可能指向函数中间的某一条
指令,因此不能用*(p+1)来表示函数的下一条指令。
2)如果要用指针调用函数,就必须先使用指针变量指向该函数。如:p = max
3)在给函数指针变量赋值时,只须给出函数名而不必给出参数,例如:
p = max; //将函数的入口地址赋给p
因为是将函数入口地址赋给p,而不牵涉实参与形参的结合问题。如果写成 p = max(a,b);
就错了。p = max(a,b)的作用是将调用max函数所得到的函数值赋给p,而不是将函数入
口地址赋给p
4)用函数指针变量调用函数时,只须将 (*p) 代替函数名即可 (p为指针变量名),在 (*p)
之后的括号中根据需要写上实参。例如:c = (*p)(a,b);
5)用函数名调用函数,只能调用所指定的一个函数,而通过指针变量调用函数比较灵
活,可以根据不同情况先后调用不同的函数。(在一个程序中,一个指针变量可以先后
指向不同类型的不同函数)
指针的注意事项和细节
1)指针变量存放的是地址,从这个角度看指针的本质就是地址。
2)变量声明的时候,如果没有确切的地址赋值,为指针变量赋给一个NULL值是好的编
程习惯。
3)赋给NULL值的指针被称为空指针,NULL指针是一个标准库<stdio.h>中的值为零的常
量 #define NULL 0