概念
指针是什么?指针就是地址,众所周知,内存中的每个存储单元都有自己的地址,根据存储地址可以准确的找到该内存单元,所有通常把这个内存地址称为指针。所有指针就是实际地址。在c语言中,使用一个变量来存储指针,那么这个就是指针变量。
一个指针的值就是某个内存单元的地址(或者指针)。指针是指地址是一个常量;指针变量时指取值为地址的变量。
指针的定义方式和初始化
1 //单个的定义指针 2 3 int *p; 4 5 //一条语句定义多个指针 6 7 int *p1,*p2; 8 9 10 //使用typedef来便捷定义 11 12 typedef int *ZHE; 13 ZHE a,b,c; 14 15 //////////////////////////// 16 //指针的初始化 17 //方式一 18 int a; 19 int *p=&a; 20 21 //方式二 22 int a; 23 int *p; 24 p=&a; 25 26 //方式三 27 28 int *p,*q; 29 int a=90; 30 p=&a; 31 q=p;
赋值指针注意
- 不同类型的指针赋值需要强制转换
- 不允许将一个值直接给指针变量(0除外)
- 在c语言中,auto变量不能赋值给static指针变量。
int a=90; static int *p=&a; ////////////////////////////// 错误 /////////////////////////////
实例
void main() { int a,*p; p = &a; *p = 11; a++; printf("a=%d,*p=%d", a, *p); }
指针运算
指针是地址,地址是一种无符号整数;指针只有加法和减法,没有乘除法,因为两个地址之间的没有任何意义。但是两个地址之间的加法也没有任何意义,而两个地址相减表示两个指针之间的内存单元数。
指针的加减的结果=当前地址+/-n*sizeof(type);例如:int *pi;pi的值是2000的话,那么pi++,就是2000+1*sizeof(int)=2002;其他类型也是类似。
如果两个指针p1,p2存在如下关系:
p1==p2:p1,p2指向同一个内存单元;
p1>p2;表示p1处于高地址位置;
p1<p2:表示p1处于低地址位置。
指针数组之间的关系
数组的指针其实就是数组再内存中的起始地址。
void main() { int a[10]; int k; for (k = 0; k < 10; k++) a[k] = k;// *(a+k)=k; }
数组元素的几种赋值方法
void main() { char str[10]; int i; //常规方法 for (i = 0; i < 10; i++) str[i] = 'a' + i; //指针方法 char *array = str; for (i = 0; i < 10; i++) *(array + i) = 'a' + i; //指针自增方法 for (i = 0; i < 10; i++) *array++ = 'a' + i; }
在上面3种方法中,第三种方法 array指向的是str[9]的下一个单元,显然超出了数组所占的内存区域,这是越界现象,因为C语言不会对数组越界检查,所以需要程序员自己控制。
在后面加一个array=str即可。
多维数组指针的定义方式
void main() { int a[2][3] = { { 1,2,3 },{ 4,5,6 } }; int(*p)[3]; int i,j; p = a; for (i = 0; i < 2; i++) for (j = 0; j < 3; j++) printf("%d", *(p + 3 * i + j));// printf("%d",*(p[i]+j)) }
数组指针与指针数组的区别
- 定义的方式不一样,数组指针 int (*p)[5]; 指针数组 int *p[5];
- 表示的东西不一样,数组指针 p是指针变量,不是数组名,可以对此赋值;指针数组p是数组名,不可赋值。
- 存储的对象不一样;数组指针存储的是普通值,指针数组存储的是指针。
void main() { int i, j, k; int a, b, c, d, e, f; int *p[6] = { &a,&b,&c,&d,&e,&f }; for (i = 0; i < 6; i++) { scanf("%d", p[i]); } for (i = 0; i < 5; i++) { for (j = i+1; j < 6; j++) { if (*p[i] > *p[j]) { k = *p[i]; *p[i] = *p[j]; *p[j] = k; } } } for (i = 0; i < 6; i++) printf("%d ", *p[i]); }
字符指针
void main() { char str[] = { "i am your father" }; char ch; char *p, *q; p = str; q = p + strlen(str) - 1; while (p < q) { ch = *q; *q-- = *p; *p++ = ch; } printf("%s", str);
}
指针与动态内存分配
我们以往的定义如 int a[10]; int b;等等都是静态内存分配,这些内存在程序运行前就分配好了,不可改变。
假如我们需要记录一个班级的学生成绩,那么我们要定义一个数组,但是我们常规定义数组要确定数组的大小。如果我们开辟一个1000的大小的数组,如果人数多,不够用,人数少造成浪费。然而动态内存分配就解决了这个问题。
动态内存分配的方式
- malloc:void * malloc(unsiged int size);
int n ,*p; scanf("%d",&n); p=(int *)malloc(n*sizeof(int));
- calloc:void *calloc (unsigned int n,unsigned size);功能和malloc一样,但是他将赋初始值。
- realloc:void *realloc(void *p,unsigned int size):在原来的空间不够用的时候重新开辟更大的空间,优点是,原来的数据时保存的。
内存的释放
使用free(void * p)释放无用的内存,避免浪费内存。
二级指针
int a=20; int *p; int **k; p=&a; **k=&p;
函数指针
使用背景,假如有多个函数,他们的参数和返回值都完全相同,那么我们使用一个函数指针对这些函数统一调用。
#include<stdio.h> #include<conio.h> #include<string.h> int max(int a, int b); int min(int a, int b); int sum(int a, int b); int func(int a, int b, int(*fun)(int, int)); void main() { int a = 2; int b = 3; int res; res=func(a, b, max); res=func(a, b, min); res=func(a, b, sum); } int func(int a, int b, int(*fun)(int, int)) { return (*fun)(a, b); } int max(int a, int b) { return a > b ? a : b; } int min(int a, int b) { return a < b ? a : b; } int sum(int a, int b) { return a + b; }
ps:一个函数的返回值是指针时应该注意:在返回之前一定要保证返回的指针时有效的,不是野的,因为auto在使用完后会被立即销毁,所有函数内部需要用static修饰
int *get(int num) { static int a[100]; //// //// //// //// return (a); }