程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> 關於C語言 >> C Primer Plus(十)

C Primer Plus(十)

編輯:關於C語言

10.1 數組

數組是由一系列類型相同的元素構成。
數組聲明中包括數組元素的數目和元素的類型。

10.1.1 初始化

有時需要使用只讀數組,也就是程序從數組中讀取數值,但是程序不向數組中寫數據。在這種情況下,初始化的時候可以使用關鍵字const。
與普通變量相似,在初始化之前數組元素的數值是不定的。
當數值數目少於數組元素數目時,多余的數組元素被初始化為0。如果不初始化數組,數組元素和未初始化的普通變量一樣,其中存儲的是無用的數值;
但是如果部分初始化數組,未初始化的元素則被設置為0。
如果初始化列表中的項目個數大於數組大小,編譯器會認為這是一個錯誤。
您可以省略括號中的數字,從而讓編譯器自動匹配數組大小和初始化列表中的項目數目。

由於人工計算容易出錯,可以讓計算機來計算數組的大小。運算sizeof給出其後的對象或類型的大小。sizeof days是整個數組的大小(以字節為單位),sizeof days[0]是一個元素的大小。

10.1.2 指定初始化項目(C99)

此特性允許選擇對某些元素進行初始化。例如:
int arr[6]={[5]=212};
程序如下:

#include<stdio.h>
#define MONTHS 12
int main(void)
{
int days[MONTHS]={31,28,[4]=31,30,31,[1]=29};
int index;
for(index=0;index<MONTHS;index++)
printf("month %2d has %d days.\n",index+1,days[index]);
return 0;
}

如果多次對一個元素進行初始化,則最後的一次有效。
聲明數組時在方括號內只能使用整數常量表達式。sizeof表達式被認為是一個整數常量,而一個const值卻不是整數常量。並且該表達式的值必須大於0。
C99引入變長數組主要是為了使C更適於做數值計算。

 

10.2 多維數組

二維數組的聲明方法:float rain[5][12];
rain是一個包含5個元素的數組,每個元素的類型是float[12];rain[0][0]是一個float數。
也可以把rain看作是一個二維數組,它包含有5行,每行12列。改變第二個下標,可以沿著一行移動,改變第一個下標,可以沿著一列垂直移動。
初始化二維數組可以例如float[5][12]={{.....},{.....},{.....},{.....},{.....}};
每個數值列表都用花括號括起來。第一個列表給賦值給數組的第一行。初始化時候也可以省略內部的花括號,只保留最外面的一對花括號。只要保證數值的個數正確,若不夠,則後面的元素被初始化為0。
同樣適用於三維數組。

10.3 指針和數組

數組標記實際上是一種變相使用指針的形式。數組名同時也是該數組首元素的地址。如果fizny是一個數組,則finzy==&finzy[0];兩者都是常量。
在C中對一個指針加1的結果是對該指針增加1個存儲單元(它指向的對象的字節大小)。對於數組而言,地址會增加到下一個元素的地址,而不是下一個字節。
finzy+2==&finzy[2];*(finzy+2)==finzy[2];
注意區分*(finzy+2)和*finzy+2:間接運算符*的優先級高於+,因此後者等價於:*(finzy)+2,前者為數組第三個元素的值。
在函數原型中,可以用int *ar代替 int ar[];
將數組名傳遞給函數的形參時,數組大小無法得知。可以有兩種方法結解決
1.在函數代碼中協商固定的數組大小。2.把數組大小作為第二個參數傳遞給函數。

向函數傳遞數組信息時,可以傳遞兩個指針,一個指明數組的起始地址,一個指明數組的結束地址。例如

end實際指向的位置實在數組最後一個元素之後。C保證在為數組分配存儲空間的時候,指向數組之後的第一個位置的指針也是合法的。
*start++:一元運算符*和++具有相等的優先級,但它在結合時是從右向左進行的。盡管*start++合法,但為了清晰起見應該使用*(start++)。

10.4 指針操作

下面例舉了可對指針變量執行的基本操作:
賦值求值----運算符*可取出指針指向地址中存儲的數值。
取指針地址----指針變量同其它變量一樣具有地址和數值,使用運算符&可以得到存儲指針本身的地址。
將一個整數加給指針----整數會和指針所指類型的字節數相乘,然後所得的結果會加到初始地址上。
增加指針的值----可以通過一般加法或增量運算符來增加一個指針的值。
從指針中減去一個數----指針必須是第一個操作數,或者是一個指向整數的指針。
減小指針的值----指針可以做減量運算。
求差值----通常對分別指向同一個數組內兩個元素的指針求差值,以求出元素之間的距離,差值的單位是相應類型的大小。
比較----前提是兩個指針具有相同的類型。
C保證指向數組元素的指針和指向數組後的第一個地址的指針是有效的。但如果指針超出了這個范圍,後果將是未知的。
不能對未初始化的指針取值。這樣的話可能會覆蓋程序數據或者代碼,甚至導致程序的崩潰。
當創建一個指針時,系統只飛陪了用來存儲指針本身的內存空間,並把分配用來存儲數據的內存空間。

10.5 保護數組內容

因為向函數傳遞的是數組,可能會破壞原始數據的完整性。
為此,可以在函數原型和定義的形式參量聲明中使用關鍵字const。

10.5.1 有關const的其它內容

指向常量的指針不能用於修改數值。
double rates[5]={88.99,100.12,59.45,183.11,340.5};
const double *pd=rates;
*pd=29.89;                //不允許
pd[2]=222.22;           //不允許
rates[0]=99.99;         //允許
pd++                       //允許
const double locked[4]={0.08,0.075,0.0725,0.07}; double *pnc; pnc=locked;      //非法的

也可以使用兩個const來創建指針,這個指針既不可以更改所指向地址,也不可以修改所指向數據。 const double *const pc=rates;

10.6 指針和多維數組

int zippo[4][2];
數組名zippo是數組首元素的地址,所以zippo的值和&zippo[0]相同。另一方面zippo[0]本身也是包含兩個整數的數組,因此zippo[0]的值和其首元素的地址&zippo[0][0]相同。zippo[0]是一個整數大小對象的值,而zippo是兩個整數大小對象的地址。因為整數和兩個整數組成的數組開始於同一個地址,因此zippo和zippo[0]具有相同的數值。
對一個指針加1,會對原來的數值加上一個對應類型大小的數值。因此zippo+1和zippo[0]+1的結果不同。
*(zippo[0])代表其首元素zippo[0][0]的值,*zippo代表其首元素zippo[0]的值,即&zippo[0][0]。**zippo等價於*&zippo[0][0]即zippo[0][0]。
zippo[2][1]的等價指針符號表示為*(*(zippo+2)+1);

10.6.1 指向多維數組的指針

int (* pz)[2]; //pz指向一個包含兩個int值的數組
int * pz[2];   //創建一個指針數組

int *pt; int ar[3][2];int **pd;
pd=&pt;                //合法,pd是指向指針的指針,&pt指向指針pt,pt是一個指向int元素的指針
*pd=ar[0];            //合法,*pd指向一個元素的指針,ar[0]是指向ar[0][0]的指針。
pd=ar;                 //非法

int * p1;
const int * p2;
const int ** pp2;
p1=p2;             //非法
p2=p1;            //合法
pp2=&p1         //非法
也可以用 int sum2(int ar[3][4],int rows);但是3將被忽略。
一般地,聲明N維數組的指針時,除了最左邊的方括號可以留空之外,其它都需要填寫數據。

10.7 變長數組(VLA)

C99標准引入了變長數組,它允許使用變量定義數組各維。例如
int quarters=1;
int regions=5;
double sales[regions][quarters];
變長數組的限制:VLA必須是自動存儲類的,這意味著它們必須在函數內部或作為函數參量聲明,而且聲明時不可以進行初始化。
變並不表示在創建數組後,您可以修改其大小。它的意思是說其維數大小可以用變量來指定。
int sum2d(int rows, int cols, int ar[rows][cols]);
C99標准規定,可以省略函數原型中的名稱;但是如果省略,則需要用星號來代替省略的維數。
int sum2d(int , int , int ar[*][*]);

10.8 符合文字

下面是一個復合文字,創建了一個包含兩個int值的無名稱數組:
(int [2]){10,20};
初始化一個復合文字時也可以省略數組大小
(int []){50,20,90};
由於這些復合文字沒有名稱,因此不可能在一個語句中創建它們,然後在另一個語句中使用。而是必須在創建它們的同時通過某種方法來使用它們,一種方法是使用指針保存其位置。
int *pt1;
pt1=(int [2]){10,20};

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved