目录
数组
不存在的数组
数组的地址
字符型数组
函数
函数的注释
函数与数组
一二维数组做函数的形参与实参
正文
数组
首先单独讲一下数组
不存在的数组
数组实在是太奇妙了,有些老师会介绍说,数组有一维数组、二维数组、三维数组······,也有些老师会说数组其实只有一维的,其他都是一维数组的嵌套。而笔者认为,C语言中重来没有数组,只有指针,或者说数据地址(虽然这么说优点无赖的感觉)。举个例子,对于int a[2];中a[1]来说,大部分老师会怎么解释呢,没错,老师都会说这是a数组里的第二个元素,但是你可以去尝试输出printf("%d\n",1[a]);,会有什么情况呢,会报错吗,答案是不会,而且完全正确!!就连你输出的值与a[1]也别无二般,但你总不能说这是一个数组名叫“2”的数组中第二个元素吧。这其中到底有什么玄关呢,笔者先买个关子,等在数组与指针那一篇里面再详细解读。
我们先来看看数组的其他知识
数组的地址
当我们定义一个数组时,数组的首地址就已经确定,且不能更改,如 int a[10]; 这个数组的首地址就是a,而数组的下标则是对a地址的偏移量。一个数组的地址是连续的。随意更改数组首地址将会报错。
字符型数组
这里有三个字符型数组要注意的点
当说一个数组的长度时,说的就是这个数组的元素个数,但如果是字符型的数组,最后会加上一个“/0"字符(只会在字符串后面自动加,其他的如char a[] = {'a','b'}是不会加的,用sizeof和strlen求都是2)。使用sizeof求长度时,会计入这个字符,长度加一,使用strlen求长度时,不会计入。
根据以上,请问以下两个定义是否有错
char a[5] = {"abcde"}; char a[5] = {'a','b','c','d','e'};
答案是第一个是错的,第二个是正确的。为什么呢,因为字符串后面会自动加一个字符'/0',所以第一个定义实际上有6个字符,超出数组大小,而第二个定义不会加'/0',所以还是5个字符。
当有 char a[] = {0,1,48};的字符型数组被定义时,初始化中,像这样直接写的是数字的,其实记录的是对应字符的ASCII码值,如a[2]其实是ASCII为‘48’的那个字符。想要存储字符,就必须有单引号引起来。
我们再看一组就能更加深入理解sizeof与strlen这两个关键字了
char s[6]={'2','3','\0','6','5'} ; printf("%d\n",sizeof(s)); //输出 “2” char s[6]={'2','3','\0','6','5'} ; printf("%d\n",strlen(s)); //输出 “6” char s[6]={'2','3','\0','6','5','8'} ; printf("%d\n",sizeof(s)); //输出 “6”
可以看出,sizeof会在数组未满时,或者字符串后面自动计数上“/0”结束符,并且不会因为中间遇到“/0”结束符就中止计数,会将所有元素个数计入;而strlen会遇上“/0”就会中止计数,并不计入“/0”结束符。
连续定义数组空间分配问题
两个或多个数组连续定义的时,一般会连续分配空间,不止是数组,当我们连续定义变量时,大概率都会连续分配空间,而当我们不注意空间大小时,可能数据会溢出到其他变量里。
让我们判断一下一下程序会输出上面呢?
char s1[8]; char s2[8] = {"abcde"}; strcpy(s1,"0123456789"); //strcpy:将后面的字符串复制到前面的变量里 printf("%s\n",s1); printf("%s\n",s2);
答案是:
0123456789 89
因为s1与s2的内存分布是连着的,而strcpy不会考虑是否越界,所以字符“89”将越界到s2中去,这也导致s1中没有了结束符,所以会一直读到有结束符的地方,再strcpy完后,也自动加上“/0‘结束符,也就是s2[8] = {'8',9','\0','d','e'}。(当然,有些编译器可以不会出现这种问题)
函数
函数的注释
初学者可能还没有深刻的认识,但已经从事开发的程序员来说,这一点是非常重要的一点。毕竟程序员都讨厌两种人,一种是不写注释的人,还有一种就是让自己写注释的人。很荣幸,我也成了其中之一。所以就让我们在现在做起,做一个会写注释的好程序员吧。
对于语句的注释,那当然就是表达清晰即可,但对于函数的注释,是要很规范的,这样,别人看你的代码和你看别人的代码都能节约不少时间,格式如下:
/*函数名:函数功能 @:形参名1:形参名1的含义 @:形参名2:形参名2的含义 ... @:形参名n:形参名n的含义 返回值: 返回值1:返回值1的含义 返回值n:返回值n的含义 ... 返回值n:返回值n的含义 */
这里涉及到了形参,其实对应的还有一个实参,他们的区别是:
形式参数:定义函数时,指定的参数
实际参数:调用函数时,指定的参数
函数与数组
一二维数组做函数的形参与实参
一维数组做函数的形参与实参
int a[10]; void function(int a[],int n) //形式参数 function(a,10) //实际参数
一维数组做函数的形参与实参
int a[5][10]; void function(int a[][10],int n) //形式参数 function(a,5) //实际参数
到这里,数组与指针的关系就介绍完啦,如果对你有帮助的话,可以点个赞收藏一下哦。后续这个专栏也会出指针与数组和函数的相关文章,相信我,那个才是真的有趣!!