目录
运算符&的“前世今生”
刚开始接触C语言时,我们就得记住一件事,scanf()中输入一个变量,变量前必须加“&”,否则就会报错,而printf()中却不用。
要知道它的作用,就先从变量入手。
C语言的变量放在内存里,因此有一个占据的地方,就是地址。而“&”就是把变量的地址拿出来,告诉你这个变量放在哪里,然后取出调用
&也有地址,在printf() 中可用%p求出
#include<stdio.h>
int main(){
int i = 0;
printf("%p\n",&i);
return 0;
}
而地址的大小是否与int相同,则取决于编译器
取地址时&右边必须是明确的变量,不能为表达式
相邻地址间的差距永远是4
#include<stdio.h>
int main(void) {
int a[10];
printf("%p\n",&a);
printf("%p\n",a);
printf("%p\n",&a[0]);
printf("%p\n",&a[1]);
return 0;
}
指针
需要一个参数保存变量的地址,则可以使用指针
指针类型的变量就是保存地址的变量
int* p = &i; 就是把i的地址保存到指针p中,其中*可以靠近int 也可以靠近p
int* p,q;等价于int *p,q;我们就可以说p指向了q
指针变量的值是具有实际值的变量的地址,而普通变量的值是实际的值
#include<stdio.h>
void f(int *p);
int main(void)
{
int i = 6;
printf("&i=%p\n",&i);
f(&i);
system("pause");
return 0;
}
void f(int *p)
{
printf("p=%p\n",p);
}
可见输出结果中p已经保存了i的地址,使得f函数拥有访问外面i的能力了,可是该怎么访问,即怎样读或写?
其实只需使用*加指针变量即可,同上代码,可以把*p理解成一个整数
在f函数中加入一句
printf("*p = %d\n",*p);
这时输出的数值即为6,就是i的初值,可见使用*加上指针变量就能访问这个地址
修改外部的值
按照之前的课程,我们知道函数是独立程序模块,不能将外部定义的值修改,而此时有了指针,在函数中获取了地址,则情况就不一样了
#include<stdio.h>
void f(int *p);
void g(int k);
int main(void)
{
int i = 6;
printf("&i=%p\n",&i);
f(&i);
g(i);
system("pause");
return 0;
}
void f(int *p)
{
printf("p=%p\n",p);
printf("*p = %d\n",*p);
*p = 26;
}
void g(int k)
{
printf("k =%d",k);
}
f函数里的*p保存了i的地址,在这个函数指向i,此时对*p赋值,也就相当于对i值进行了改变,实现了对外链接,i的值变为了26,就是芥末神奇
指针的应用
一、交换两个变量的值
当我们学到函数时,尝试过利用函数交换两个数,结果可想而知,无法改变函数外a,b的取值
但这却可以用指针来解决
#include<stdio.h>
void swap(int *pa,int *pb);
int main()
{
int a = 5;
int b = 6;
swap(&a, &b);
printf("a=%d,b=%d",a,b);
return 0;
}
void swap(int *pa, int *pb)
{
int t = *pa;
*pa=*pb;
*pb=t;
}
运行后a与b 的值发生了互换
返回多个值
函数中return语句只能传出一个变量值,函数结果不止一个时可以用指针传出
#include<stdio.h>
void minmax(int a[],int len,int *max,int *min);
int main(void)
{
int a[] = {1,2,3,4,5,6,7,8,9,12,13,14,16,17,21,23,55,};
int min,max;
minmax(a,sizeof(a)/sizeof(a[0]),&min,&max);
printf("min=%d,max=%d",min,max);
return 0;
}
void minmax(int a[],int len,int *min,int *max)
{
int i;
*min=*max=a[0];
for(i=1;i<len;i++){
if(a[i]<*min){
*min = a[i];
}
if(a[i]>*max){
*max = a[i];
}
}
}
以此代码为例,在minmax函数中找出素数最大与最小值,用指针便可传递两值离开函数,并在主函数中printf输出
指针与数组
函数参数表中的数组实际上是指针,但可以用数组的运算符 [ ] 进行运算
sizeof(a)==sizeof(int*)
数组变量本身表达地址,所以在数组无需用&取地址即int a[10]; int *p=a;
但数组的单元表达是变量,如a[0],a[1]···等等,需要用&取地址
a==&a[0] 运算符 [ ] 可以对数组做,也可以对指针做:*p<==>p[0]
相反,*也可以对数组做:*a<==>a[0]
指针这个知识点是真滴生涩,看不懂啊喂 QwQ
数组变量是const的指针,所以不能被赋值,数组变量间不能做赋值
错误示范:a[ ]=b或者int a[ ];a=b;
一个数组是常量指针,即const的指针,所以不能被赋值
int a[ ]<==>int *const a=···
const int a[]={1,2,3,4,5,6};数组变量本身是const指针
这里的const表明数组的每个单元都是const int,所以必须通过初始化进行赋值,否则接下来将不能进行赋值操作
希望数组在函数中不被破坏,可以设置参数为const
int sum(const int a[],int length);
指针与常量
指针是const时,表示一旦得到了某个变量的地址,不能再指向其他变量,即关系一定,指针一定指向某个变量,不会被改变
①int *const q = &i
(q是const)q指向了i这个事实不可改变,它们之间的关系是永久的
此时以*q = 26为例,是可以做的,因为i不是const,i可以赋初值,使 i=26,但因为q是const,所以q++的做法是错误的
②const int *p = &i
表示不能通过p这个指针去修改i这个变量,即*p=26是错误的,不能让 i=26,此时的*p是const
但i不是const,可以单独给i赋值,i=26而不能通过*p去改变。同时p不是const,它也可以指向其他地址,p = &j;是成立的
总的来说,有两种意思:一是指针不可修改,另一是不可通过指针修改
const在*前,表面它所指的东西不能修改
const在*后,表面指针不能被修改
指针的运算
#include<stdio.h>
int main()
{
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);
char ai[]={0,1,2,3,4,5,6,7,8,9,};
char *q=ai;
printf("q=%p\n",q);
printf("q+1=%p\n",q+1);
return 0;
}
让指针加1:sizeof(char)=1,sizeof(int)=4
由上面的代码运行可知,char的指针地址加1,而int时,变成了加4。所以指针加1,并不是在地址值上加1,而是在地址值上加一个sizeof那个指针所指的类型
int一个单元占4个字节,所以2c加1后单元地址为30,再加1,则为34
对指针做加一,实际上是我们把它移到下一个单元去
*p ->ac[0] 所以*(p+1)->ac[1]
#include<stdio.h>
int main()
{
char ac[]={0,1,2,3,4,5,6,7,8,9,};
char *p=ac;
printf("*p=%d\n",*p);
printf("*(p+1)=%d\n",*(p+1));
return 0;
}
运行代码可见,*p确实输出为0与ac[0]相同
而*(p+1)为1,与ac[1]相同===================》》》》》*(p+n)与a[n]是一回事儿
如果指针不是指向一片连续分配的空间,如数组,则这种运行没有意义
指针计算
1.给指针加减一个整数(+,+=,-,-=)
2.递增递减(++,--)
3.两个指针相减(所得结果不是两个地址的差,而是差,除以sizeof的类型,表示在这两者间有多少个单元在里面)
#include<stdio.h>
#include<stdlib.h>
int main()
{
char ac[]={0,1,2,3,4,5,6,7,8,9,};
char *p=ac;
char *p1=&ac[5];
printf("p1-p=%d\n",p1-p);
char ai[]={0,1,2,3,4,5,6,7,8,9,};
char *q=ai;
char *q1=&ai[5];
printf("q1-q=%d\n",q1-q);
system("pause");
return 0;
}
*p++
取出*p所指的那个数据来,再顺便把p移到下一位
*优先级虽然高,但没有++高,所以不需要再加括号变成*(p++)
*p++常用于数组类的连续空间操作
#include<stdio.h>
int main(void)
{
char a[]={0,10,25,37,49,52,65,76,83,95,-1};
char *p=&a[0];
for(p=a;*p!=-1;*p++){
printf("%d\n",*p);
}
return 0;
}
指针比较
<,<=,==,>=,>,!=都可以对指针进行比较内存中的地址
数组中的单元地址肯定是线性递增
指针类型
无论指向什么类型,所有指针的大小都是一样的,因为都是地址,但指向不同类型的指针是不能直接相互赋值的