AutoLeaders控制组——C语言指针笔记
一.指针简介
1.指针定义
什么是指针?从根本上看指针(pointer)是一个值为内存地址的变量。正如char类型变量的值是字符,int类型变量的值是整数,指针变量的值是地址。因此指针即地址
2.声明指针
声明指针变量时必须指定指针所指向变量的类型,这是因为不同的变量类型占用不同的存储空间。下面是一些指针的声明示例
int * pi; // pi是指向int 类型变量的指针
char * pc; // pc是指向 char 类型变量的指针
float * pf,* pg; // pf、pg都是指向float 类型变量的指针
类型说明符表明了指针所指向对象的类型,星号(*)表明声明的变量是一个指针。int *pi;声明的意思是pi 是一个指针,*pi是int类型
二.指针与函数
1.作为桥梁来修改函数中变量的值
void f(int *p);
指针在被调用的时候得到了某个变量的地址: int i=0; f(&i);
在函数里面可以通过这个指针访问外面的变量i ,同时可以通过对 *p赋值从而改变变量 i 的值。
代码如下
#include <stdio.h>
void f(int *p);
int main(void){
int i = 6;
printf("&i=%p\n", &i);
f(&i);
printf("%d",i);
return 0;
}
void f(int *p) {
printf(" p=%p\n",p);
*p=666;
}
2.在函数中进行变量交换
通过传入变量的地址来进行变量值的交换
代码如下:
#include<stdio.h>
void swap(int *pa,int *pb);
int main()
{
int a=5;
int b=6;
swap(&a,&b);
printf("%d %d\n",a,b);
return 0;
}
void swap(int *pa,int *pb){
int t=*pa;
*pa=*pb;
*pb=t;
}
3.从函数中返回多个值
函数返回多个值,某些值就只能通过指针返回,传入的参数实际上是需要保存带回的结果的变量
代码如下:`
#include<stdio.h>
void maxmin(int a[],int len,int *max,int *min);
int main()
{
int a[]={1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,};
int max,min,len;
maxmin (a,sizeof(a)/sizeof(a[0]),&max,&min);
printf("%d %d",max,min);
return 0;
}
void maxmin(int a[],int len,int *max,int *min){
int i;
*max=*min=a[0];
for(i=1;i<len;i++){
if(*min>a[i]){
*min=a[i];
}if(*max<a[i]){
*max=a[i];
}
}
}
4.通过指针返回函数运算的结果
函数返回运算的状态,结果通过指针返回
函数在运算的过程中可能遇到特殊的状态计算,未得到特殊的结果
常用的套路是让函数返回特殊的不属于有效范围内的值来表示出错: 如 返回-1或0(在文件操作会看到大量的例子)
但是当任何数值都是有效的可能结果时,就得分开返回
函数状态用return 返回而结果则用指针返回
#include <stdio.h> /**
@return 如果除法成功,返回1;否则返回0
*/
int divide(int a, int b, int *result);
int main(void)
int a=5;
int b=2;
int c;
if ( divide(a,b,&c) ) {
printf("%d/%d=%d\n",a, b, c);
}
return 0;
}
int divide(int a, int b, int *result) {
int ret = 1;
if( b == 0 ) ret = 0; else {
*result = a/b;
return ret;
}
三. 指针常见错误
定义了指针变量,还没有指向任何变量,就开始使用指针
如下
int *p;
int k;
k=12;
*p=12;
这样会是指针指向未知的位置,从而导致程序的崩溃
四.指针与数组
在函数参数表中,数组就是指针
由于函数原型可以省略参数名,所以下面4种原型都是等价的:
int sum(int *ar, int n); int sum(int *, int);
int sum(int ar[],int n); int sum(int[],int);
数组变量本身表达地址,所以
int a[10]; int*p=a;// 无需用&取地址
但是数组的单元表达的是变量,需要用&取地址
a == &a[0]
[ ]运算符可以对数组做,也可以对指针做: p[0] <=> a[0]
运算符可以对指针做,也可以对数组做: * a=25;此时*a代表的值为a[0]
数组变量是const的指针,所以不能被赋值· int a[ ] <=> int *const a=…
因此数组变量就是特殊的指针
五.指针与const
1. 指针是const
表示指针一旦得到了某个变量的地址,不能再指向其他变量
int * const q = &i; // q 是 const
*q = 26;// OK
q++; // ERROR
2.所指是const
表示不能通过这个指针去修改那个变量(并不能使得那个变量成为const)
const int *p = &i;
*p = 26;// ERROR!(*p) 是 const
i= 26;//OK
p=&j;//OK
判断哪个被const了的标志是const在星号的前面还是后面
int i;
const int* p1 = &i;
int const* p2 = &i;
int *const p3 = &i;
如果const在星号前表明所指是const,反之则为指针是const
3.const转换
通过const转换可以把一个非const的值转换成const的值
例如:
void f(const int* x);
int a = 15;
f(&a); // ok
const int b = a; f(&b); // ok
b = a + 1; // Error!
把变量a的值进行固定
当要传递的参数的类型比地址大的时候,这是常用的手段:既能用比较少的字节数传递值给参数,又能避免函数对外面的变量的修改
4.const数组
防止数组在函数内被修改可以使用const数组,由于数组变量就是特殊的指针
const int a[ ]={I,2,3,4,5,6,};
数组变量已经是const的指针了,这里的const表明数组的每个单元都是const int,所以必须通过这样的初始化进行赋值
六.指针的运算
1.指针的简单运算
指针的运算并不是简单的加减, 我们的系统中,地址按字节编址,short类型占用2字节,double类型占用8字节。指针加1 指的是增加一个存储单元。对数组而言,加1后的地址是下一个元素的地址,而不是下一个节的地址
指针加1,指针的值递增它所指向类型的大小(以字节为单位)。
验证如下:
#include<stdio.h>
int main(void)
char ac[] = {0,1,2,3,4,5,6,7,8,9,};
char *p = ac;
printf("p =%p\n",p);
printf("p+1=%p\n", p+1);
printf("*(p+1)=%d\n", *(p+1));
int ai[] = {0,1,2,3,4,5,6,7,8,9,};
int *q = ai;
printf("q =%p\n",q);
printf("q+1=%p\n",q+1);
printf("*(q+1)=%d\n", *(q+1));
return 0;
}
同理,同类型指针之间相减得到的值为存储单元(以字节为单位)
指针只能做加减,指针乘除无意义
指针之间可以作比较,比较的是它们在内存中的地址
2.指针运算与数组的关系
若指针p指向数组,那么指针加一将会使数组进入下一个单元
例如:
*p<=>ac[0]
*(p+1)<=>ac[1]
七. 指针的类型转换
void* 表示不知道指向什么东西的指针,指向一个内存空间
计算时与char*相同(但不相通)
指针可以转换类型 例如:
int * p = &i;
void *q= (void *)p;
这并没有改变p所指的变量的类型,i还是int类型。而是让后人用不同的眼光通过p看它所指的变量·我不再当你是int啦,我认为你就是个void!