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

資訊專欄INFORMATION COLUMN

《C陷阱與缺陷》第三章

tyheist / 1861人閱讀

摘要:而對于二維數組,因為內存連續性的原因,內存并不會真真的開辟一個二維空間,而是連續依次存入二維數組的每個數據。之所以有二維數組的說法是為了分析問題方便。二維數組的實質是一維數組,只是其元素類型是一維數組類型。

前言:

  • 博主實力有限,博文有什么錯誤,請你斧正,非常感謝!

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

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

  • 《C陷阱與缺陷》第一章,我們認識了詞法“陷阱”,第二章認識了語法“陷阱”

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

《C陷阱與缺陷》

“詞法”陷阱“語法”陷阱

語義”陷阱“

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

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

指針與數組

指針與數組之間的聯系是密不可分,理解數組必然需要理解指針。

  • 數組名是不能進行自增,自減運算的,因為數組名是常地址。

  • C語言只有一維數組,而且數組的大小必須在編譯期間就作為常數確定下來。
  • | C99標準允許變長數組(int arr[m] [n]).但是市面上大部分C編譯器(VS2019)還沒有完全實現C99標準,但是對于在線OJ系統允許變長數組。另外GCC中實現了變長數組。 |
    | :----------------------------------------------------------- |

  • 為什么說C語言只有一維數組呢?

  • 我們知道變量在內存是連續存放的,同樣一維數組也是。Exp;arr[m];當我們定義一個一維數組時,內存會為arr開辟大小為:m*sizeof(arr[0])的字節空間。而對于二維數組,因為內存連續性的原因,內存并不會真真的開辟一個二維空間,而是連續依次存入二維數組的每個數據。之所以有二維數組的說法是為了分析問題方便。

Exp: int arr[ 3 ] [3 ] ;

聲明 arr是一個數組,該數組有3個元素,每個元素類型是數組大小為3的一維數組。

  • 二維數組的實質是一維數組,只是其元素類型是一維數組類型。

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

為了給數組開辟內存

  • 對于數組我們只要知道2件事:1.數組大小;2.獲得指向數組首元素地址的指針。對于數組的運算就沒問題了
  • 為什么說知道數組首元素地址就可以了

1.指針的運算是根據其指向數據類型來進行計算。

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

2.以數組下標的形式進行數組的運算很正常,但是實質底層原理是指針的運算(編譯器在遇到數組都將其轉化為同類型指針)。任何一個數組元素的下標都可以通過指針找到。因此我們完全可以依據指針進行數組的運算。

  • 許多程序設計語言中都內建有索引運算,在C語言中索引運算是以指針算術的形式定義的。
int *p=arr;//數組下標為0的元素是arr[0]//實質是*(p+0);//數組下標為1的元素是arr[1]//實質是 *(p+1)int arr[2][3]={0};int (*p)[3]=arr;//數組下標為0的元素是arr[0],但是其類型int*即int的地址,因此二維數組下標 (0,0)的arr[0][0]//其實質:*(*(p+0)+0)//數組下標為1的元素是arr[1],但是其類型int*即int的地址,因此二維數組下標 (1,0)的arr[1][0]//其實質:*(*(p+1)+0)

操作符:sizeof()

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

  • sizeof()用于只用于求數據內存中所占內存的大小單位字節,在()里面不產生的任何影響

  • sizeof對數組的一些運算,有特殊規定

C中數組名代表其數組首元素地址。但是對于sizeof()來說,其代表整個數組。而&arr代表取數組的地址,因此對地址求其大小,在32位系統4字節大小

64位系統下8字節大小。

指針

  • 任何指針都是指向某種類型的變量,類型決定了指針運算跳過的字節大小。

  • 只有同類型的指針之間,才能進行有效運算

int 型指針與int型指針間進行運算,數組型指針與數組型指針間進行運算。等。。。

  • 同類型指針間的運算是有意義的
  • 比如同時指向數組的2個指針,其相減就可以得到2個指針間的元素個數

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

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

  • 因為*(p+i)== *(i+p),即p[i]=i[p],但是強烈不推薦這種i[p]這種形式

非數組的指針

  • 字符串

C語言的字符串常量存放在常量區,其代表一塊包括字符串中所有字符以及字符串``結束標志‘/0’`組成 的內存區域的首地址.

因此對于字符型指針,其不是指向整個字符串,而指向的是字符串的首地址

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

  • 字符串的實質是地址,但是因為其是常量,因此不能修改其值
char *str="hello";*str="G";//在C語言在是違法,禁止的
  • 打印字符串%s的規則
  1. 其打印的地址必須是字符串類型

  1. 打印結束標志是‘/0’;

作為參數的數組聲明

  • | 在C語言中,我們沒辦法可以將一個數組作為函數參數直接傳遞。我們用數組名傳參,數組名會被編譯器自動轉換為同類型的指針。 |
    | :----------------------------------------------------------- |

Exp:

int fun(int arr[])//編譯器自動轉換數組名int fun(int *p)

避免”舉隅法“

  • ”舉隅法“是一種文學修辭上的手段,類似以微笑代替喜悅,贊許之情。而對于C語言中,指針是指向某個數據,但是并不意味這指針就是該數據,指針存的是該數據的地址。即不要混淆指針指針所指向的數據

空指針并非空字符串

C語言的強制轉換操作符,可以將一個整數X強制轉換為指針(即x將變成對應16進制內存編號的地址),但是對于常數0這個特殊情況,編譯器保證由0轉換的指針不等于任何有效的指針。

當0轉換為指針時,絕對不可以對其解引用(*)

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

邊界計算與不對稱邊界

邊界計算:

對一個數組有10個元素,那么數組下標的范圍是什么呢?

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

不對稱邊界:

問題:修建一個100米的護欄,護欄間的距離是10米,問需要多少欄桿?

答案: 11

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

針對這種錯誤有一種好的方法:

  • 首先考慮最簡單情況下的特例,然后推廣
  • 仔細計算邊界。

而在C語言編程時如何更好的避免差一錯誤呢?

這就需要“不對稱邊界”:

  • 用第一個入界點和最后一個出界點來表示數值范圍
  • 取值范圍大小是出界點與入界點差
  • 上界永遠不小于下界

Exp1:

Exp2:

數組邊界”溢界“問題

int i =0;int arr[10]={0};for(i =0;i<=12;i++){arr[i]=0;printf("%d/n",arr[i])}//這種用法在C中是允許的,因為底層是指針。//程序是個死循環,下面解釋//在Vs2019中,編譯器會在變量與數組之間放2個空內內存,目的就是防止"溢界"問題//內存的利用是先高地址,后低地址。//正是因為這個規則和變量與數組的定義順序,當arr[12]即是i//此時i又重新賦值為0,因此進入死循環
ANSI C標志明確允許這種用法:數組中實際不存在的”溢界“元素地址位于數組所占內存之后,這個地址可以被用于賦值和比較,但是引用該元素就是非法的。

求值順序

  • 運算符的優先級并不決定求值順序。

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

//編譯器只知道*比+先計算,但是不知道開始的順序是怎樣的。

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

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

  • 但是C語言在規定了4個運算符的求值順序

四個運算符是:&&;|| ; ?: ; ‘,’ ;

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

  • a?b:c 先算a,后根據a算b,c;

  • ,首先對左側操作數求值,然后丟棄該值,再對下一個操作數求值。

  • 分隔函數參數的‘’逗號‘’不是“逗號運算符”。

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

整數“溢出”

C中的每種數據類型都有其取值范圍。

如signed char -128~127

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

等…

  • C語言中存在2種整數算術運算,有符號和無符號
  • 在無符號運算中,無”溢出“一說
  • 在無符號與有符號運算中,有符號會轉化為無符號型,進行運算,不在有“”溢出“一說
  • 在有符號運算中,存在”溢出“一說。另外“溢出”的結果是未定義的,當發生“溢出”,任何的運算都是不安全的。

假設a和b是2個非負整形變量,我們檢驗是否會“溢出”,溢出后就會成為”負數“。

if(a+b<0{..}
在某些機器上,加分運算器講設置一個寄存器的4種狀態之一:正,負,0,溢出。在這種編譯器上,a+b后判斷寄存器是否未”負“,但是此時寄存器的狀態是”溢出“,那么if的檢測就會不安全。

更改為:

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

為main函數提供返回值

  • 函數為說明返回值的類型時,默認為int,main也同理

  • 對于大多數C語言都是通過main的返回值來告訴操作系統該函數執行是成功還是失敗。

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

  • 因此return具有結束函數執行的效果,在循環中合理運用會產生奇妙的效果

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/118803.html

相關文章

  • C經典書籍筆記——C陷阱缺陷③(語意陷阱

    摘要:兩個指針所指向位置相同,實際為同一個指針。四求值順序總結語言中只有四個運算符,明確規定了求值順序和先對左邊求值,只在需要時對右邊求值如此避免除錯誤。在結果為真是返回,結果為假是返回。原因一只要的值都限制在和的結果始終相同。 目錄 一、前言 二、字符指針 三、邊界計算與不對稱邊界 1.經典錯誤...

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

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

    wpw 評論0 收藏0
  • JS干貨| 瀏覽器缺陷、瀏覽器的缺陷修復等五大開發問題解決之道

    摘要:圖對可復用代碼挑戰最大的五項問題五大開發問題如下。瀏覽器的缺陷修復。瀏覽器缺失的功能。復雜的地方是,當前瀏覽器會在未來的瀏覽器版本中被修復。假設瀏覽器引起常見的網站問題為解決瀏覽器使用特殊技巧,將來瀏覽器發布新版本修復了,就會出現問題。 任意一段重要的代碼都需要關注無數的開發問題。但是,其中對可復用JavaScript代碼挑戰最大的五項問題如圖14.2所示。 showImg(https...

    qiangdada 評論0 收藏0
  • 只看不敲,神也學不好C---------計算機經典書籍經驗分享

    摘要:學單片機多去官網上查資料,下載手冊,像我入門的單片機經常去官網,還有學的系列板子,公司的官網的官方例程給的很詳細,在英文視角閱讀對你大有益處。 目錄 1.C語言經典 2.單片機系列 3.Python方面 4.嵌入式LWip協議 5.Android 6.C++經典書籍 7.Linux開發 ...

    FleyX 評論0 收藏0
  • 如何避免多云網絡管理的陷阱

    摘要:然而,遷移到多云網絡并進行管理可能是一個持續的復雜過程。因此,在不評估這將對結合云計算服務的客戶產生影響的情況下,服務可能會發生變化。但是,為了充分利用云計算的好處,組織應該注意避免遷移和管理中的潛在缺陷。由于靈活性和彈性的提高,越來越多的組織采用多云網絡。然而,遷移到多云網絡并進行管理可能是一個持續的復雜過程。多云平臺的管理由于供應商數量的增加而更加復雜,但這也創造了機會。例如,多云網絡架...

    stonezhu 評論0 收藏0

發表評論

0條評論

tyheist

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<