`
jinghuainfo
  • 浏览: 1515068 次
  • 性别: Icon_minigender_2
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

C语言数组与指针详解

 
阅读更多

++++++++++++++++++++++++++++++++++++++++++

本文系本站原创,欢迎转载! 转载请注明出处:

http://blog.csdn.net/mr_raptor/article/details/6844691

++++++++++++++++++++++++++++++++++++++++++

好多同学都说:“老师,我看到指针就晕!”,说实话,见过晕血的,见过晕车的,晕指针的到是第一次听说!

我们先来分析一下晕车的原理,再来对比一下为什么晕指针。

晕车,是因为耳朵里的一个器官对外界的振动太敏感,导致身体调节功能紊乱,系统不能正常工作,轻则,晕点,中则,吐点,重则,“重启”(倒地)。时间长了,知道自己晕车,于是,看到公交车,TAXI,火车,自行车,都晕!这样的病就大了,上升到心理疾病了。这可得治。我们都明白上面的道理,怎么克服晕车呢?你不可能避免做车,你要去面对,怎么克服晕车也很简单,先是功心,“口服不如心服”,所以先治心病:建立信心。经常试着去做晃动不大的车,最好听着MP3,这样能减缓心理对晕车的敏感度。时间长了,慢慢的克服了心理作用,然后就要上升到治根的阶段了,要去试着挑战做公交,TAXI,船。

上面都是个人的一些见解,上大学时,要是不学计算机就去学医了!

回来我们开始治“晕指针”这号病,其实很多同学晕指针,也是因为自己基础不好(身体素质不好),刚开始学的时候,不用心,还没有弄的很明白,一编程(有的同学4年都没编过一个程序)就错,形成了恐惧心理,其实C指针非常灵活,它对学生的要求也比较高,说白了,它要求有计算机的组成原理一些基础,如果有的话,你回头看指针,So easy!

我们先开始“攻心”。

1. 晕指针,唐式偏方一:“投石问路”

#include <stdio.h>

int main(void)

{

char* str = "ABCDEFGHIJKL";

int* pInt = (int*)str;

printf("%c\n%c\n",*(str+1),*(char *)(pInt+1));

return 0;

}

上面的程序如果你要是灰常EASY的回答出来,那你的功底已经不错了!心病是估计没有了,可以进入吃药保养阶段了(做题)。

如果上面的题看起来就特别费劲,看来你晕的不轻,得治。要不问题会很严重。

基于上面的小测试,进入唐式第二方:“理气静心”

我们先看把C指针的基础打好。在这之前先来复习下变量和常量,有的同学会问,这是为什么,我只能告诉你,你晕C指针,是因为你从刚开始有问题就没有重视,或者你忽略了问题的严重性,导致现在的情况,这也没有办法,中国的教育就不重视这一块,说实话,大学里讲C语言的,很多都没有太多的讲到变量和常量,这是很XXX的。我们开始治疗。

  • 常量:其值不发生改变的量称谓常量。常量又称为字面量,表述常数。它们可以和数据类型结合起来分类,比如:整形常量,浮点型常量,字符常量= =,常量是可以不经过定义和初始化,而直接引用的

常量又分为:直接常量和符号常量。

直接常量又叫做:字面常量。如12,0,4.6,‘a‘,“abcd”

符号常量如宏定义的:#define PI 3.14

特点:常量的值在其作用域内不会发生改变,也不能再被赋值。其在出现时就被当作一个立即数来使用。也就是说,只能被访问,被读,而不能被写,被赋值。

  • 变量:其值可以改变的量称这变量。一个变量应该有一个名字,在内存中占据一定的存储单元。变量在使用前必须要定义

  • 变量名和变量的值:

变量名是在,变量的声明的时候,该名字就和内存中一块地址绑定在一起了。可以通过变量名直接找到对应的内存区域,也可以通过地址找到其内存区域。因此有了引入指针的依据。

变量的值是变量所对应的内存区域内存放的二进制序列。当该变量被声明成整形时,内存区域的二进制序列被以整形的形式翻译出来。比如:int a = 97; 其在内存中是以97的二进制形式存放的,当使用时,他会被以10进制形式表现出来。同样的char a = ‘a’; a的ASIIC码是97,也是以97的二进制存放的,使用时,会被以字符a的形式表现出来。

如果变量是一个指针变量,那么指针变量里的二进制序列被翻译成一个地址,

比如:

int a = 10;

int * p;

p = &a;

这里的指针变量p的值是a的地址(p = &a),它是什么啊?看下图:

声明了一个变量a,它是整型,被赋值为10(它的值被翻译成整数),要形成这种思维,时间长了你就知道这样做的好处了,又声明了一个指针变量p,它是Int类型的(它指向的地址里面要装Int),然后将a变量的地址(ox2c406b24)给了p,这儿注意下。现在访问a里面的值有了两种方式(其实本来也有这两种),一个是通过变量名a(绑定的),一个是通过地址ox2c406b24,地址ox2c406b24给了p了,p指针变量(指针变量是变量,这个思维很重要)里面存放的是ox2c406b24(a的地址),那么现在访问a可以通过:

printf("%d\n", a); //通过变量名

printf("%d\n", *p); //通过指针变量

如果你现在上面的都很明白了,那你有了晕指针好转的迹象,只是迹象,(迹象だけです^_^)。现在验证下是不是真的有好转:


1、

char ch = 'a';

int a = (int)ch;

printf("%d %c\n", a, ch);

ch是什么? ch 里面是什么? a是什么? a里面又是什么?打印什么?

2、

int add = 0x123456;

int * p = (int*)add;

add是什么?add里是什么? P是什么? P里面是什么? *p 又是什么?

嘿嘿,晕不?别慌,再来。。。

3、

#define PI 3.14

int a = PI;

printf("%d\n", a);

上面的程序有没有问题?

4、

#define PI 3.14

printf("%d\n", PI);

程序有没有问题?

5、

#define PI 3.14

int a = PI;

PI = 1.85;

int b = PI;

printf("%d%d\n", a, b);

程序有没有问题?

差不多头疼的不行了吧,没事,这是药劲,好药都这样。

最后一个:

6、

char *str = "abcdef";

printf("%s\n", str);

*str = "fedcba";

printf("%s\n", str);

str[2] = 'C'; //修改第三个字符为大写

printf("%s\n", str);

程序有没有问题?

好,第一方到此为止,老中医要休息会。


上一方药劲比较重,年轻人吗,口味要重点。现在给你们点解药:

1、主要是测试类型转换,还有对变量的理解是否到位。

2、对变量的值的理解是否到位

3、对常量,宏替换的理解是否到位

4、对宏替换的理解是否到位

5、能否修改常量的值?

6、能否修改字符串常量的值?

通过上面我们可以学到以下内容,重点,记下,考试要考(这话在学校里很耳熟,但是XXX的这样很不负责任):

1、不管什么常量,其值是编译是固定好的,不能再被改变

2、变量里的值,和其数据类型没有关系,它只是一个二进制序列,不要将电脑想的多聪明,它只认识0, 1,只不过,这一堆01被其类型限定了其代表的意义,类型为整形就是其值,指针地址类型,就是内存里的一个地址,字符型,就是其无符号整形代表的ASCII码。

3、字符串,是常量(字符指针指向一字符串,不是数组,数组和指针的区别在后面),其值不能再被改变,char * str = "abcdef";这行代码的意思是告诉编译器:老编啊,我这儿有个抽屉(指针变量str),你给我找个房间(存放字符串的内存空间),找到后,把钥匙给我放到这个抽屉里。老编去找客房经理,找到后问:有没有空房间啊,有的话给我一间,一哥们要开房,客房经理去查房间入住情况(内存管理),最后说,这儿有一间,它是老总的房间,你要不先用着,你用没事,你可别乱动里面的东西,你要是动的话,估计你那哥们就被KILL掉,老板是黑社会的,不过,你用没事。于是,老编将老总房间钥匙给我放到了抽屉(指针变量str)里,这样,我打开抽屉(指针变量),拿出房间(内存空间)钥匙(指针),去开房了,老编告诉的,别乱动,用没事(读取),一定不能破坏里面的结构(修改数据内容),要是乱动(修改数据),会出乱子的(段错误),然后你会被KILL的(异常结束程序)。如果有两个人,就会Double kill,老板就GOD LIKE了。

明白了常量和变量的区别后,再进行后面的学习就轻松点了!下面我们来看下指针的双胞胎哥们,数组。一般晕车人里面有很多也晕飞机,晕船,所以呢,晕指针的,也一般都会晕数组。

  • 数组:我们先咬文嚼字一下,数指数据,组,就是小组,由数据组成的小组,就叫数组(学计算机的,不光要学好计算机,也要学好语文,偶尔还要懂点医学,你要是经常看计算机图书,你看台湾人写的书,都有很多文言文在里面,我们这点做的完全没有台胞做的好,所以人家计算机牛啊,世界上的电子代工,台湾占了绝大数比例)。

数组有几个特点一定要注意,看到数组就要想到:

1、 数组里面的数据类型是相同的,小组里面的成员肯定要一样的啊,驴堆里站一马,驴马不分,鸡窝里蹲一丹顶鹤,鹤立鸡群,这都是不合群的东西,计算机里面也讲“和谐”。我们顺便看下数据的基本类型:int float double char 这些是基本类型,所以它们可以存在以下类似数组:int a[10], float f[10], doule d[10], char str[10]; 它们每一个都有10个元素,每一个元素的类型都是其前面声明的类型。我们是学嵌入式的,我们不能光看到表面的东西,我们要看到底,好东西是走了光才叫好,光有好东西,别人不知道也不行。其实数组在内存中是连续分配的,如下图:

定义了一char型数组a,它有6个元素,分别是'A', 'B', 'C', 'D', 'E', 'F',它们在内存里面是连续存放的,每个元素占用一个字节。 强烈谴责那些将'A' 当成"A"的人,前者是单个字符,后者是字符串,鄙视那些,问“字符和字符串有什么区别?”的人,不知道字符和字符串的区别,那你吃过羊肉串吗?单个羊肉块能叫串吗,多个羊肉块串起来才叫串,所以字符是单个,字符串可以是多个字符组成的数组(最后有一个结束符号\0),羊肉块串起来一烤就叫烤羊肉串,字符串一拷,叫拷贝串,学计算机哪有那么简单,要是我开个学校,入学前要体检,测视力,量身高体重,....,三围什么的,不行的PASS。

仔细看上面的图,每一个字符都有一个地址,它们的跨度是1(字节),数组的每个元素都可以通过下标来访问,下标(index, for循环变量经常用i就是因为这个东西)其实就是他在数组中的位置,也就是他的号,拉10个人过来,报数,1,2,3.....,只不过,C语言里数组的下标是从0开始的,在计算机里面能访问的最小单位就是字节了,也就是地址只能找到以字节为单位,不能再精确了。数组名a和变量名道理上是一样的,在编译时就和数组的首地址绑定上了,a就是数组的首地址,变量名和数组名其实都是方便人们记忆而取的代号,它在代码反汇编后,其实不存在变量名的,回想下,访问数据有两种方式,既然反汇编后的代码不存在变量名,只能通过那种方式访问数据了,那就是地址。数组中的每一个元素,可以被看成一个变量(回想下变量的特点),因此其可以被读,写,修改,爱怎么得瑟怎么得瑟,你只要不把房间拆了(内存空间),怎么折腾都行。每一个元素的地址都可以通过首地址的偏移量(offset这个词记住,四级里没有)来算出来,这个偏移量说白了就是下标了。比如上面的图中:'C'所在地址0x28c5,相对首地址0x28c3的偏移量是2,那a[2]也可以访问'C'了,注意一点,a代表数组代表数组的首地址代表数组第一个元素的地址,这“三个代表”一定要记住。那a+1呢,a是三个代表,那它是第一代表还是第二个代表,还是第三个代表呢?这儿的a应该是第一个元素地址的意思表示的意思应该是&a[0],a+1是个地址的算术运算,而数组是个一维数组,数组中每个元素都是一个字符,a+1就是a当前地址0x28c3的下一个元素的地址0x28c4(结合图来看),也就是'B'的地址,如果a是一个二维数组名的话,那么二维数组被编译器理解为一个一维数组,一维数组里的每一个元素是一个一维数组,有点乱,别慌,屡一下,看下图:

a是个二维数组,它有3X4=12个字符元素,而编译器将它认为是一个一维数组,它有三个元素,分别是a[0], a[1], a[2], 每一个元素是一个含有4个字符的数组,那么a+1的话,是&a[0]的地址,a[0]是一个一给数组,取了一个数组的地址,再加1 ,肯定就是下一个数组的地址了,就是a[1]上图,那么这个时候它的地址增加可不再是1了,而是列数4,也就是说是a这个二维数组中元素(一维数组)的长度。

回到前面那个图:a[5] - a[3] = ? 地址的运算,这里算的也是元素的相对偏移量,结果当然是2,虽然0x28c8- 0x28c6 = 2结果也是2,不过意义不一样,如果数组类型换成int a[10], 那么a[5] - a[3] 还是2,不是8,这个直接用下标相减就对了。

因此我们可以总结一下,指针相加减时,要看类型,打狗看主人,指针加减看类型,其运算的值n*sizeof(类型),比如:字符型地址加1 ,其实地址加也是sizeof(char) = 1,整形地址加1,地址加sizeof(int) = 4,结构体数组中,地址加1,地址加sizeof(结构体)。

通过上面的分析可以看出,数组有很多地方很相似,其实,编译器这哥们处理数组的时候就是将其看成指针来处理的,没有办法,编译器只认地址,变量名一直都是被编译器藐视的。

看一个程序图:

程序图这个名词是我自创的,因为好多东西说不清,道不明,一个图全搞定。

上面的执行结果是什么?已经很清楚了。休息会。

上面的例子结果是:B和E

++++++++++++++++++++++++++++++++++++++++++

本文系本站原创,欢迎转载! 转载请注明出处:

http://blog.csdn.net/mr_raptor/article/details/6844691

++++++++++++++++++++++++++++++++++++++++++

分享到:
评论

相关推荐

    C语言数组和指针详解

    C语言数组和指针详解,C语言的灵魂!总结详细,实例经典!

    c语言指针数组-·详解数组指针与指针数组

    ·详解数组指针与指针数组 ·数组指针 ⾸先我们需要了解什么是数组指针以及什么是指针数组,如下图: int *p[5]; int (*p)[5]; 数组指针的意思即为通过指针引⽤数组,p先和*结合,说明了p是⼀个指针变量,指向⼀个...

    二维数组与指针详解

    详细讲述了二维数组与指针之间的联系,对于学习C语言,理解指针数组吗,数组指针,数组与指针之间的关系有重要的帮助。仔细学习完该文档,详细你不会再为指针和数据而困惑。

    数组的定义,初始化和使用,C语言数组详解.pdf

    c语言数组 数组可以说是目前为止讲到的第一个真正意义上存储数据的结构。虽然前面学习的变量也能存储数据,但变量所能存储的数据很有限。不仅如此,数组和指针(后续会讲)是相辅相成的,学习数组可以为学习指针打下...

    C语言:数组、指针与字符串(简易入门、精髓)

    数组例程详解 指针例程详解 字符串例程详解 PPT详细描述数组、指针和字符串在C程序中的应用

    C语言 数组指针详解及示例代码

    本文主要介绍C语言 数组指针,这里整理了相关资料并附示例待会及实现结果,帮助大家学习C语言中指针的知识,有需要学习此部分内容的朋友可以参考下

    最全的C语言指针详解

    指针定义与使用、指针与函数、指针与数组、指针与字符串、指针数组与多级指针 、指针与动态内存分配

    C语言 指针与数组的详解及区别

    C语言 指针与数组的详解及对比 通俗理解数组指针和指针数组 数组指针: eg:int( *arr)[10]; 数组指针通俗理解就是这个数组作为指针,指向某一个变量。 指针数组: eg:int*arr[10]; 指针数组简言之就是存放指针的数组...

    c语言中详解指针.doc

    c语言中详解指针 1 指针是什么 2 指向数据对象的指针 3 指针的应用与误用 4 指针与一维数组 5 指针的应用(二) 6 高维数组名 7 变量长度数组—VLA(C99) 8 数组类型的字面量(C99) 9 指针与结构体 10 指针与函数

    C语言基础及指针数组的详解

    对C语言相对比较难点的知识点进行详解。内容容易理解,对知识点的拓展!

    C语言 指针数组详解及示例代码

    本文主要介绍C语言 指针数组,这里提供详细的资料和简单示例代码以便大家学习参考,有需要学习的小伙伴可以参考下

    c语言---指针详解

    指针是C语言中的重要概念,也是C语言的重要特色。使用指针,可以使程序更加简洁、紧凑、高效。...9.5 返回指针值的函数 9.6 指针数组与主函数main()的形参 9.7 函数的指针和指向函数的指针变量

    C语言多级指针专项详解图示分析程序代码

    这是我自己写的关于多级指针的使用方法,讲解简短使用

    详解C语言中的指针与数组的定义与使用

    内存的分配与释放 c语言分配内存的方法 // malloc(需要分配的大小); 这里的分配的大小需要对齐的2的指数 void *mem = malloc(size); 释放内存 // 一般分配的内容都是在堆空间中的 // 如果使用完不去释放会照成...

    详解C语言中的函数、数组与指针

    主要介绍了C语言中的函数、数组与指针,本文给大家介绍的非常详细,具有参考借鉴价值,需要的朋友可以参考下

    C语言 指针与二维数组详解

    二维数组在概念上是二维的,有行和列,但在内存中所有的数组元素都是连续排列的,...C语言中的二维数组是按行排列的,也就是先存放 a[0] 行,再存放 a[1] 行,最后存放 a[2] 行;每行中的 4 个元素也是依次存放。数组 a

Global site tag (gtag.js) - Google Analytics