国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

《C陷阱與缺陷》第三章

tyheist / 1882人閱讀

摘要:而對(duì)于二維數(shù)組,因?yàn)閮?nèi)存連續(xù)性的原因,內(nèi)存并不會(huì)真真的開(kāi)辟一個(gè)二維空間,而是連續(xù)依次存入二維數(shù)組的每個(gè)數(shù)據(jù)。之所以有二維數(shù)組的說(shuō)法是為了分析問(wèn)題方便。二維數(shù)組的實(shí)質(zhì)是一維數(shù)組,只是其元素類型是一維數(shù)組類型。

前言:

  • 博主實(shí)力有限,博文有什么錯(cuò)誤,請(qǐng)你斧正,非常感謝!

  • 博主目前只掌握的c語(yǔ)言,因此本文主要以c語(yǔ)言為背景討論問(wèn)題。編譯器:VS2019

  • 本文是《C陷阱與缺陷》專欄第3章

  • 《C陷阱與缺陷》第一章,我們認(rèn)識(shí)了詞法“陷阱”,第二章認(rèn)識(shí)了語(yǔ)法“陷阱”

  • 第三章讓我們了解一下語(yǔ)義”陷阱“(指針與數(shù)組底層原理,求值順序)

《C陷阱與缺陷》

“詞法”陷阱“語(yǔ)法”陷阱

語(yǔ)義”陷阱“

  • 一句話,哪怕,單詞,語(yǔ)法都對(duì),仍然可能存在歧義或者非我們表達(dá)希望的意思。

  • 同樣對(duì)于c程序,即使語(yǔ)法正確,編譯器對(duì)其也可能是我們非希望的運(yùn)算,因此本博文主要討論:語(yǔ)義“陷阱“。

指針與數(shù)組

指針與數(shù)組之間的聯(lián)系是密不可分,理解數(shù)組必然需要理解指針。

  • 數(shù)組名是不能進(jìn)行自增,自減運(yùn)算的,因?yàn)閿?shù)組名是常地址。

  • C語(yǔ)言只有一維數(shù)組,而且數(shù)組的大小必須在編譯期間就作為常數(shù)確定下來(lái)。
  • | C99標(biāo)準(zhǔn)允許變長(zhǎng)數(shù)組(int arr[m] [n]).但是市面上大部分C編譯器(VS2019)還沒(méi)有完全實(shí)現(xiàn)C99標(biāo)準(zhǔn),但是對(duì)于在線OJ系統(tǒng)允許變長(zhǎng)數(shù)組。另外GCC中實(shí)現(xiàn)了變長(zhǎng)數(shù)組。 |
    | :----------------------------------------------------------- |

  • 為什么說(shuō)C語(yǔ)言只有一維數(shù)組呢?

  • 我們知道變量在內(nèi)存是連續(xù)存放的,同樣一維數(shù)組也是。Exp;arr[m];當(dāng)我們定義一個(gè)一維數(shù)組時(shí),內(nèi)存會(huì)為arr開(kāi)辟大小為:m*sizeof(arr[0])的字節(jié)空間。而對(duì)于二維數(shù)組,因?yàn)閮?nèi)存連續(xù)性的原因,內(nèi)存并不會(huì)真真的開(kāi)辟一個(gè)二維空間,而是連續(xù)依次存入二維數(shù)組的每個(gè)數(shù)據(jù)。之所以有二維數(shù)組的說(shuō)法是為了分析問(wèn)題方便。

Exp: int arr[ 3 ] [3 ] ;

聲明 arr是一個(gè)數(shù)組,該數(shù)組有3個(gè)元素,每個(gè)元素類型是數(shù)組大小為3的一維數(shù)組。

  • 二維數(shù)組的實(shí)質(zhì)是一維數(shù)組,只是其元素類型是一維數(shù)組類型。

  • 多維數(shù)組同理
  • 為什么要在編譯期間確定大小

為了給數(shù)組開(kāi)辟內(nèi)存

  • 對(duì)于數(shù)組我們只要知道2件事:1.數(shù)組大小;2.獲得指向數(shù)組首元素地址的指針。對(duì)于數(shù)組的運(yùn)算就沒(méi)問(wèn)題了
  • 為什么說(shuō)知道數(shù)組首元素地址就可以了

1.指針的運(yùn)算是根據(jù)其指向數(shù)據(jù)類型來(lái)進(jìn)行計(jì)算。

int main(){int arr1[4] = { 5,6,8,4};int* p1 = arr1;//數(shù)組名是一維數(shù)組arr1首元素地址,而首元素是int 類型,因此p類型為intprintf("%d/n", *arr1);printf("%d/n", *p1);printf("%d/n", *(arr1+1));printf("%d/n", *(p1+1));//p的類型是int,因此加一,跳過(guò)int 字節(jié)內(nèi)存。//二維數(shù)組printf("/n");int  arr2[3][2] = {45,4,5,6,78,75 };int(*p2)[2] = arr2;//數(shù)組名是二維數(shù)組首元素地址,而首元素的,類型是 int [2](含有2個(gè)元素的一維數(shù)組)                  //因此p在定義的類型為:int [2];printf("%d/n", arr2[0][0]);printf("%d/n", **p2);//*p后的地址類型為int,而%d需要int型數(shù)據(jù),因此再*;printf("%d/n", arr2[1][0]);printf("%d/n", *(*(p2 + 1)+0));return 0;}

2.以數(shù)組下標(biāo)的形式進(jìn)行數(shù)組的運(yùn)算很正常,但是實(shí)質(zhì)底層原理是指針的運(yùn)算(編譯器在遇到數(shù)組都將其轉(zhuǎn)化為同類型指針)。任何一個(gè)數(shù)組元素的下標(biāo)都可以通過(guò)指針找到。因此我們完全可以依據(jù)指針進(jìn)行數(shù)組的運(yùn)算。

  • 許多程序設(shè)計(jì)語(yǔ)言中都內(nèi)建有索引運(yùn)算,在C語(yǔ)言中索引運(yùn)算是以指針?biāo)阈g(shù)的形式定義的。
int *p=arr;//數(shù)組下標(biāo)為0的元素是arr[0]//實(shí)質(zhì)是*(p+0);//數(shù)組下標(biāo)為1的元素是arr[1]//實(shí)質(zhì)是 *(p+1)int arr[2][3]={0};int (*p)[3]=arr;//數(shù)組下標(biāo)為0的元素是arr[0],但是其類型int*即int的地址,因此二維數(shù)組下標(biāo) (0,0)的arr[0][0]//其實(shí)質(zhì):*(*(p+0)+0)//數(shù)組下標(biāo)為1的元素是arr[1],但是其類型int*即int的地址,因此二維數(shù)組下標(biāo) (1,0)的arr[1][0]//其實(shí)質(zhì):*(*(p+1)+0)

操作符:sizeof()

  • sizeof()是操作符,不是函數(shù)

  • sizeof()用于只用于求數(shù)據(jù)內(nèi)存中所占內(nèi)存的大小單位字節(jié),在()里面不產(chǎn)生的任何影響

  • sizeof對(duì)數(shù)組的一些運(yùn)算,有特殊規(guī)定

C中數(shù)組名代表其數(shù)組首元素地址。但是對(duì)于sizeof()來(lái)說(shuō),其代表整個(gè)數(shù)組。而&arr代表取數(shù)組的地址,因此對(duì)地址求其大小,在32位系統(tǒng)4字節(jié)大小

64位系統(tǒng)下8字節(jié)大小。

指針

  • 任何指針都是指向某種類型的變量,類型決定了指針運(yùn)算跳過(guò)的字節(jié)大小。

  • 只有同類型的指針之間,才能進(jìn)行有效運(yùn)算

int 型指針與int型指針間進(jìn)行運(yùn)算,數(shù)組型指針與數(shù)組型指針間進(jìn)行運(yùn)算。等。。。

  • 同類型指針間的運(yùn)算是有意義的
  • 比如同時(shí)指向數(shù)組的2個(gè)指針,其相減就可以得到2個(gè)指針間的元素個(gè)數(shù)

  • 一旦定義指針,就必須指定其指向,或者對(duì)指針賦值NULL

  • 對(duì)于一維數(shù)組arr[i]與* (p+i)意義一樣,但是[ ]的形式更容易理解,尤其是二維數(shù)組。

  • 因?yàn)?(p+i)== *(i+p),即p[i]=i[p],但是強(qiáng)烈不推薦這種i[p]這種形式

非數(shù)組的指針

  • 字符串

C語(yǔ)言的字符串常量存放在常量區(qū),其代表一塊包括字符串中所有字符以及字符串``結(jié)束標(biāo)志‘/0’`組成 的內(nèi)存區(qū)域的首地址.

因此對(duì)于字符型指針,其不是指向整個(gè)字符串,而指向的是字符串的首地址

另外不同的指針,指向相同字符串,不同指針指向同一地址的字符串

  • 字符串的實(shí)質(zhì)是地址,但是因?yàn)槠涫浅A浚虼瞬荒苄薷钠渲?/li>
char *str="hello";*str="G";//在C語(yǔ)言在是違法,禁止的
  • 打印字符串%s的規(guī)則
  1. 其打印的地址必須是字符串類型

  1. 打印結(jié)束標(biāo)志是‘/0’;

作為參數(shù)的數(shù)組聲明

  • | 在C語(yǔ)言中,我們沒(méi)辦法可以將一個(gè)數(shù)組作為函數(shù)參數(shù)直接傳遞。我們用數(shù)組名傳參,數(shù)組名會(huì)被編譯器自動(dòng)轉(zhuǎn)換為同類型的指針。 |
    | :----------------------------------------------------------- |

Exp:

int fun(int arr[])//編譯器自動(dòng)轉(zhuǎn)換數(shù)組名int fun(int *p)

避免”舉隅法“

  • ”舉隅法“是一種文學(xué)修辭上的手段,類似以微笑代替喜悅,贊許之情。而對(duì)于C語(yǔ)言中,指針是指向某個(gè)數(shù)據(jù),但是并不意味這指針就是該數(shù)據(jù),指針存的是該數(shù)據(jù)的地址。即不要混淆指針指針?biāo)赶虻臄?shù)據(jù)

空指針并非空字符串

C語(yǔ)言的強(qiáng)制轉(zhuǎn)換操作符,可以將一個(gè)整數(shù)X強(qiáng)制轉(zhuǎn)換為指針(即x將變成對(duì)應(yīng)16進(jìn)制內(nèi)存編號(hào)的地址),但是對(duì)于常數(shù)0這個(gè)特殊情況,編譯器保證由0轉(zhuǎn)換的指針不等于任何有效的指針。

當(dāng)0轉(zhuǎn)換為指針時(shí),絕對(duì)不可以對(duì)其解引用(*)

if(p==(char*)0){}//合法if(strcmp(p,(char *)0)){}//非法,庫(kù)函數(shù)strcmp中有對(duì)指針的``解引用``

邊界計(jì)算與不對(duì)稱邊界

邊界計(jì)算:

對(duì)一個(gè)數(shù)組有10個(gè)元素,那么數(shù)組下標(biāo)的范圍是什么呢?

  • 對(duì)于Fortran,Pl/I,Snobol4等程序語(yǔ)言,下標(biāo)從1開(kāi)始,而且這些語(yǔ)言允許自定義數(shù)組下標(biāo)的起始地址。
  • 對(duì)于Algol,Pascal,編程必須顯示的指定數(shù)組下標(biāo)上界與下界
  • 在Basic中聲明一個(gè)10個(gè)元素的數(shù)組,實(shí)際編譯器分配11個(gè)元素的空間,下標(biāo)從0到10

不對(duì)稱邊界:

問(wèn)題:修建一個(gè)100米的護(hù)欄,護(hù)欄間的距離是10米,問(wèn)需要多少欄桿?

答案: 11

這是典型的”欄桿錯(cuò)誤“,也被稱謂”差一錯(cuò)誤“

針對(duì)這種錯(cuò)誤有一種好的方法:

  • 首先考慮最簡(jiǎn)單情況下的特例,然后推廣
  • 仔細(xì)計(jì)算邊界。

而在C語(yǔ)言編程時(shí)如何更好的避免差一錯(cuò)誤呢?

這就需要“不對(duì)稱邊界”:

  • 用第一個(gè)入界點(diǎn)和最后一個(gè)出界點(diǎn)來(lái)表示數(shù)值范圍
  • 取值范圍大小是出界點(diǎn)與入界點(diǎn)差
  • 上界永遠(yuǎn)不小于下界

Exp1:

Exp2:

數(shù)組邊界”溢界“問(wèn)題

int i =0;int arr[10]={0};for(i =0;i<=12;i++){arr[i]=0;printf("%d/n",arr[i])}//這種用法在C中是允許的,因?yàn)榈讓邮侵羔槨?/span>//程序是個(gè)死循環(huán),下面解釋//在Vs2019中,編譯器會(huì)在變量與數(shù)組之間放2個(gè)空內(nèi)內(nèi)存,目的就是防止"溢界"問(wèn)題//內(nèi)存的利用是先高地址,后低地址。//正是因?yàn)檫@個(gè)規(guī)則和變量與數(shù)組的定義順序,當(dāng)arr[12]即是i//此時(shí)i又重新賦值為0,因此進(jìn)入死循環(huán)
ANSI C標(biāo)志明確允許這種用法:數(shù)組中實(shí)際不存在的”溢界“元素地址位于數(shù)組所占內(nèi)存之后,這個(gè)地址可以被用于賦值和比較,但是引用該元素就是非法的。

求值順序

  • 運(yùn)算符的優(yōu)先級(jí)并不決定求值順序。

int a=b*c+d *e+f * g;

//編譯器只知道*比+先計(jì)算,但是不知道開(kāi)始的順序是怎樣的。

即a=(b*c+d *e)+f * g;

或者a=b*c+(d *e+f * g);

  • 但是C語(yǔ)言在規(guī)定了4個(gè)運(yùn)算符的求值順序

四個(gè)運(yùn)算符是:&&;|| ; ?: ; ‘,’ ;

  • &&和||首先對(duì)左側(cè)操作數(shù)求值,具有改變運(yùn)算順序的性質(zhì)即(左側(cè)為真,右側(cè)就不需要求值)

  • a?b:c 先算a,后根據(jù)a算b,c;

  • ,首先對(duì)左側(cè)操作數(shù)求值,然后丟棄該值,再對(duì)下一個(gè)操作數(shù)求值。

  • 分隔函數(shù)參數(shù)的‘’逗號(hào)‘’不是“逗號(hào)運(yùn)算符”。

  • 所有賦值運(yùn)算都不決定求值順序
int i=0while(i<n){y[i]=x[i++]}//因?yàn)橘x值"="的性質(zhì),無(wú)法確定y,x中的i是哪個(gè)值,另外不同編譯器會(huì)有自己的賦值運(yùn)算符求值順序。為避免這個(gè)有爭(zhēng)議的”垃圾代碼“我們可以while(i<n){y[i]=x[i];i++;}

整數(shù)“溢出”

C中的每種數(shù)據(jù)類型都有其取值范圍。

如signed char -128~127

int (-2^31) ~(2^31-1)

等…

  • C語(yǔ)言中存在2種整數(shù)算術(shù)運(yùn)算,有符號(hào)和無(wú)符號(hào)
  • 在無(wú)符號(hào)運(yùn)算中,無(wú)”溢出“一說(shuō)
  • 在無(wú)符號(hào)與有符號(hào)運(yùn)算中,有符號(hào)會(huì)轉(zhuǎn)化為無(wú)符號(hào)型,進(jìn)行運(yùn)算,不在有“”溢出“一說(shuō)
  • 在有符號(hào)運(yùn)算中,存在”溢出“一說(shuō)。另外“溢出”的結(jié)果是未定義的,當(dāng)發(fā)生“溢出”,任何的運(yùn)算都是不安全的。

假設(shè)a和b是2個(gè)非負(fù)整形變量,我們檢驗(yàn)是否會(huì)“溢出”,溢出后就會(huì)成為”負(fù)數(shù)“。

if(a+b<0{..}
在某些機(jī)器上,加分運(yùn)算器講設(shè)置一個(gè)寄存器的4種狀態(tài)之一:正,負(fù),0,溢出。在這種編譯器上,a+b后判斷寄存器是否未”負(fù)“,但是此時(shí)寄存器的狀態(tài)是”溢出“,那么if的檢測(cè)就會(huì)不安全。

更改為:

//方法一if((unsingned)a+(unsigned)b>INT_MAX){}//INT_MAX是整形數(shù)據(jù)的最大取值,定義在庫(kù)中//方法二if(a>INT_MAX-b){}

為main函數(shù)提供返回值

  • 函數(shù)為說(shuō)明返回值的類型時(shí),默認(rèn)為int,main也同理

  • 對(duì)于大多數(shù)C語(yǔ)言都是通過(guò)main的返回值來(lái)告訴操作系統(tǒng)該函數(shù)執(zhí)行是成功還是失敗。

  • 返回0代表成功,非0代表失敗

  • 因此return具有結(jié)束函數(shù)執(zhí)行的效果,在循環(huán)中合理運(yùn)用會(huì)產(chǎn)生奇妙的效果

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/118803.html

相關(guān)文章

  • C經(jīng)典書籍筆記——C陷阱缺陷③(語(yǔ)意陷阱

    摘要:兩個(gè)指針?biāo)赶蛭恢孟嗤瑢?shí)際為同一個(gè)指針。四求值順序總結(jié)語(yǔ)言中只有四個(gè)運(yùn)算符,明確規(guī)定了求值順序和先對(duì)左邊求值,只在需要時(shí)對(duì)右邊求值如此避免除錯(cuò)誤。在結(jié)果為真是返回,結(jié)果為假是返回。原因一只要的值都限制在和的結(jié)果始終相同。 目錄 一、前言 二、字符指針 三、邊界計(jì)算與不對(duì)稱邊界 1.經(jīng)典錯(cuò)誤...

    atinosun 評(píng)論0 收藏0
  • 【帶你刷系列】?c陷阱缺陷(一)

    內(nèi)容介紹 詞法陷阱介紹1 =不同于==2 & 和 | 不同于 && 和 ||3 詞法分析中的貪心法4 整形常量問(wèn)題5 字符與字符串問(wèn)題 詞法陷阱介紹 探討符號(hào)和組成符號(hào)的字符間的關(guān)系,以及有關(guān)符號(hào)含義的一些常見(jiàn)誤解 1 =不同于== =:賦值操作符,將右操作數(shù)的值放到左操作數(shù)的空間里面。 ==:關(guān)系操作符,用來(lái)比較左右兩個(gè)數(shù),若相等則為1,若不相等則為0。 當(dāng) == 寫成 = 的后...

    wpw 評(píng)論0 收藏0
  • JS干貨| 瀏覽器缺陷、瀏覽器的缺陷修復(fù)等五大開(kāi)發(fā)問(wèn)題解決之道

    摘要:圖對(duì)可復(fù)用代碼挑戰(zhàn)最大的五項(xiàng)問(wèn)題五大開(kāi)發(fā)問(wèn)題如下。瀏覽器的缺陷修復(fù)。瀏覽器缺失的功能。復(fù)雜的地方是,當(dāng)前瀏覽器會(huì)在未來(lái)的瀏覽器版本中被修復(fù)。假設(shè)瀏覽器引起常見(jiàn)的網(wǎng)站問(wèn)題為解決瀏覽器使用特殊技巧,將來(lái)瀏覽器發(fā)布新版本修復(fù)了,就會(huì)出現(xiàn)問(wèn)題。 任意一段重要的代碼都需要關(guān)注無(wú)數(shù)的開(kāi)發(fā)問(wèn)題。但是,其中對(duì)可復(fù)用JavaScript代碼挑戰(zhàn)最大的五項(xiàng)問(wèn)題如圖14.2所示。 showImg(https...

    qiangdada 評(píng)論0 收藏0
  • 只看不敲,神也學(xué)不好C---------計(jì)算機(jī)經(jīng)典書籍經(jīng)驗(yàn)分享

    摘要:學(xué)單片機(jī)多去官網(wǎng)上查資料,下載手冊(cè),像我入門的單片機(jī)經(jīng)常去官網(wǎng),還有學(xué)的系列板子,公司的官網(wǎng)的官方例程給的很詳細(xì),在英文視角閱讀對(duì)你大有益處。 目錄 1.C語(yǔ)言經(jīng)典 2.單片機(jī)系列 3.Python方面 4.嵌入式LWip協(xié)議 5.Android 6.C++經(jīng)典書籍 7.Linux開(kāi)發(fā) ...

    FleyX 評(píng)論0 收藏0
  • 如何避免多云網(wǎng)絡(luò)管理的陷阱

    摘要:然而,遷移到多云網(wǎng)絡(luò)并進(jìn)行管理可能是一個(gè)持續(xù)的復(fù)雜過(guò)程。因此,在不評(píng)估這將對(duì)結(jié)合云計(jì)算服務(wù)的客戶產(chǎn)生影響的情況下,服務(wù)可能會(huì)發(fā)生變化。但是,為了充分利用云計(jì)算的好處,組織應(yīng)該注意避免遷移和管理中的潛在缺陷。由于靈活性和彈性的提高,越來(lái)越多的組織采用多云網(wǎng)絡(luò)。然而,遷移到多云網(wǎng)絡(luò)并進(jìn)行管理可能是一個(gè)持續(xù)的復(fù)雜過(guò)程。多云平臺(tái)的管理由于供應(yīng)商數(shù)量的增加而更加復(fù)雜,但這也創(chuàng)造了機(jī)會(huì)。例如,多云網(wǎng)絡(luò)架...

    stonezhu 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

tyheist

|高級(jí)講師

TA的文章

閱讀更多
最新活動(dòng)
閱讀需要支付1元查看
<