進階C語言第十章、陣列和指針

2020-08-12 16:23:24
  1. 陣列
    :由數據型別相同的一系列元素組成。使用陣列時,通過宣告陣列告知編譯器陣列中有多少元素和這些元素的型別。編譯器根據這些資訊正確地建立陣列。
    1、使用逗號分隔的值列表來初始化陣列。
    2、有時需要把陣列設定爲只讀,const int day [MON]= {1,1,23,32,};
    3、編譯器使用的值是記憶體相應位置上的現在有值,使用陣列前必須先賦初值。
    4、如果不初始化陣列,陣列元素和未初始化的普通變數一樣,其儲存的都是垃圾值。部分初始化,剩餘元素就會被初始化爲0。可以省略方括號中的數位,讓編譯器自動匹配陣列大小和初始化列表中的項。
    5、可以在初始化列表中使用帶方括號的下標指明待初始化的元素
    int day[MONTHS] = { 31, 32, [4] = 31, 33, 32, [1] = 29 };
    1)如果指定初始化裏面有更多值[4] = 31,33,32,那麼後面這些值將被用於初始化指定的元素後面的元素。2)如果再次初始化指定元素,那麼最後初始化將會取代之前的初始化。
    6、給陣列元素賦值
    C不允許把陣列作爲一個單元賦給另一個數組,初始化以外也不允許花括號列表的形式賦值。
#include <stdio.h>
#define SIZE 50
int main(void)
{
	int counter, evens[SIZE];
	for (counter = 0; counter < SIZE; counter++)
		even[counter] = 2 * counter;
}

使用陣列時防之下標超出邊界,使用越界下標可能會導致程式改變其它 變數的值
7、指定陣列的大小
宣告陣列時只能在方括號中使用整型常數表達式。下標必須大於0,陣列大小必須大於0,陣列大小必須是整數。

  1. 多維陣列
    1、宣告:float rain[5][12];
    主陣列有五個元素,每個元素內含12個數組。
    常用於處理二維陣列的巢狀回圈結構。
#include <stdio.h>
#define MONTHS 12 //一年的月份
#define YEARS 5 //年數
const float rain[YEARS][MONTHS]={{},{},{},  };
int year,month;
float subtot, total;
for (year = 0, total = 0; year < YEARS; year++)  
{  //處理每一年的數據
	for (month = 0, subtot = 0; month < MONTHS; month++)
	//處理每月的數據
	subtot += rain[year][month];//處理每一年的的數據
	printf("%5d %1.51f\n", 2010 + year, subtot);
	total += subtot;
}

巢狀for回圈的內層回圈,在年不變的情況下,計算這年的總降水量;而外層回圈改變year的值,重複遍歷month,計算5年總降水量。
2、初始化二維陣列

const float rain[YEARS][MONTHS]=
{											{},
											{},
											{} 
 };

可以省略內部花括號,只保留最外面一對花括號。但是如果初始化值不夠,則按先後順序逐行初始化,直至用完全,後面沒有初始化的元素被同一初始化爲0.
3、其它多維陣列
一維陣列想象成一行數據,二維陣列想象成數值表,三維陣列是一疊數據表。或者看作陣列的陣列。多次巢狀。

  1. 指針和陣列
    :指針提供一種以符號形式使用地址的方法。指針能有效的處理陣列。
    陣列是變相的使用指針。
    陣列名是陣列首元素的地址。
    flizny == &flizny[0],是常數。在程式執行過程中不會改變。但是可以把它們賦值給指針變數,然後可以修改指針變數的值。
short dates[SIZES];
short * pti;
pti = dates;

地址按位元組編址,short佔兩個位元組。
指針加1指的是增加一個儲存單元。
對陣列來說,加1後的地址是下一個元素的地址。
這也是爲什麼要宣告指針所指向物件型別的原因之一。

指針的值是它所指向物件的地址。在指針前使用*運算子可以得到該指針所指向物件的值。指針加1,指針的值遞增它所指向型別的大小。

`dates + 2 ==&date[2];//地址相同  
 *(dates + 2)== dates[2]//值相同`

到記憶體的ar位置,然後移動n個單元,檢索儲存在那裏的值。
間接運算子(*)優先順序高於+

  1. 函數、陣列、指針
    處理名爲marbles的int型陣列的函數,該函數返回陣列中所有元素之和。
    total = sum(marbles);//可能的函數呼叫
    實際參數marbles是一個儲存的int型值的地址,應該把它賦給一個指針形式參數,即該形參是一個指向int型別值的指針。
    int sum(int * ar);//對應的函數原形
    該形參並未包含陣列元素個數資訊。因爲函數操縱的是指向陣列元素的指針,而不是陣列本身,因此函數忽略陣列長度。如果定義中包含陣列長度,則特別容易引起誤讀。
    兩種方法讓函數獲得陣列個數。
    1)在函數程式碼中寫上固定的陣列大小
int sum (int * ar)
{
	int i;
	int total = 0;
	
	for (i = 0; i < 10; i++) //假設陣列有十個元素
		total +=  ar[i];  //ar[i]與*(ar + i)相同
	return total;
}

2)把陣列元素的個數作爲第二個參數

int sum(int * ar, int n)
{
	int i;
	int total = 0;
	
	for (i = 0; i < n; i++) //假設陣列有n個元素
		total +=  ar[i];  //ar[i]與*(ar + i)相同
	return total;
}

只有在函數原形或定義頭中,纔可以用 int ar[ ] 替代 int *ar.int ar[ ] 和 int *ar,都表示ar是一個指向 int 的指針。 int *ar只能用於宣告形式參數。int ar[ ]提醒讀者指針ar指向的不僅是一個int型別值,還是一個int型別陣列的元素。
函數原型可以省略參數名,函數定義中不能省略參數名
1、使用指針形參
函數處理陣列必須要知道何時開始、何時結束。
1)用一個指針形參標識陣列的開始,用一個整數形參表明待處理陣列的元素個數。
2)傳遞兩個指針,一個開始一個結束。

int sump(int * start, int * end)
{
	int total = 0;
	while (start < end)
	{
		total += *start;
		start++;//指針變數纔可以用++,是變數才行。陣列表示的是常數。
	}
	return total;
}

end 所指向的實際位置上在陣列最後一個元素的後面。陣列後面第一個位置的指針仍是有效的指針。
難點:total += *start++
*start++; ++start
一元運算子
和++運算子相同,++在前,從右到左,先遞增指針,再使用。
++在後,先使用,後遞增。
原因:start++作爲一個整體與 * 運算,++後綴的++的運算規則其實是先運算,再加1。

  1. 指針操作
    該指針指向的地址,儲存在指針指向地址上的值,指針自己的地址。
    指針剛宣告完畢時,它並無指向的地址,只有當與某儲存的變數發生關係時,纔有指向地址。
    比較:前提是兩個指針都指向相同類型的物件。
    1)使用一個指針去減另一個指針,得到一個整數,
    2)用一個指針減一個整數得到一個指針

  2. 保護陣列中的數據
    只有程式需要在函數中改變該數值時,纔會傳遞指針。對於數組別無選擇,必須傳遞指針,因爲這樣效率高。如果一個函數按值傳遞陣列,則必須分配足夠的空間來儲存原陣列的副本,然後把原陣列所有的數據拷貝至新的陣列中。把陣列的地址傳遞給函數,然函數直接處理原陣列效率更高。
    1、對形式參數使用const

int sum(const int ar[ ], int n);//int ar[ ]和int *ar都表示指向int的指針

const並不要求原陣列是常數,而是該函數在處理陣列時將其視爲常數,不可更改。需要修改陣列,在宣告中不使用const。
2、可以建立const陣列、指針、和指向const的指針。
const int day [SIZES] = { 2, 3, 4, 5 };
const double * pd = rates;
doublel * const pc = rates;

7.指針和多維陣列

int zippo[4][2];

zippo 是該陣列元素的地址。所以zippo的值和&zippo[0]的值相同。zippo[0]又是一個內含兩個整數的陣列。所以zippo[0]的值和它首元素(一個整數)的地址相同 &zippo[0][0]。
給指針加一,會增加對應型別大小的數值。zippo佔用兩個int大小,zippo[0]佔用一個int大小。
解除參照一個指針。*(zippo[0]) == zippo[0][0]
*zippo == zippo[0] == &zippo[0][0]
**zippo == *&zippo[0][0]
1、指向多維陣列的指針

  1. 變長陣列
    變是指在建立陣列時,可以使用變數指定陣列的維度。
    首先要宣告兩個形參。
int sum2d(int rows, int cols, int ar[rows][cols]);

可以省略原形中的形參

int sum2d(int, int, int ar[*][*]);