例如:
???Type a, *p=&a;(Type等于char, int, struct, int *…)void *pv;pv=p;
就像前面说的,void指针的好处,就在于,任意的指针都可以直接赋值给它,这在某些场合非常有用,因此有些操作对于任意指针都是相同的 。void指针最常用于内存管理 。最典型的,也是大家最熟知的,就是标准库的free函数 。它的原型如下:
void free(void*ptr);
free函数的参数可以是任意指针,没有谁见过free参数里面的指针需要强壮为void*的吧?
malloc, calloc,realloc这些函数的返回值也是void指针,因为内存分配,实际上只需要知道分配的大小,然后返回新分配内存的地址就可以了,指针的值就是地址,返回的不管是何种指针,其实结果都是一样的,因为所有的指针长度其实都是32位的(32位机器),它的值就是内存的地址,指针类型只是给编译器看的,目的是让编译器在编译的时候能够正确的设置指针的值(参见指针运算章节) 。如果malloc函数设置成下面这样的原型,完全没有问题 。
char*malloc(size_t sz);
实际上设置成
Type*malloc(size_t sz);
也是完全正确的,使用void指针的原因,实际上就像前面说的,void指针意思是任意指针,这样设计更加严谨一些,也更符合我们的直观理解 。如果对前面我说的指针概念理解的童鞋,肯定明白这一点 。
结构体和指针
结构体指针有特殊的语法:-> 符号
如果p是一个结构体指针,则可以使用 p ->【成员】 的方法访问结构体的成员
typedef struct{ char name[31]; int age; float score;}Student;int main(void){ Student stu = {"Bob" , 19, 98.0}; Student*ps = &stu; ps->age = 20; ps->score = 99.0; printf("name:%s age:%d",ps->name,ps->age); return 0;}数组和指针
1、数组名作为右值的时候,就是第一个元素的地址 。
int main(void){ int arr[3] = {1,2,3}; int*p_first = arr; printf("%d",*p_first); //1 return 0;}2、指向数组元素的指针 支持 递增 递减 运算 。
(实质上所有指针都支持递增递减 运算,但只有在数组中使用才是有意义的)
int main(void){ int arr[3] = {1,2,3}; int*p = arr; for(;p!=arr+3;p++){ printf("%d",*p); } return 0;}3、p= p+1 意思是,让p指向原来指向的内存块的下一个相邻的相同类型的内存块 。
同一个数组中,元素的指针之间可以做减法运算,此时,指针之差等于下标之差 。
4、p[n] == *(p+n)
p[n][m] == *( *(p+n)+ m )
5、当对数组名使用sizeof时,返回的是整个数组占用的内存字节数 。当把数组名赋值给一个指针后,再对指针使用sizeof运算符,返回的是指针的大小 。
这就是为什么将一个数组传递给一个函数时,需要另外用一个参数传递数组元素个数的原因了 。
int main(void){ int arr[3] = {1,2,3}; int*p = arr; printf("sizeof(arr)=%d",sizeof(arr)); //sizeof(arr)=12 printf("sizeof(p)=%d",sizeof(p)); //sizeof(p)=4 return 0;}
函数和指针
函数的参数和指针
C语言中,实参传递给形参,是按值传递的,也就是说,函数中的形参是实参的拷贝份,形参和实参只是在值上面一样,而不是同一个内存数据对象 。
这就意味着:这种数据传递是单向的,即从调用者传递给被调函数,而被调函数无法修改传递的参数达到回传的效果 。
void change(int a){ a++; //在函数中改变的只是这个函数的局部变量a,而随着函数执行结束,a被销毁 。age还是原来的age,纹丝不动 。}int main(void){ int age = 19; change(age); printf("age = %d",age); // age = 19 return 0;}
有时候我们可以使用函数的返回值来回传数据,在简单的情况下是可以的 。
但是如果返回值有其它用途(例如返回函数的执行状态量),或者要回传的数据不止一个,返回值就解决不了了 。
传递变量的指针可以轻松解决上述问题 。
void change(int* pa){ (*pa)++; //因为传递的是age的地址,因此pa指向内存数据age 。当在函数中对指针pa解地址时,//会直接去内存中找到age这个数据,然后把它增1 。}int main(void){ int age = 19; change(&age); printf("age = %d",age); // age = 20 return 0;}再来一个老生常谈的,用函数交换2个变量的值的例子:
#include<stdio.h>void swap_bad(int a,int b);void swap_ok(int*pa,int*pb);int main(){ int a = 5; int b = 3; swap_bad(a,b); //Can`t swap; swap_ok(&a,&b); //OK return 0;}//错误的写法void swap_bad(int a,int b){ int t; t=a; a=b; b=t;}//正确的写法:通过指针void swap_ok(int*pa,int*pb){ int t; t=*pa; *pa=*pb; *pb=t;}
推荐阅读
- 超炫酷技巧!C语言代码优化的技巧
- C语言访问字符串数组元素的方式
- C语言关键字const和指针结合的使用
- 头昏脑胀怎么治疗?
- C语言厉害在哪?
- C语言、嵌入式重点知识:回调函数
- C语言指针经典知识汇总
- 移动应用开发的六大编程语言
- 用C语言编写CPU使用率限制程序
- 跨平台的C语言网络框架库acl