很多小伙伴都老是会碰到疑问,其实还是基础没打扎实,这些题如果你不看答案你能知道多少呢?如果还有很多不知道就证明基础没打扎实,如果你还在入门纠结,如果你还在苦恼怎么入门!小编有个建议,可以加小编弄的一个C语言交流基地,大家可以进入交流基地:565122788,里面新手入门资料,可以说从零到项目实战,都是可以免费获取的,还有程序员大牛为各位免费解答问题,热心肠的小伙伴也是蛮多的。不失为是一个交流的的好地方,小编在这里邀请大家加入我的大家庭。欢迎你的到来。一起交流学习!共同进步!小编等你!还有前面没有看的同学最好从程序员教你学C语言(一)开始看哦,尤其是基础还没打扎实的同学!
第五章:数组和函数
今天先来讲一种特殊的指针---数组,有人可能要问了,数组能是指针吗?我们先往下看,一般书籍对数组的定义:数组是相同数据类型的元素按一定先后顺序排列的集合,就是把有限个类型相同的变量用一个名字命名,然后用编号区分他们的变量的集合,这个名字称为数组名,编号称为下标,下标从0开始。我们先来谈谈为什么会有数组这个东西,假设我们要记录100个学生的成绩,我们没有数组,那我们是不是要定义100个变量来保存这些数据,我想那肯定不是很好受的事,那假如有1000个学生呢,那是不是要定义1000个变量,那不得累死人吗?回想一下,我们前面的知识里也有类似的情况,就是我们讲循环的时候,我们要计算1到100的平方和,假设没有循环,我们要写很多重复的代码,所以循环的出现就是为了减少重复代码的编写,而数组的出现则是为了减少重复的数据定义。下面我们用一个程序来看看一般数组的三种定义和赋初值的方法:
可以看到这三种形式都有个共同点,就是定义数组时一定要确定数组的大小,不然编译器是会报错的,char a[] = {1,2,3,4,5}这种方式其实也通过后面的元素确定了这是一个有5个元素的数组,因为C89标准中是不允许可变长数组出现的,但是在C99标准中,加入了对可变长数组的支持 ,不过支持的编译器不多,而且由于栈溢出的安全问题,没有太多的人敢用这个可变长数组,所以在C11标准中又把它规定为可选实现的功能了,改来改去其实又恨不得改成C89的样子,反正大家就记住不要定义可变长数组就行了。另外我把数组元素的地址也打印出来了,大家观察发现没,char型数组每个元素间隔1,int型数组元素间隔4,而double数组元素间隔8,大家有没有觉得很眼熟呢,其实就和前面的指针运算pBefore和pFollow是一样的,大家可以大胆猜测一下这是怎么回事?不要怕猜错,“大胆猜想与小心求证”本来就是科学研究的基本要求
其实在C语言里,对于数组a,a[i]其实就是*(a+i)的语法糖,语法糖也叫作糖衣语法,指计算机语言中添加的某种语法,这种语法对语言的功能并没有影响,但是更方便程序员使用,所以a[i]和*(a+i)是一样的东西。我们来看看下面的程序就更清楚这一点了:
学习交流群(565122788)
第一种用法array[i]是我们最常用最熟悉的用法,第二种用法*(array+i)就是它的语法糖,第三种用法,我们是定义了一个指针变量p,把它赋值为了数组名array,然后我们也可以使用*(p+i),同时也可以使用和数组一样的方式p[i]来访问数组的元素,这还不算最奇怪的,我们再看看下面的一个for里面,我们居然可以使用i[array]这样的方式来访问数组元素,是不是有人没见过这样的用法。而且我们可以看看我们的数组其实是只包含5个元素的,也就是说我们数组的下标应该是从0~4,但是我们在后面去可以使用5[array]和*(p+5)这样的方式来访问不在数组最后一个元素的下一个元素,这种操作其实就叫做越界,但是C语言里并没有提供数组的越界检查,所以我们再使用数组时一定要特别小心,C语言是一门很简洁实用的语言,但是它也是很危险的东西,它的危险极大程度的来源于它的指针,这是我们前面就讲过的。之所以可以这么用,我们可以大胆猜测下数组名就是一个指针,但是它是一个特殊的指针,它的特殊性我在下面再说。
为什么说数组名是一个特殊的指针呢,主要来自于两种意外的情况,对于某个数组a,
sizeof(a)和&a就会产生我们说的意外情况,我们来看实际的程序:
C/C++学习交流群,欢迎大家一起来交流提升。565122788进群就能获取C语言新手学习大礼包
我们可以看到结果完全出乎我们意料,我们不是说数组名是一个特殊的指针吗,数组在内存里是用连续的内存地址进行存放的,我们的设想应该是数组名是指向第一个元素的地址的指针,但是为什么sizeof(array)不等于4呢,它应该和sizeof(p)一样也等于4啊,而且如果array是指针,那么&array应该是二重指针啊,怎么会array=&array呢?其实这两个问题都设计到编译器了,我简单讲下,声明一个数组时,编译器将根据声明所指定的元素数量为数组保留内存空间,然后再创建数组名,数组名的值是一个常量,指向这段空间的起始位置。
数组名是符号地址常量,在编译时求值并存在编译器的符号表里面,其值就是个内存地址;所以可以认为程序没有给array分配空间,数组名只是代表了那个数组空间;与普通指针变量不一样,指针变量指向一块空间,同时指针变量本身也存储在某个空间;可以认为数组名存在在符号表里,符号表是编译器用的,我们管不到,sizeof这个关键字会去向编译器请求类型的长度,所以当我们使用sizeof(数组)时,其实就是编译器告诉了sizeof数组的长度;array和&array值是一样的,本来对常量取地址是非法的,但是标准组织没有定对数组名取地址是非法还是合法,所以因编译器而异,在我的c-free和VC上是合法的,但是这个东西不属于C标准,也就是说假如以后遇到"&数组"编译器报错的情况,我们也不要埋怨编译器,我们在这里讨论合法的情况,这种情况下array指向的是数组的第一个元素,而&array是指向整个数组,我们从array+1和&array+1就可以看出它们的差别,一个是进行的+4个字节的操作就是向后移动了一个元素的大小,&array+1则进行的是+20(注意十六进制的0022FF34和0022FF20是相差了20的)就是移动了整个数组大小。
这两种意外情况我就说到这了,如果还不懂的就直接背吧。