C数组知识点(越界风险、数组传递、栈溢出)

一、一维数组

1.数组初始化

数组初始化

2.数组越界会导致的风险

数组越界

数组越界就是访问数组元素的时候,索引超过了定义的数组长度,导致访问了申请内存空间之外的内存地址,这样会带来很大的风险。如上图中的b[10]赋值操作,就会导致风险。

首先,在b[10]=100;语句前打了断点,这时候分别打印下a、b数组的地址,在打印一下a的各元素值。

过掉断点,再进行a数组各元素的打印。

这时候会发现,a[2]的值竟然由3变成了100。这个数值的改变其实就是数组b的越界操作b[10]=100;导致的,接下来分析一下原因。

由上面打印的a、b数组的地址分析:

a数组的起始地址:0x00007ffeefbff520

b数组的起始地址:0x00007ffeefbff500

 a比b先进行定义,而a的地址高于b的地址,说明栈空间是由上至下(高地址到低地址)分配空间的。

通过打印b[0]和b[1]的地址:0x00007ffeefbff500和0x00007ffeefbff504可知一个元素分配了四个字节空间

故可推知:b[4]地址为0x00007ffeefbff510,与数组a的首地址相差16字节空间,打印证实一下

所以可以类比推测,如果用数组b的话,只要使用下标8~12便能访问到a数组的1~5号元素,果不其然

通过对b[10]的赋值操作,成功的对a[2]的元素值进行了更改。

故数组越界访问是很危险的,有可能会改掉我们无法预料到的地址空间的数值,甚至可能导致程序崩溃

3.数组打印,数组的传递(用一维举例)

首先在main函数中初始化一个数组,而后调用函数传入数组,对数组元素打印。

在打印的时候,有时候我们会这样判断数组的长度,企图利用sizeof求出数组总长度,除以每个元素的长度,就能求出元素的个数

但输出却不尽人意

按理来说数组初始化五个整形元素,大小应该是20字节,而一个int元素是4字节,应该是五个元素都能打印出来。为什么会这样?我们分别打印一下sizeof(arr)和sizeof(int)

打印发现sizeof(int)正常,但是sizeof(arr)却不是我们想象中的20字节,这是为什么呢。接下来我们再分别打印一下main函数中a数组和子函数中arr数组的类型。

可以看出a和arr完全不是同一种类型,a是数组类型,而arr却是(int *)类型。

其实是因为在main函数中定义的数组a的类型为(int [5])类型,但是经过参数传递到arr_print()方法中的,并不是这个数组本身,而是传的一个(int *)类型的指针变量,即子函数中的arr,其实是一个指针变量,该指针变量中保存着a数组的首地址

故当我们使用sizeof(arr)/sizeof(int)来计算数组的元素个数的时候,其实sizeof(arr)计算的结果是指针变量

arr的大小,而不是数组的大小。

总结一下:一维数组名其实就是代表了该数组的首元素地址,数组名作为参数传递的时候,传递的是数组的首地址(由指针变量装载),而不是整个数组

4.栈空间溢出

1.一般使用数组不会导致栈空间溢出(stackoverflow),当程序运行的时候,运行到某一个函数时,系统会将函数压入栈,为该函数分配一定大小的栈空间,windows下是1MB,linux系统下是10MB(可以更改),当我们初始化数组时,如果数组的长度过大,便会导致栈空间溢出,报stackoverflow的错误。

2.第二种常见的栈溢出,便是递归所导致的栈溢出,由于递归层层调用函数,如果递归次数过多,便有可能将分配到的栈空间消耗殆尽,发生栈溢出。

二、二维数组

1.初始化

2.数组输出,数组传递

首先使用上图中的a数组进行测试说明。先写一个负责输出的子函数,第一个参数接收数组,第二个参数为数组行数。

这里要对二维数组的传递做一下说明:(使用的是上面定义的a数组)

二维数组的传递,跟一维数组不太一样

(1)一维数组名作为参数传递,其实子函数接收到的是一个(int *)类型的整型指针变量,其中装载着数组的首元素的地址

(2)二维数组名作为参数传递,其实子函数接收到的是一个{ int(*)[4] }类型的指针变量(上图中arr),即arr是数组指针。如下图打印,可以看出a的类型为int [3][4];而传到子函数中后,arr为int (*)[4]类型。

本例中二维数组a是三行四列,该数组指针arr指向二维数组的第一行(即第一行的一维数组int[4])的内存地址空间,注意是第一行的一维数组的整个地址空间,而不是数组的首元素的地址空间,即当我们对该数组指针进行自加移动操作,移动步长不再是一个整形变量的长度,而是一个int[4]数组的长度,即如果我们对(arr+1)进行内容打印,其实是比arr的内容多出16个字节,正好是每一行的四个整形元素所占空间,如图

arr作为一个数组指针,指向a数组的第一行的一维数组的地址空间,(arr+1)后便是指向第二行的一维数组的地址空间。

弄清楚二维数组的传递后,做一个小拓展,我们将原本的子函数做如下改动。

将arr[][]的列数由原来的4变为了3,而在传参的时候,将行数改成4行,即原本的a数组是3*4的结构,现在我们试图将数组按照4*3的结构传过去试图打印。

其实这样表面上是更改了数组的形状范围,看似会发生错误,但其实是可以正常输出的,C的灵活就在于此处。因为a数组的地址在内存中是连续的,原来的三行四列,只是在那一片连续的地址空间中,分为了三份,每份16字节,而我们传参的时候,把行列互换了,其实就是将a原本的连续地址空间分为了四份,每一份12字节,并没有超出数组a的地址空间,所以是可以正常打印的,打印结果如下

这种做法会导致子函数调用的时候报警告,因为辨析器判断出我们子函数中arr的接收类型与a数组的类型不匹配,虽然不影响打印输出,但是也可以通过一个类型转换让警告消失,即将a强转为我们设定的参数类型即可。

二维数组部分在指针笔记中也将进行较详细的记录。

三、字符数组

如图我们可以看见,无论是a还是b,我们在初始化的时候,定义的数组长度都要比赋的字符数多一。那么为什么数组长度要比赋值的字符数多1呢?

因为其实每个字符串都是以'\0'作为结束的,在我们对字符数组赋值时,系统会自动在末尾加上一个'\0'作为结束符。这样在我们输出打印字符串的时候,打印到'\0'时,就会停止。如果多留一个位置,'\0'就无法录入数组。

那么为什么一定要加'\0'呢,或者说,如果偏要写成b[5] = "hello";这样呢

这就要说%s打印了,众所周知%s是专门用来输出字符串的,而%s输出字符串的时候,它判断何时停止的标志就是'\0',如果我们对数组赋值的时候,没有留出'\0'的位置,或者没有手动加上'\0',那么打印就不会停止。

他(%s)首先会在字符数组的地址空间中取值打印出来,而后因为没有'\0'标志停止,打印就会继续打印b字符数组的后续地址空间中的数值,这时候就会出现我们所谓的"乱码"。如图用%s打印b[5]的结果:

那么乱码有时候也不是无穷打印的(如上图),那么打印什么时候结束呢。

答案是:当打印遇到后续地址空间中的0x00字节时,即'\0',才会停止打印。

注:%s虽然看起来是直接输出字符串,但其实依旧是通过for循环进行单个字符依次输出的方式实现的。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,033评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,725评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,473评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,846评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,848评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,691评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,053评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,700评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,856评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,676评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,787评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,430评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,034评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,990评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,218评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,174评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,526评论 2 343

推荐阅读更多精彩内容