最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會員登陸 & 注冊

C語言數(shù)組和指針

2023-01-28 15:54 作者:虛云幻仙  | 我要投稿

#define _CRT_SECURE_NO_WARNINGS

#include <stdio.h>

#define LEN 3


void pointer_array(void);

void copy_array(void);

void copy_array1(double src[], int len, double dest[]); // 以一維數(shù)組為形參時不需要指定數(shù)組長度,即使寫了也無效,長度需要單獨傳參,形參列表為(原數(shù)組,數(shù)組長度,目標數(shù)組)

void copy_array2(double* src, int len, double* dest); // 數(shù)組實際上是通過指針實現(xiàn)的,所以形參聲明數(shù)組和聲明指針等價,所有數(shù)組形式的操作都會被編譯器轉(zhuǎn)換為指針形式的操作

void copy_array3(double* src_start, double* src_end_next, double dest[]); // 指定數(shù)組的開始地址和最后一個元素往后下一個地址,將這一段連續(xù)的地址的值賦值給目標數(shù)組(目標地址及往后的一段相同的長度)

//應(yīng)模仿賦值表達式的形式利于記憶,dest=src將src賦值給dest,拷貝函數(shù)寫為func(dest,size,src)將src的size個元素賦值給dest

void show_array(double ar[], int len);

void show_max1(void);

void show_max2(int ar[], int len);

int show_max_index1(void);

int show_max_index2(double ar[], int len);

void array2d(void);

void array2d_alter(double ar[][4], int len);

void array2d_show(double ar[][4], int len);

void sub_array(void);

void array_vla(void);


void pointer_array(void) {

???? double ar1[LEN] = { 1.0,2.0,3.0 }; // 聲明數(shù)組會在內(nèi)存中創(chuàng)建一塊連續(xù)的區(qū)域,ar1在內(nèi)存中創(chuàng)建了一塊連續(xù)的3*8字節(jié)的區(qū)域,該區(qū)域的第一個double地址上(第一個8字節(jié))的值為1.0,之后依次為2.0,3.0,ar1除了3*8的區(qū)域外沒有再創(chuàng)建區(qū)域來引用這個區(qū)域,C沒有引用變量,也就是說ar1就是數(shù)組本身,數(shù)組本身就是這個3*8的區(qū)域,而每個元素就是這個區(qū)域內(nèi)的每個8字節(jié)

???? printf("&ar1[0] = %p\n", &ar1[0]); //ar1[0]為數(shù)組的首元素,&ar1[0]為首元素的地址

???? printf("ar1 = %p\n", ar1); //數(shù)組名ar1實際是ar1[0]的地址,常量

???? if (ar1 == &ar1[0]) // ar1地址常量和&ar1[0]地址常量 地址相等,

???? {

???????? printf("sizeof ar1 = %zd\n", sizeof(ar1)); //ar1的大小為24,即數(shù)組的大小

????????printf("sizeof ar1[0] = %zd\n", sizeof(ar1[0])); //ar1[0]的大小為8,即首元素(double類型變量)的大小

????????printf("sizeof &ar1[0] = %zd\n", sizeof(&ar1[0])); //&ar1[0]的大小為8,是ari[0]double類型變量的地址常量的大小,本系統(tǒng)中存儲地址的類型(指針類型)大小為8

???????? printf("ar1[0] = %.1f\n", ar1[0]); // ar1[0] = 1.0

???????? printf("*ar1 = %.1f\n", *ar1); // *ar1 = 1.0 ,使用*解引用數(shù)組名的結(jié)果等價于*&ar1[0],雖然ar1大小為24,但解引用時依然會返回第一個元素的值

???? }

}

void copy_array(void) {

???? double ar1[LEN] = { 1.0,2.0,3.0 }; // 使用define常量聲明數(shù)組,經(jīng)過編譯之后所有LEN會被替換為數(shù)字3,所以在運行時不存在常量LEN,數(shù)組聲明為ar1[3]

???? double ar2[3],ar3[3],ar4[4]; // 使用常量聲明數(shù)組

???? copy_array1(ar1, LEN, ar2); //使用LEN和使用數(shù)字3等價

???? copy_array2(ar1, sizeof(ar1)/sizeof(ar1[0]), ar3); //sizeof(ar1)是數(shù)組的大小,單位字節(jié),數(shù)組占3個double即3*8字節(jié),sizeof(ar1[0])是數(shù)組第一個元素的大小,元素為double類型,所以占8字節(jié),所以3*8/8為3個元素的長度

???? copy_array3(ar1, &ar1[3], ar4); // 數(shù)組名ar1實際上是一個地址常量,該地址實際是該數(shù)據(jù)對象/數(shù)組在內(nèi)存中對應(yīng)的塊的首位的地址(24字節(jié)*8=192位的首位的地址),ar1 == &ar1[0] 為true,&ar1[0]是該double變量/數(shù)據(jù)對象在內(nèi)存中對應(yīng)的塊的首位的地址(8字節(jié)*8=64位的首位的地址),而ar1[0]是數(shù)組ar1首元素,所以ar1[0]元素在內(nèi)存中位于ar1數(shù)組的最前面,ar1[0]的8字節(jié)的首位的地址和ar1的24字節(jié)的首位的地址是同一個地址,也就是說這里使用ar1[0]的地址既可以用&ar1[0]表示也可以用ar1表示,因為傳參的實參為那一位的地址,無論主調(diào)函數(shù)是怎么使用這一位的,被調(diào)函數(shù)只接受了這一位的地址,沒有接收主調(diào)函數(shù)賦予的含義,但ar1不是&ar1[0],sizeof(ar1)為24,而sizeof(&ar1[0])為8,這是因為類型/單位不同,ar1是一個包含3個double元素的數(shù)組,單位是3個double大小即3*8,而ar1[0]是一個double類型的元素,單位是1個double即8字節(jié),函數(shù)定義中使用和元素同類型的指針來接收這個地址,所以接收到的指針是同類型(double)即單位為8字節(jié)的指針,并不包含數(shù)組長度(因為數(shù)組沒有完整傳進來),所以需要一個參數(shù)來控制指針移動的范圍,len表示指針向后移動(增加)的次數(shù),在該次數(shù)之內(nèi)的范圍是數(shù)組的范圍,end_next表示指針向后移動到該地址之前都是數(shù)組的范圍,&ar1[3]實際也只是將數(shù)組范圍外的第一位的地址傳參給被調(diào)函數(shù),被調(diào)函數(shù)中使用double*來接收這一位置,(可以理解為)將其解釋成數(shù)組范圍外首元素的地址

???? show_array(ar1, LEN);

???? show_array(ar2, LEN);

???? show_array(ar3, LEN);

???? show_array(ar4, LEN);

????

}

void copy_array1(double src[], int len, double dest[]) {

???? int i;

???? for ( i = 0; i < len; i++)

???? {

???? ???? dest[i] = src[i];

???? }

???? // 數(shù)組的修改是直接在原地址上進行的,所以不需要額外返回數(shù)組

}

void copy_array2(double* src, int len, double* dest) {

???? int i;

???? for ( i = 0; i < len; i++)

???? {

???? ???? *dest++ = *src++; // 判定順序為++(后綴遞增)優(yōu)先級高于*,后綴遞增先使用再自增,指向double的指針每次遞增或+1即向后移動一個double長度即8字節(jié)即移動64位,假設(shè)dest的值(指向的地址)為F4A0,那么dest++后的值為F4A8,這里dest的地址不會變化即&dest是常量(指針變量的常量地址),而dest的值變了即*&dest改變了,而*dest是dest值指向的地址的值,使用指針賦值的思路:數(shù)組是連續(xù)的內(nèi)存空間,用指針src指向了該連續(xù)空間/地址的首個元素的地址,將該地址的值賦給dest指向的地址(同為數(shù)組的首元素地址),每次賦值之后兩個指針都向后移動一個單元,相當于數(shù)組索引增加一位,總共有l(wèi)en個單位,所以總共進行l(wèi)en次賦值后遞增

???? }

}

void copy_array3(double* src_start, double* src_end_next, double dest[]) {

???? int i;

???? for (i = 0; src_start + i < src_end_next; i++) {

???? ???? dest[i] = *(src_start + i); // *src_start代表指向地址的值,src_start+1代表指向地址的下一個單位的地址,*(src_start+1)即下一個地址的值,等價于src_start[1],*src_start等價于*(src_start+0),而dest[i]也可以寫為:*(dest+i)

???? }

???? // 在形參定義上,指針和一維數(shù)組是等價的,double* dest和double dest[]是完全相同的

}

void show_array(const double ar[], int len) { // 如果函數(shù)不需要對傳入的數(shù)組進行修改,可以將形參聲明為const只讀,這使得通過指針ar調(diào)用地址的值的時候無法修改該值,但這不會影響原數(shù)組,無論原數(shù)組是否const

???? int i;

???? printf("[");

???? for (i = 0; i < len-1; i++)

???? {

???? ???? printf(" %.1f,", ar[i]);

???? }

???? printf(" %.1f]\n", ar[len - 1]);

???? //ar[0] = 1.0;? 無效,因為const double ar[]指針不能修改指向的地址的值

???? double* const ar2 = ar; // 將const寫在指針名前面,使指針的值不能修改,即指針指向的地址

???? //ar2++;? 無效,ar2不能修改指向的地址

???? ar2[0] = 1.0; // 有效,ar2[0]等價*ar2,雖然不能修改指向的地址,但是可以修改指向地址的值

???? const double* const ar3 = ar; //兩個const,限制ar3既不能修改指向的地址,也不能修改指向地址的值

}

void show_max1(void) {

???? int ar[] = { 5,2,6,3,1 }; //使用{}初始化數(shù)組而不指定數(shù)組長度的情況下,編譯器會計算{}的長度賦值給數(shù)組,這使得程序運行之前就知道應(yīng)該為這個數(shù)組預(yù)留多少空間

???? show_max2(ar, sizeof(ar) / sizeof(*ar)); //*ar==ar[0]

}

void show_max2(int ar[], int len) {

???? int max;

???? for (max = 0; len > 0; len--)

???? {

???? ???? max = max > ar[len - 1] ? max : ar[len - 1]; // index應(yīng)為0~len-1,所以第一次循環(huán)len為原值索引為長度-1,最后一次循環(huán)len為1索引為1-1

???? }

???? printf("max = %d", max);

}

int show_max_index1(void) {

????printf("index = %d", show_max_index2((double[]) { 2.0, 5.0, 3.0, 6.0, 1.0 }, 5)); // 復(fù)合字面量,類似int常量20、char常量'a',用(type [size]){element1,element2....}的形式表示數(shù)組常量,不需要起變量名,如這里的 (double[]){2.0,5.0...} ,數(shù)組的長度不寫的話編譯器會計算{}的長度來補上

}

int show_max_index2(double ar[], int len) {

???? int max = 0;

???? for (int i = 1; i < len; i++)

???? {

???? ???? max = ar[max] > ar[i] ? max : i;

???? }

???? return max;

}

void array2d(void) {

???? double ar[3][4] = {

???? {1.0,2.0,3.0,4.0},

???? {2.0,3.0,4.0,5.0},

???? {3.0,4.0,5.0,6.0}

???? }; //二維數(shù)組,ar有三個數(shù)組元素,每個數(shù)組元素有四個double元素,將每個子數(shù)組單獨寫一行,ar數(shù)組看作是一個3行4列的矩陣,一行row為一個一維數(shù)組(二維數(shù)組的元素ar[i]),一列col為所有一維數(shù)組的同下標元素(ar[][j])

???? // 一維數(shù)組本身是連續(xù)內(nèi)存空間,連續(xù)的地址依次存放每個元素的值

???? // 二維數(shù)組同樣,本身是連續(xù)內(nèi)存空間,連續(xù)的地址依次存放每個數(shù)組元素本身,所以二維數(shù)組即更大的一塊連續(xù)的內(nèi)存空間,從第一個地址開始,連續(xù)存放第一個子數(shù)組的每一個元素,之后再存放第二個子數(shù)組,以此類推

???? // 二維數(shù)組不是引用類型,C沒有引用類型,二維數(shù)組中實實在在存放著一維數(shù)組本身,所以二維數(shù)組名ar地址常量的值和ar[0]首子數(shù)組地址常量的值和&ar[0][0]首子數(shù)組的首元素的地址相同,都是那一位的地址

???? // 但大小不同,ar的大小為整個二維數(shù)組的3*4*8,ar[0]子數(shù)組的大小為4*8,ar[0][0]元素的大小為8

???? // 使用{}初始化聲明二維數(shù)組同樣可省略長度3、4,編譯器會計算后補上

???? double dest[3][4]; // 沒有初始化數(shù)組的值,3、4不能省略,因為編譯器不知道數(shù)組多大

???? copy_array1(ar[0], 4, *dest); //拷貝一維數(shù)組,*dest和dest[0]等價,而**dest和dest[0][0]等價

???? copy_array2(ar[1], 4, *(dest + 1)); //*(dest+1)和dest[1]等價

???? copy_array3(ar[2], ar[2] + 4, *dest + 8); //ar[2]是&ar[2][0]的地址,ar[2]+4即&ar[2][4]的地址,這和ar+2==&ar[2]同理,而*dest是首子數(shù)組的首元素的地址&dest[0][0],單位是double8字節(jié),因為數(shù)組是內(nèi)存連續(xù)的,所以&dest[0][0]的下一個是&dest[0][1],&dest[0][3]的下一個是&dest[1][0],所以*dest的下8個是&dest[2][0]

???? for (int i = 0; i < 3; i++)

???? {

???? ????show_array(dest[i], 4);

???? }

???? array2d_alter(dest, 3);

???? array2d_show(dest, 3);

}

void array2d_alter(double ar[][4], int len) { //多維數(shù)組作為形參時,第一個[]內(nèi)的值會被編譯器忽略,之后的[]必須聲明值,因為多維數(shù)組的單位是子數(shù)組的大小,指針ar[][4]每++都會移動一個子數(shù)組即4個double長度,這個長度是必須在編譯階段聲明的

???? for (int i = 0; i < len; i++) //len是行row

???? {

???????? for (int j = 0; j < 4; j++) //4是列col

???????? {

???????? ???? ar[i][j] *= 2; //將每個double元素的值翻倍

???????? }

???? }

}

void array2d_show(double ar[][4], int len) {

???? // 形參中聲明的double ar[][4]是二維數(shù)組的指針,在語句塊內(nèi)聲明二維數(shù)組的指針需要寫作 double(*ar)[4];

???? double(*arr)[4] = ar; //將二維數(shù)組指針ar的值賦給arr,這時兩個指針指向相同的地址,單位也相同

???? double* arra[4]; //[4]的優(yōu)先級高于*,所以這會先創(chuàng)建一個包含4個元素的數(shù)組,然后運行*,數(shù)組的元素是指針,然后運行double,指針指向double,所以arra是包含四個double指針的數(shù)組,arra==&arra[0]是常量而非變量,不能作為左值,而ar和arr、arra[0]是指針變量,可以作為左值

???? arra[0] = ar[0]; //arra[0]是指向double的指針,而ar[0]是double一維數(shù)組,也是&ar[0][0]首元素double元素的地址,這兩個的單位都是double,可以賦值

???? *(arra + 1) = *(ar + 1); //arra是&arra[0]的地址常量,單位為指針的大小,因為是存放指針的數(shù)組,+1只會移動一個指針類型大小,在指針數(shù)組的區(qū)域內(nèi)向后移動了一個單位,ar是指針,是變量,ar的值是二維數(shù)組的[0][0]的地址,ar的單位是[4]四個double大小,+1是從二維數(shù)組區(qū)域內(nèi)的[0][0]地址向后移動了一個單位

???? for (int i = 0; i < len; i++)

???? {

???????? for (int j = 0; j < 4; j++)

???????? {

???????? ???? printf("%.1f ", ar[i][j]);

???????? }

???????? putchar('\n');

???? }

}

void sub_array(void) {

???? double ar[7] = { 1.0,2.0,3.0,4.0,5.0 }; //聲明的長度不能小于{}的長度,如果大了,那么數(shù)組后側(cè)空出來的元素會初始化為0,即{1,2,3,4,5,0,0}

???? double sub_ar[3]; //聲明一個3元素的數(shù)組

???? copy_array1(ar, 3, sub_ar); //將ar[0]的地址傳給函數(shù),指定拷貝長度3,所以sub_ar實際會得到{1.0,2.0,3.0}這前三個元素的值

???? show_array(sub_ar, 3);

???? copy_array2(ar + 2, 3, sub_ar); //將ar[2]的地址傳給函數(shù),指定拷貝長度3,所以sub_ar實際會得到{3.0,4.0,5.0}中間三個元素的值

???? show_array(sub_ar, 3);

}

void array_vla(void) {

???? int row = 3;

???? int col = 5;

???? //int ar[row][col] = { 1,2,3,4,5,6 };? //變長數(shù)組,使用變量聲明數(shù)組的長度,因為編譯器在編譯階段不知道變量在這一行時的確切值,所以數(shù)組的實際大小只有到運行程序時才能確定,MSVC不支持變長數(shù)組,在C11標準中規(guī)定變長數(shù)組VLA為可選項,不再必須實現(xiàn)

???? //這里假設(shè)程序支持變長數(shù)組,那么ar有三個數(shù)組元素,每個數(shù)組元素有5個int元素,而初始化{}只顯示了6個元素,則從前往后依次賦值,6個元素之后的所有位置都初始化為0,所以ar[0]是{1,2,3,4,5},ar[1]是{6,0,0,0,0}

}


C語言數(shù)組和指針的評論 (共 條)

分享到微博請遵守國家法律
定西市| 晴隆县| 台湾省| 古交市| 布尔津县| 延吉市| 昌黎县| 柳河县| 桃源县| 乌拉特中旗| 札达县| 仪征市| 墨玉县| 日喀则市| 云和县| 景宁| 吕梁市| 宜昌市| 金川县| 杂多县| 深泽县| 柳河县| 静安区| 平泉县| 霍州市| 乌苏市| 龙川县| 宁河县| 永仁县| 宿松县| 客服| 江油市| 巴林左旗| 临武县| 平顺县| 垣曲县| 广汉市| 永仁县| 丁青县| 丽水市| 理塘县|