青梅浅谈之C语言指针
讲师:青梅煮酒
指针是C语言独有的也是学习C语言的重点,要学好C语言,必须将指针十分了解,才能很好的利用C语言来为我们服务。你是不是觉得指针很难学?不,不要有这样的想法,下面就由我来想大家讲解C指针,从浅至深。
一、什么是变量
首先先定义一个变量a,其内部结构如下图所示:
貌似不能插入图片
一个变量有三个属性,分别是:名称、地址、内容,名称为我们声明变量时为变量赋予的名字;地址是系统随机分配的一个内存编号;内容是我们赋予变量的值。我们来分析如下代码:
int main (void)
{
int a;
a = 10;
return 0;
}
1. int a; 我们声明一个名称为a的变量,系统在内存中随机找到一块空闲的空间,并将使用权限交于软件,此时a变量的名称与地址都已定义,其值暂未定义,目前是垃圾值。
2. a = 10; 将变量a的值定义为10。
由此可见在一个变量的定义时,我们认为可以操控其名称与值,但地址是由系统随机控制的。这里要注意的是不要将变量的这三个属性混淆,认清这一点有助于我们对指针的学习。
二、什么是指针变量
所谓的指针就是指地址,所谓指针变量就是用来专门存放地址的变量。我们定义的一般变量可以存放如:字符、数字等值,而指针变量只能存放变量的地址,并且指针变量的类型应为所所指向变量的类型,如:你不可以创建一个整型变量a,在创建一个浮点型指针,将其指向变量a(明白这一点有助于对结构的学习)。
指针变量和一般变量向同,也由三个属性,其分别为:名称、地址、内容,指针变量的内容存放的是地址。这里应注意的是不要将指针变量的地址与内容混淆,指针变量的地址是其自身的地址,而内容是别的变量的地址(如指针变量的内容指向自己的地址,这里不讨论)。
1.如何定义指针变量
int main(void)
{
int a;
int* p;
p = &a;
*p = 10;
printf("%d\n",a);
return 0;
}
1. int a; 创建一个变量a,其类型为int型,
2. int* p; 创建一个指针变量p,其值为垃圾值
3. p = &a; 将变量a的地址赋予指针变量p,
4. *p = 10; 修改指针变量p所指向的变量内容。
详解:
第2步创建了一个指针变量p,方法为所要指向变量的数据类型加“*”,注意的是其创建的指针变量是p,而不是*p,其类型为int*型。这时的指针变量的内容为垃圾值,第3步将为指针变量赋值p = &a;,将a的地址发送给p。
2.如何使用指针变量
指针变量的使用与一般变量有所不同,首先我们要明白为何声明一个指针变量?其实声明指针变量的作用是用来控制一般变量,所以我们不能像一般变量那样使用指针变量。判断下面两行加粗代码:
int main(void)
{
int a;
int* p;
p = &a;
p = 10;
*p = 10;
printf("%d\n",a);
return 0;
}
详解:
指针变量p只接受地址,所以p = 10;,是错误的。而在上一步p = &a;,中我们已将a的地址发送给p,为何要将a的地址发送给p呢?我们的目的是通过指针变量p来控制a,那么怎么才能达到目的呢?我们使用“*”加p的方式,就可以控制a,这时候*p就等同于a变量,编译以上代码,查看结果。
一个指针变量,不论其为何类型,都只占4个字节,原因是指针变量只储存任何数据的前4个字节的地址,其长度是由类型控制的。如:定义一个double a;变量,其指针只保存其前4个字节的地址,后4个字节时由double来控制,所以说我们定义的指针变量其类型要与其指向的变量类型形同。
三、指针与数组
首先分析(式一):
void tex (int* p, int i)
{
p[2] = 10;
}
int main(void)
{
int n;
int a[5] = {1, 2, 3, 4, 5};
tex(a, 5);
printf("%d",a[2]);
return 0;
}
上式时定义了一个数组a,然后通过函数tex将a第三个元素的值进行修改后输出。你是不是有这样一个问题:p[2] = 10;不对吧,怎么不是*p[2] = 10;?这里是难点也是重点,当初我自学时也卡到了这里,不过也很简单,主要是我们将一个概念没有弄明白。
1.什么是数组
我们在以前学习数组时,由于并没有接触指针,所以数组的内部结构并没有学习,那么现在我们就来重新认识一下数组。
数组就是将数据连续的储存在内存中,这里的关键词是连续!C语言中规定一个数组的数组名就是其第一个元素的地址,由此我们可以知道a实质是a[0]的地址即a == &a[0]。那么结合我们所学的指针,数组a的第一个元素就是*(a),第二个元素是*(a+1),以此类推。
int main(void)
{
int i;
int a[5];
*(a) = 1;
*(a+1) = 2;
*(a+2) = 3;
*(a+3) = 4;
*(a+4) = 5;
for (i=0; i<5; ++i)
{
printf("%d",a[i]);
}
return 0;
}
将上式输入VC++6.0中是能成功编译的,同时为方便使用C语言又规定我们可以使用下标“[]”,即*(a) == a[0],*(a+1) == a[1]。所以对于数组来说,其数组名本来就是一个地址,C语言规定了可以用下标的形式来表示各个元素,所以在(式一)中我们使用的是p[2] = 10; 而不是*p[2] = 10;。我们所使用的数组就是指针的一种形式,这一点在动态数组中将充分的体现出来。
注:*(a+1)其等同于 *(a + (int*1)) 地址跳向下一个元素。
四、指针与结构体
所谓结构体就是自定义数据类型,以下为结构体中指针的使用,其中p->personnel = 20;等价于(*p).personnel = 20;,p->等同于(*p).。在编程中同常采用第二种形式书写,希望大家吃透以下代码,这有利于以后对链接的学习。
# include <string.h>
struct item
{
char name[50];
int personnel;
double invest;
};
int main(void)
{
struct item one;
struct item* p = &one;
strcpy((*p).name,"calzada");
(*p).personnel = 20;
(*p).invest = 20.5;
//strcpy(p->name,"calzada");
//p->personnel = 20;
//p->invest = 20.5;
return 0;
}
上面代码中struct item{ ….. }是创建了一个数据类型而不是变量,其类型为struct item型。struct item one;是创建了名为one的变量,其数据类型为struct item,所以指向one的指针也必须为struct item型。结构体变量不能参与算数用算,只能相互赋值。
五、指针的指针
先阅读下列式子
int main (void)
{
int* p;
printf("%0x\n",p);
int** q = &p;
int i;
printf("%0x\n",&i);
*q = &i;
printf("%0x\n",p);
return 0;
}
上式是将一个指针变量p的地址发送给一个指针变量q,然后通过指针变量q修改指针变量p的内容(所指向的地址)。由于指针变量p为int*类型,所以指向它的指针变量q也应为int*类型再加“*”,即为int**类型。*q = &i;等同于p = &i;。
结束语
学好指针对日后C语言的学习事关重要,C语言是面向过程的语言,其实质是对内存的操作,而指针为我们提供了控制内存的方法。
首先感谢您的阅读,本文内容为我个人的见解所以名为:青梅浅谈,本文章为原创,受著作权保护,如需引用请指明出处!谢谢!
青梅煮酒
2012年3月6日19:54:26