//
初学C指针 19th . Oct . 2011 EVE
/
零、不得不说。
此博文仅代表个人观点,如有悖“天理”,欢迎指正。
----
欢迎所有的想一起研究的朋友加我,嗯,人多力量大嘛!
下面进入正题~
本文引用:
http://topic.csdn.net/u/20070112/09/35186e5a-0d94-4ea6-9b72-c5463cb3d1f3.html [深入理解c指针]
----------------------------------
一、什么是指针?
大家都知道,计算机也是靠物理原理实现的,
所以,物理操作就一定要有操作的对象,
那么CPU直接操作的对象是什么呢?
是所谓的“内存条”
这个内存条上都是有地址编号的,就像我们住的小区,
每一家都有每一家的地址,计算机在传送数据的时候
(就像我们要给朋友家送点东西,就一定要知道他家的地址一样)
需要地址来识别这个信息
(哪家哪户,别搞错了,我去一个朋友家送吃的,结果错进了一个美女家,
碰巧我又长的很帅,而她的情人就在这个时候回来了,麻烦了)
那么指针就是:比如说我,我自己家有个地址,然后,我知道我同学家的地址
我就能从我家,去我同学家,这不废话么,
换个说法就是:int *p ; //定义了一个整形指针变量
int a; //声明一个整形变量,再简单不过了,
p = &a ; //取了同学a的地址,告诉了我,我是p
// —— ,—— 对,我是p
也就是: int **p ; //我是p(二级指针...)
int *pa ; //我朋友(一级指针)
int a ; //The girl
pa = &a ; //朋友知道女孩家的地址
p = &pa ; //我知道朋友家的地址
printf ("%x",*p); //我去了朋友家(取出p中存的a的地址)
printf ("%x",**p); //朋友告诉了我她家的地址(取出a)
二、认识指针
在认识指针之前,需要通过几个方面:
1.什么是指针的类型?
从语法的角度看,你只要把指针声明语句里的指针名字去掉,
剩下的部分就是这个指针的类型。这是指针本身所具有的类型。
(1)int*ptr;//指针的类型是int*
(2)char*ptr;//指针的类型是char*
(3)int**ptr;//指针的类型是int**
(4)int(*ptr)[3];//指针的类型是int(*)[3]
(5)int*(*ptr)[4];//指针的类型是int*(*)[4]
是不是很容易?
2.什么是指针指向的类型?
当你通过指针来访问指针所指向的内存区时,指针所指向的类型决定了
编译器将把那片内存区里的内容当做什么来看待。
从语法上看,你只须把
指针声明语句中的指针名字和名字左边的指针声明符*去掉,
剩下的就是指针所指向的类型。
(1)int*ptr;//指针所指向的类型是int
(2)char*ptr;//指针所指向的的类型是char
(3)int**ptr;//指针所指向的的类型是int*
(4)int(*ptr)[3];//指针所指向的的类型是int()[3]
(5)int*(*ptr)[4];//指针所指向的的类型是int*()[4]
3.指针的值(或者叫指针指向的内存区)?
指针的值是指针本身存储的数值,
这个值将被编译器当作一个地址,而不是一个一般的数值。
在32位程序里,所有类型的指针的值都是一个32位整数,
因为32位程序里内存地址全都是32位长。
指针所指向的内存区就是从指针的值所代表的那个内存地址开始,
长度为sizeof(指针所指向的类型)的一片内存区。
以后,我们说一个指针的值是XX,
就相当于说该指针指向了以XX为首地址的一片内存区域;
我们说一个指针指向了某块内存区域,
就相当于说该指针的值是这块内存区域的首地址。
以后,每遇到一个指针,都应该问问:
这个指针的类型是什么?指针指的类型是什么?该指针指向了哪里?
我们可以用一个指针和一个循环来遍历一个数组,看例子:
-------------------
intarray[20];
int*ptr=array;
...
//此处略去为整型数组赋值的代码。
...
for(i=0;i <20;i++)
{
(*ptr)++;
ptr++;
}
这个例子将整型数组中各个单元的值加1。由于每次循环都将指针ptr加1,
所以每次循环都能访问数组的下一个单元。
再看例子:
-------------------
char a[20];
int *ptr=a;
...
...
ptr+=5;
在这个例子中,ptr被加上了5,编译器是这样处理的:
将指针ptr的值加上5乘sizeof(int),
在32位程序中就是加上了5乘4=20。
由于地址的单位是字节,故现在的ptr所指向的地址比起加5后的
ptr所指向的地址来说,向高地址方向移动了20个字节。
在这个例子中,没加5前的ptr指向数组a的第0号单元开始的四个字节,
加5后,ptr已经指向了数组a的合法范围之外了。
虽然这种情况在应用上会出问题,但在语法上却是可以的。
这也体现出了指针的灵活性。
如果上例中,ptr是被减去5,那么处理过程大同小异,
只不过ptr的值是被减去5乘sizeof(int),
新的ptr指向的地址将比原来的ptr所指向的地址
向低地址方向移动了20个字节
4.指针本身占据的地址(内存)
指针本身占了多大的内存?你只要用函数
sizeof(指针的类型)测一下就知道了。在32位平台里,指针本身占据了4个字节的长度。
三、指针表达式
啥是指针表达式啊?
简单的说就是左边右边都是指针。
比如:
-----------------
int *p ;
float f ;
p = (float *)&f ; //这是一个指针表达式
int a,b;
int array[10];
int *pa;
pa = &a //这是一个指针表达式
int **ptr = &pa ;//this too
*ptr = &b ; //and this
pa = arry; //this
pa ++; //this
犹豫指针表达式的结果是一个指针,所以指针表达式也具有指针的四个要素!
这里有一点需要注意的就是说,指针表达式左边与右边的指针的类型必须相同
当然了,不相同,有的编译器也不会报错,
C给人们的自由,更高的自由就意味着永远的警惕!
有的同学问了说:不相同能怎么样呢?
问题大了!接着看,
四、指针的算数运算
---------------
char a[20];
int *ptr=a;
...
...
ptr++;
在上例中,指针ptr的类型是int*,它指向的类型是int,
它被初始化为指向整形变量a。接下来的第3句中,指针ptr被加了1,
编译器是这样处理的:它把指针ptr的值加上了sizeof(int),
在32位程序中,是被加上了4。由于地址是用字节做单位的,
故ptr所指向的地址由原来的变量a的地址向高地址方向增加了4个字节。
由于char类型的长度是一个字节,
所以,原来ptr是指向数组a的第0号单元开始的四个字节,
----------------------------------------------
此时指向了数组a中从第4号单元开始的四个字节。
---------------------------------------
c语言的数组不做过界检查!
-------------------
char *str[3]={
"Hello,thisisasample! ",
"Hi,goodmorning. ",
"Helloworld "
};
chars[80];
strcpy(s,str[0]);//也可写成strcpy(s,*str);
strcpy(s,str[1]);//也可写成strcpy(s,*(str+1));
strcpy(s,str[2]);//也可写成strcpy(s,*(str+2));
上例中,str是一个三单元的数组,该数组的每个单元都是一个指针,
这些指针各指向一个字符串。把指针数组名str当作一个指针的话,
它指向数组的第0号单元,它的类型是char**,它指向的类型是char*。
*str也是一个指针,它的类型是char*,它所指向的类型是char,
它指向的地址是字符串 "Hello,thisisasample! "的第一个字符的地址,
即 'H '的地址。 str+1也是一个指针,
它指向数组的第1号单元,它的类型是char**,它指向的类型是char*。
------------
chars= 'a ';
int*ptr;
ptr=(int*)&s;
*ptr=1298;
指针ptr是一个int*类型的指针,它指向的类型是int。
它指向的地址就是s的首地址。在32位程序中,s占一个字节,int类型占四个字节。
最后一条语句不但改变了s所占的一个字节,
还把和s相临的高地址方向的三个字节也改变了。这三个字节是干什么的?
只有编译程序知道,而写程序的人是不太可能知道的。
也许这三个字节里存储了非常重要的数据,
也许这三个字节里正好是程序的一条代码,而由于你对指针的马虎应用,
这三个字节的值被改变了!这会造成崩溃性的错误!!!!!!!!!
在指针的强制类型转换:ptr1=(TYPE*)ptr2中,
如果sizeof(ptr2的类型)大于sizeof(ptr1的类型),
那么在使用指针 ptr1来访问ptr2所指向的存储区时是安全的。
如果sizeof(ptr2的类型)小于sizeof(ptr1的类型),
那么在使用指针ptr1来访问ptr2所指向的存储区时是不安全的。
至于为什么,读者结合上例,想想应该会明白的。
五、野指针
什么是野指针?
就是,这个指针是很野,它不老实,它会乱成一气!
没准指向的是没有内容的地址,好呀,好呀,没事呀,没事呀。
过了一会,它偷偷的指向了系统内存!!! 完了,系统让它弄屎了!!!!
使用指针一定要注意:
1.定义出来的指针首先赋为空。
2.使用完毕之后的指针,我是指free();了之后的,也要赋为空。
3.使用的指针不要操作超越了变量的作用范围
愿君细心啊!
六、其他
C语言的精髓就是指针了,
最难学的也是指针,
但是它是C的灵魂所在。 好好学把。:-)
数组名存放的是数组的首地址,也就是指针,但是它是指针常量。
什么是常量,5是常量,2是常量,1是常量,999也是常量。
就是不能改变的,不能让他自加自减,系统会很不高兴的。
int array [10];
t = sizeof (array);
在表达式sizeof(array)中,数组名array代表数组本身,
故这时sizeof函数测出的是整个数组的大小。
好了,就这么多,欢迎多多提提意见,我是个知错就改的银。
欢迎转载,请注明出处。 CSDN ID :Coder_Black
初学C指针 19th . Oct . 2011 EVE
/
零、不得不说。
此博文仅代表个人观点,如有悖“天理”,欢迎指正。
----
欢迎所有的想一起研究的朋友加我,嗯,人多力量大嘛!
下面进入正题~
本文引用:
http://topic.csdn.net/u/20070112/09/35186e5a-0d94-4ea6-9b72-c5463cb3d1f3.html [深入理解c指针]
----------------------------------
一、什么是指针?
大家都知道,计算机也是靠物理原理实现的,
所以,物理操作就一定要有操作的对象,
那么CPU直接操作的对象是什么呢?
是所谓的“内存条”
这个内存条上都是有地址编号的,就像我们住的小区,
每一家都有每一家的地址,计算机在传送数据的时候
(就像我们要给朋友家送点东西,就一定要知道他家的地址一样)
需要地址来识别这个信息
(哪家哪户,别搞错了,我去一个朋友家送吃的,结果错进了一个美女家,
碰巧我又长的很帅,而她的情人就在这个时候回来了,麻烦了)
那么指针就是:比如说我,我自己家有个地址,然后,我知道我同学家的地址
我就能从我家,去我同学家,这不废话么,
换个说法就是:int *p ; //定义了一个整形指针变量
int a; //声明一个整形变量,再简单不过了,
p = &a ; //取了同学a的地址,告诉了我,我是p
// —— ,—— 对,我是p
那么指针的指针就是:我知道我同学家的地址,而我的同学又碰巧知道另一个
我想知道的女孩家的地址,他能帮我找到她。
也就是: int **p ; //我是p(二级指针...)
int *pa ; //我朋友(一级指针)
int a ; //The girl
pa = &a ; //朋友知道女孩家的地址
p = &pa ; //我知道朋友家的地址
printf ("%x",*p); //我去了朋友家(取出p中存的a的地址)
printf ("%x",**p); //朋友告诉了我她家的地址(取出a)
二、认识指针
在认识指针之前,需要通过几个方面:
1.什么是指针的类型?
从语法的角度看,你只要把指针声明语句里的指针名字去掉,
剩下的部分就是这个指针的类型。这是指针本身所具有的类型。
(1)int*ptr;//指针的类型是int*
(2)char*ptr;//指针的类型是char*
(3)int**ptr;//指针的类型是int**
(4)int(*ptr)[3];//指针的类型是int(*)[3]
(5)int*(*ptr)[4];//指针的类型是int*(*)[4]
是不是很容易?
2.什么是指针指向的类型?
当你通过指针来访问指针所指向的内存区时,指针所指向的类型决定了
编译器将把那片内存区里的内容当做什么来看待。
从语法上看,你只须把
指针声明语句中的指针名字和名字左边的指针声明符*去掉,
剩下的就是指针所指向的类型。
(1)int*ptr;//指针所指向的类型是int
(2)char*ptr;//指针所指向的的类型是char
(3)int**ptr;//指针所指向的的类型是int*
(4)int(*ptr)[3];//指针所指向的的类型是int()[3]
(5)int*(*ptr)[4];//指针所指向的的类型是int*()[4]
3.指针的值(或者叫指针指向的内存区)?
指针的值是指针本身存储的数值,
这个值将被编译器当作一个地址,而不是一个一般的数值。
在32位程序里,所有类型的指针的值都是一个32位整数,
因为32位程序里内存地址全都是32位长。
指针所指向的内存区就是从指针的值所代表的那个内存地址开始,
长度为sizeof(指针所指向的类型)的一片内存区。
以后,我们说一个指针的值是XX,
就相当于说该指针指向了以XX为首地址的一片内存区域;
我们说一个指针指向了某块内存区域,
就相当于说该指针的值是这块内存区域的首地址。
以后,每遇到一个指针,都应该问问:
这个指针的类型是什么?指针指的类型是什么?该指针指向了哪里?
我们可以用一个指针和一个循环来遍历一个数组,看例子:
-------------------
intarray[20];
int*ptr=array;
...
//此处略去为整型数组赋值的代码。
...
for(i=0;i <20;i++)
{
(*ptr)++;
ptr++;
}
这个例子将整型数组中各个单元的值加1。由于每次循环都将指针ptr加1,
所以每次循环都能访问数组的下一个单元。
再看例子:
-------------------
char a[20];
int *ptr=a;
...
...
ptr+=5;
在这个例子中,ptr被加上了5,编译器是这样处理的:
将指针ptr的值加上5乘sizeof(int),
在32位程序中就是加上了5乘4=20。
由于地址的单位是字节,故现在的ptr所指向的地址比起加5后的
ptr所指向的地址来说,向高地址方向移动了20个字节。
在这个例子中,没加5前的ptr指向数组a的第0号单元开始的四个字节,
加5后,ptr已经指向了数组a的合法范围之外了。
虽然这种情况在应用上会出问题,但在语法上却是可以的。
这也体现出了指针的灵活性。
如果上例中,ptr是被减去5,那么处理过程大同小异,
只不过ptr的值是被减去5乘sizeof(int),
新的ptr指向的地址将比原来的ptr所指向的地址
向低地址方向移动了20个字节
4.指针本身占据的地址(内存)
指针本身占了多大的内存?你只要用函数
sizeof(指针的类型)测一下就知道了。在32位平台里,指针本身占据了4个字节的长度。
三、指针表达式
啥是指针表达式啊?
简单的说就是左边右边都是指针。
比如:
-----------------
int *p ;
float f ;
p = (float *)&f ; //这是一个指针表达式
int a,b;
int array[10];
int *pa;
pa = &a //这是一个指针表达式
int **ptr = &pa ;//this too
*ptr = &b ; //and this
pa = arry; //this
pa ++; //this
犹豫指针表达式的结果是一个指针,所以指针表达式也具有指针的四个要素!
这里有一点需要注意的就是说,指针表达式左边与右边的指针的类型必须相同
当然了,不相同,有的编译器也不会报错,
C给人们的自由,更高的自由就意味着永远的警惕!
有的同学问了说:不相同能怎么样呢?
问题大了!接着看,
四、指针的算数运算
---------------
char a[20];
int *ptr=a;
...
...
ptr++;
在上例中,指针ptr的类型是int*,它指向的类型是int,
它被初始化为指向整形变量a。接下来的第3句中,指针ptr被加了1,
编译器是这样处理的:它把指针ptr的值加上了sizeof(int),
在32位程序中,是被加上了4。由于地址是用字节做单位的,
故ptr所指向的地址由原来的变量a的地址向高地址方向增加了4个字节。
由于char类型的长度是一个字节,
所以,原来ptr是指向数组a的第0号单元开始的四个字节,
----------------------------------------------
此时指向了数组a中从第4号单元开始的四个字节。
---------------------------------------
c语言的数组不做过界检查!
-------------------
char *str[3]={
"Hello,thisisasample! ",
"Hi,goodmorning. ",
"Helloworld "
};
chars[80];
strcpy(s,str[0]);//也可写成strcpy(s,*str);
strcpy(s,str[1]);//也可写成strcpy(s,*(str+1));
strcpy(s,str[2]);//也可写成strcpy(s,*(str+2));
上例中,str是一个三单元的数组,该数组的每个单元都是一个指针,
这些指针各指向一个字符串。把指针数组名str当作一个指针的话,
它指向数组的第0号单元,它的类型是char**,它指向的类型是char*。
*str也是一个指针,它的类型是char*,它所指向的类型是char,
它指向的地址是字符串 "Hello,thisisasample! "的第一个字符的地址,
即 'H '的地址。 str+1也是一个指针,
它指向数组的第1号单元,它的类型是char**,它指向的类型是char*。
------------
chars= 'a ';
int*ptr;
ptr=(int*)&s;
*ptr=1298;
指针ptr是一个int*类型的指针,它指向的类型是int。
它指向的地址就是s的首地址。在32位程序中,s占一个字节,int类型占四个字节。
最后一条语句不但改变了s所占的一个字节,
还把和s相临的高地址方向的三个字节也改变了。这三个字节是干什么的?
只有编译程序知道,而写程序的人是不太可能知道的。
也许这三个字节里存储了非常重要的数据,
也许这三个字节里正好是程序的一条代码,而由于你对指针的马虎应用,
这三个字节的值被改变了!这会造成崩溃性的错误!!!!!!!!!
在指针的强制类型转换:ptr1=(TYPE*)ptr2中,
如果sizeof(ptr2的类型)大于sizeof(ptr1的类型),
那么在使用指针 ptr1来访问ptr2所指向的存储区时是安全的。
如果sizeof(ptr2的类型)小于sizeof(ptr1的类型),
那么在使用指针ptr1来访问ptr2所指向的存储区时是不安全的。
至于为什么,读者结合上例,想想应该会明白的。
五、野指针
什么是野指针?
就是,这个指针是很野,它不老实,它会乱成一气!
没准指向的是没有内容的地址,好呀,好呀,没事呀,没事呀。
过了一会,它偷偷的指向了系统内存!!! 完了,系统让它弄屎了!!!!
使用指针一定要注意:
1.定义出来的指针首先赋为空。
2.使用完毕之后的指针,我是指free();了之后的,也要赋为空。
3.使用的指针不要操作超越了变量的作用范围
愿君细心啊!
六、其他
C语言的精髓就是指针了,
最难学的也是指针,
但是它是C的灵魂所在。 好好学把。:-)
数组名存放的是数组的首地址,也就是指针,但是它是指针常量。
什么是常量,5是常量,2是常量,1是常量,999也是常量。
就是不能改变的,不能让他自加自减,系统会很不高兴的。
int array [10];
t = sizeof (array);
在表达式sizeof(array)中,数组名array代表数组本身,
故这时sizeof函数测出的是整个数组的大小。
好了,就这么多,欢迎多多提提意见,我是个知错就改的银。
欢迎转载,请注明出处。 CSDN ID :Coder_Black