每天学习进步一点,向着高薪工作努力。
一、指针的基本介绍
假设定义了一个a变量,例如:int a,那么当程序执行时,计算机将为这个特定的变量分配一定的存储空间,而分配的具体存储空间大小则取决于这个变量的类型,同时也取决于编译器。例如:
int-4 byte;
char-1 byte;
float-4 byte;
指针的概念:指针是一个变量,它存放着另一个变量的地址。
int a;
int *p;
p=&a;
a=5;
printf("%d",p); //204
printf("%d",&a) //204
printf("%d",&p) //64
printf("%d",*p) //5 ->解引用,利用解引用操作来取得特定地址的值。
*p=8;
printf("%d",a) //8
//p->address
//*p->value at address
不同类型的变量可以有不同类型的指针,如:
int a;//整形变量
int *p//指向整数类型的指针
char c;//字符型变量
char *p0//指向字符类型的指针
double d//双精度型变量
double *d//指向双精度类型的指针
当对指针变量进行加运算时,指针变量并不是单纯地+1,如下面这段代码:
int a=10;
int *p;
p=&a;
printf("%d\n",p);//p的地址为2002
printf("%d\n",p+1);//p+1的地址为2006
这是因为,int变量占据4个字节,当实行+1操作时,实际上地址+4;
二、指针的类型
为什么不能只使用一个通用的类型来进行存储呢?
因为指针不及能用来存储内存地址,同时也能用它来解引用那些地址的内容 ,通过这种方式就能访问和修改这些地址对于的值。
通用指针类型:void指针
三、指向指针的指针
更正:此处r内出的值应为205;
#include<stdio.h>
int main()
{
int x=5;
int *p=&x;
*p=6;
int **q=&p;
int ***r=&q;
printf("%d\n",*p);//6
printf("%d\n",*q);//215
printf("%d\n",*(*q));//6
printf("%d\n",*(*r));//225
printf("%d\n",*(*(*r)));//6
}
四、函数传值vs传应用
#include<stdio.h>
void Increment(int a)
{
a=a+1;
}
int main()
{
int a;
a=10;
increment(a);
printf("a=%d",a);
}
当main函数调用Increment函数时:首先暂停指令,先去执行Increment函数,当函数执行完后,再次回到main函数,并为Increment函数开辟另一个栈帧、参数a就会被分配到新的内存空间,当执行a=a+1时,Increment函数内的a增加了1,但它并不能访问自己栈帧以外的变量,当Increment函数调用完后,程序控制流返回到main函数,同时机器清楚之前的Increment函数使用的栈帧,main函数恢复执行。
在上面的程序中,main函数称为主调函数,而Increment函数被称为被调函数,当在主调函数中调用其他函数时,参数被称为:实参。被调函数中的参数被称为:形参。实参会被映射到形参,所以当发生函数调用时,实参‘a’会被映射到另一个形参‘a’。上述步骤就被称为是:传值调用。
全局变量:在程序的任何地方都可以被访问和修改。
局部变量:只能在特定的函数或者特定的代码块进行访问和修改。
当程序开始时,main函数将被调用,所有的信息(参数、局部变量、返回地址、指令)储存在栈上。
接下来来看下面这段程序:
#include<stdio.h>
void Increment(int *p)
{
*p=(*p)+1;
}
int main()
{
int a;
a=10;
increment(&a);
printf("a=%d",a);
}
在这个函数中,当我们调用Increment函数时,我们传递的是“a”的地址,当main函数执行时,将给main函数开辟一个栈帧,其中变量‘a’的值为10,假设a的地址为308,此时我们调用Increment函数,将会创建一个与变量‘a’对应的变量‘p’,变量‘p’是一个指针变量,它指向‘a’的地址,所以当执行Increment函数内的语句时,将会解引用‘a’的地址,并且使变量‘a’+1。
五、指针与数组
假设定义一个整型数组A[5],它在内存中的存储如下图所示。