C语言指针
指针
*的两种含义:
1. 在定义时表示 后面的变量是指针
2. 使用时表示取值(取指针地址的值)
不论指向的类型是什么,指针大小为4字节(64位为8字节 )
下列交换a b值的程序为什么错误?
原因是只交换了形参xy的值,在执行swap()函数后释放xy。
没有交换实参
如果要交换实参的值,必须要传地址
修改如下:
*x就是a , *y就是b。
野指针
int *p; //不能随意定义指针
如何合法使用内存?
1 系统分配
Int a ;
Int *p=&a;
2 用户申请内存(堆内存)
malloc(32);//动态内存分配,运行时才能找到一个内存使用
malloc()不清楚什么类型的返回值,所以干脆返回void类型
在申请内存时需要强制转换类型,如下:
char *str=(char *)malloc(32); //str指针指向了申请的32位内存
free(str);//用完内存后需要释放内存
str=NULL;//防止野指针
指针和数组
指针数组是数组,
数组指针是指针,如 int (*p)[5]; 一个指针占4个字节。

数组名为首元素的地址:
int *p = a; 和 int *p = &a[0]; 相同
a[i] 和 *(p+i) 相同
一维数组a[10],a表示首元素地址;
二维数组a[3][4],a表示首行地址(16字节),a[0]表示首行首元素地址(4字节)。
&a表示数组地址(48字节,12*4).
/*
问:如何不用3,4,直接用函数表示几行几列?
*/
/*
问:char str = "hello world";和 char *p = "hello world"; 区别?

//str++ 报错 数组名是常指针(地址常量),不能修改
//p++ 指向下一个元素e
//str[0] = ‘x’; 把str首元素改为x
//p[0] = ‘x’; 不能运行 字符串常量,不能被修改
//sizeof(str) = 5*4(字节长度) 32位操作系统
//sizeof(p) = 4
*/
/*
问:P1[0],p2[0],p3[0]的值分别是多少?
int a[5] = {1,2,3,4,5}; //设a的首地址为0x100
1.int *p1 = (int*)(&a + 1);
2.int *p2 = (int*)((int)a+1);
3.int *p3 = (int*)(a + 1);
1.&a表示数组的地址 a表示数组首元素地址
&a+1 表示跳过20字节,直接跳到下个数组;将数组指针转为(int*)型,指向下一个数组的首地址,由于下个数组没有定义,所以
P1[0]为野指针
2.P[2]先执行(int*)((int)a+1);,
将a的首地址0x100转为int型100,加一得101,再转为(int*)型0x101 进入a[0]的首地址的第二个字节。
P2[0]不合法
3.P3[0]为2, 就算不转 (a+1)也为(int*)类型
*/
指针和字符串
char *string[] = {"hello","world"};
printf("%s\n",string);
string是数组还是指针?(64位)
先括号,再char*,是数组,存放的内容为指针,指针型数组。
printf("%s\n",string); 能不能输出hello world?
string表示数组首元素地址,不能输出(野指针)
printf("%s\n",string[0]); 输出hello
printf("%s\n",string[1]); 输出world
函数指针
指向函数的指针
函数名为该函数所占内存区的首地址 函数名 = 函数内存首地址(函数入口地址)
把函数的首地址(函数入口地址)赋予一个指针变量,使指针指向函数。
通过指针变量就可以找到调用这个函数,这种指向函数的指针叫“函数指针变量”
格式为:类型说明符(*指针变量名)();
如: void (*p)(); *p表示它是一个指针,右边的括号表示它指向一个函数 ,括号里空的表明它没有参数 ,void表示它没有返回值
申明很麻烦,可以加一个定义 typedef int(*T)(int,int); 这样T就是定义函数指针了
T q = add; 等价于 int(*q)(int,int);
指针函数
返回值是指针的函数
/*
int (*p)() 和 int *p() 的区别?
int (*p)() 是一个函数指针,是一个变量,返回值是整形。
int *p() 是一个函数声明,说明p是一个指针型函数,返回值是一个指向整形量的指针。
找到变量名,先右后左
*/
回调函数
回调函数:把函数名作为另一个函数的参数
作用:修改函数的功能
冒泡排序
程序实现了从小到大排序,在函数都封装好之后,要实现从大到小排序,如何实现?
能不能让paixu()既实现从小到大排序又实现从大到小排序?
复杂函数声明
1.int*(*(*fp)(int))[10];
2.int*(*(*array[5])())();
怎么解释?
右左法则
1. int*(*(*fp)(int))[10];
先找变量fp, 看括号 int*(*(*fp)(int))[10]; ,fp是一个指针
向右看,也是一个括号 (int), int*(*(*fp)(int))[10];
括号表明指针指向一个函数,有整型的参数。
向左看,函数的返回值 int*(*(*fp)(int))[10]; 返回值是一个指针
得出fp是一个指针指向函数,函数有一个int类型的参数,函数的返回值也是指针。
再向右看,返回的指针指向[10],int*(*(*fp)(int))[10]; ,指向一个10个元素的数组。
再向左看,10个元素的类型,int*(*(*fp)(int))[10]; , 每个元素都是整形指针。
总结:fp是指针,指向一个函数,函数有整型参数,函数的返回值是指针,指向有10个元素的数组,元素是整型指针。
2. int*(*(*array[5])())();
array是一个有5个元素的数组,元素是指针,指向一个函数,函数没有参数,函数的返回值是指针,指针指向另一个
函数,这个函数没有参数,返回值是一个整型指针。
问:const和volatile能同时使用吗?
可以,volatile表示编译器不要优化变量;
const修饰指针时,表示不能使用指针来修改地址上的值,但是可以用其他指针或变量修改。
const修饰变量时,表示不能使用变量直接修改值,但是可以使用其他指针来修改。