c++ char数组初始化_c专题指针数组与指针的关联
----在今天開始寫文章之前,讓我不由的想起高中里面學的一篇文章中一段話語,是荀子寫的《勸學》:積土成山,風雨興焉;積水成淵,蛟龍生焉;積善成德,而神明自得,圣心備焉。故不積跬步,無以至千里;不積小流,無以成江海。騏驥一躍,不能十步;駑馬十駕,功在不舍。鍥而舍之,朽木不折;鍥而不舍,金石可鏤。蚓無爪牙之利,筋骨之強,上食埃土,下飲黃泉,用心一也。蟹六跪而二螯,非蛇鱔之穴無可寄托者,用心躁也。
? ? ? ? 有一個禮拜沒寫文章了,所以不由的想起這段話來,好好學習,不要浮躁。好了進入今天的主題:
一、深入理解數組:
1、什么是數組?
? ? ? ?這個簡單來理解的話,類似我們高中學的集合,只不過我們數組里裝的是同類型的數據元素,而且數據元素之間的物理內存是連續的,而且一般也是有內存限制的,可以有重復的數據元素,是因為內存單元之間是獨立的。
2、兩方面來深入理解數組:
? ? ? a):從內存角度來理解數組:
? ? ? ? ? ? ? ?從內存角度講,數組變量就是一次分配多個變量,而且這多個變量在內存中的存儲單元是依次相連接的;我們分開定義多個變量(譬如int a, b, c, d;)和一次定義一個數組(int a[4]);這兩種定義方法相同點是都定義了4個int型變量,而且這4個變量都是獨立的單個使用的;不同點是單獨定義時a、b、c、d在內存中的地址不一定相連,但是定義成數組后,數組中的4個元素地址肯定是依次相連的。數組中多個變量雖然必須單獨訪問,但是因為他們的地址彼此相連,因此很適合用指針來操作,因此數組和指針天生就叫糾結在一起。這里以int ? a[4]為例,它里面有四個元素,也就有四個內存單元:
? ? ? b):從編譯器角度來理解數組:
? ? ? ? ? ? ? 從編譯器角度來講,數組變量也是變量,和普通變量和指針變量并沒有本質不同。變量的本質就是一個地址,這個地址在編譯器中決定具體數值,具體數值和變量名綁定,變量類型決定這個地址的延續長度。注意地址是一個點:
3、數組中幾個關鍵符號(a a[0] &a &a[0])的理解(前提是 int a[10]):
? ? ? ? ? ?a):a就是數組名。a做左值時表示整個數組的所有空間(10×4=40字節),又因為C語言規定數組操作時要獨立單個操作,不能整體操作數組,所以a不能做左值;a做右值表示數組首元素(數組的第1個元素,也就是a[0])的首地址(首地址就是起始地址,就是4個字節中最開始第一個字節的地址)。a做右值等同于&a[0]。
? ? ? ? ? ?b):a[0]表示數組的首元素,也就是數組的第1個元素。做左值時表示數組第1個元素對應的內存空間(連續4字節);做右值時表示數組第0個元素的值(也就是數組第0個元素對應的內存空間中存儲的那個數)。
? ? ? ? ? ?c):&a就是數組名a取地址,字面意思來看就應該是數組的地址。&a不能做左值(&a實質是一個常量,不是變量因此不能賦值,所以自然不能做左值。);&a做右值時表示整個數組的首地址。
? ? ? ? ? ?d):&a[0]字面意思就是數組第1個元素的首地址(搞清楚[]和&的優先級,[]的優先級要高于&,所以a先和[]結合再取地址)。做左值時表示數組首元素對應的內存空間,做右值時表示數組首元素的值(也就是數組首元素對應的內存空間中存儲的那個數值)。做右值時&a[0]等同于a。
 1#include?
 2
 3
 4int?main(void) 5{
 6int?a,?b,?c,?d;?????//?分開獨立定義4個int型變量
 7int?a[4];???????????//?一次定義一個數組,包含4個int型變量
 8
 9//?注意數組和指針在初始化時的式子,和平時賦值有不同。
10int?a[10]?=?{1,?3,?4,?0};???????//?定義同時初始化
11int?*p?=?&a;????????????????????//?定義同時初始化
12
13
14a[0]?=?4;
15a[1]?=?44;
16a?=?{1,?4,?5,?32};??//?錯誤的,數組元素必須單個訪問,不能整個數組來訪問
17
18
19}? ? ? ? ------注意:為什么數組的地址是常量?因為數組是編譯器在內存中自動分配的。當我們每次執行程序時,運行時都會幫我們分配一塊內存給這個數組,只要完成了分配,這個數組的地址就定好了,本次程序運行直到終止都無法再改了。那么我們在程序中只能通過&a來獲取這個分配的地址,卻不能去用賦值運算符修改它。
4、小結:
? ? ?(1):&a和a做右值時的區別:&a是整個數組的首地址,而a是數組首元素 的首地址。這兩個在數字上是相等的,但是意義不相同。意義不相同會導致 他們在參與運算的時候有不同的表現。
? ? ? (2):a和&a[0]做右值時意義和數值完全相同,完全可以互相替代。
? ? ? (3):&a是常量,不能做左值。
? ? ? (4):a做左值代表整個數組所有空間,所以a不能做左值。
二、指針與數組的天生姻緣:
?? ? ?? 1、以指針方式來訪問數組元素:
? ? ? ? ? ? ?(1)數組元素使用時不能整體訪問,只能單個訪問。訪問方式有2種:數組形式和指針形式。
? ? ? ? ? ? (2)數組格式訪問數組元素是:數組名[下標]; (注意下標從0開始)。
? ? ? ? ? ? ? (3)指針格式訪問數組元素是:*(指針+偏移量); 如果指針是數組首元素地址(a或者&a[0]),那么偏移量就是下標;指針也可以不是首元素地址而是其他哪個元素的地址,這時候偏移量就要考慮疊加了。
? ? ? ? ? ??? (4)數組下標方式和指針方式均可以訪問數組元素,兩者的實質其實是一樣的。在編譯器內部都是用指針方式來訪問數組元素的,數組下標方式只是編譯器提供給編程者一種殼(語法糖)而已。所以用指針方式來訪問數組才是本質的做法。
? ? ? ? ?2、從內存角度理解指針訪問數組的實質:
? ? ? ? ? ? ? ? ?(1)數組的特點就是:數組中各個元素的地址是依次相連的,而且數組還有一個很大的特點(其實也是數組的一個限制)就是數組中各個元素的類型比較相同。類型相同就決定了每個數組元素占幾個字節是相同的(譬如int數組每個元素都占4字節,沒有例外)。
? ? ? ? ? ? ? ? ?(2)數組中的元素其實就是地址相連接、占地大小相同的一串內存空間。這兩個特點就決定了只要知道數組中一個元素的地址,就可以很容易推算出其他元素的地址。
? ? ? ? ? 3、指針和數組類型的匹配問題:
? ? ? ? ? ? ? ? ? ? (1)int *p; int a[5];p = a;// 類型匹配
? ? ? ? ? ? ? ? ???(2)int *p; int a[5];p = &a;// 類型不匹配。p是int *,? ?&a是整個數組的指針,也就是一個數組指針類型,不是int指針類型,所以不匹配
? ? ? ? ? ? ? ? ? ?(3)&a、a、&a[0]從數值上來看是完全相等的,但是意義來看就不同了。從意義上來看,a和&a[0]是數組首元素首地址,而&a是整個數組的首地址;從類型來看,a和&a[0]是元素的指針,也就是int *類型;而&a是數組指針,是int (*)[5];類型。
 1#include?
 2
 3
 4int?main(void) 5{
 6int?a[5]?=?{1,?2,?3,?4,?5};
 7int?*p;
 8p?=?a;
 9
10printf("*(p+1)?=?%d.\n",?*(p+1));
11printf("*(p+1)?=?%d.\n",?*((char?*)p+1));
12printf("*(p+1)?=?%d.\n",?*(int?*)((unsigned?int)p+1));
13
14char?*p2;
15p2?=?(char?*)p;
16printf("*(p+1)?=?%d.\n",?*(p2+1));
17
18
19int?a[5]?=?{1,?2,?3,?4,?5};
20int?*p;
21p?=?&a;
22
23printf("a?=?%x.\n",?a);
24printf("&a?=?%x.\n",?&a);
25printf("&a[0]?=?%x.\n",?&a[0]);
26printf("a[0]?=?%x.\n",?a[0]);
27
28
29int?a[5]?=?{1,?2,?3,?4,?5};
30
31printf("a[3]?=?%d.\n",?a[3]);
32printf("*(a+3)?=?%d.\n",?*(a+3));
33//??等效于:int b =?*(a+3); printf("*(a+3)?=?%d.\n", b);
34
35int?*p;
36p?=?a;??????//?a做右值表示數組首元素首地址,等同于&a[0]
37printf("*(p+3)?=?%d.\n",?*(p+3));???????//?等同于a[3]
38printf("*(p-1)?=?%d.\n",?*(p-1));???????//?等同于a[-1]
39
40p?=?&a[2];
41printf("*(p+1)?=?%d.\n",?*(p+1));???????//?等同于a[3]
42printf("*(p-1)?=?%d.\n",?*(p-1));???????//?等同于a[1]
43printf("*(p+3)?=?%d.\n",?*(p+3));???????//?等同于a[5]
44
45return?0;
46}
? ? ??? ?4、小結:
? ? ? ? ? ? ? ?(1)指針參與運算時,因為指針變量本身存儲的數值是表示地址的,所以運算也是地址的運算。
? ? ? ? ? ? ? ?(2)指針參與運算的特點是,指針變量+1,并不是真的加1,而是加1*sizeof(指針類型);如果是int *指針,則+1就實際表示地址+4,如果是char *指針,則+1就表示地址+1;如果是double *指針,則+1就表示地址+8.
? ? ? ? ? ? ? ?(3)指針變量+1時實際不是加1而是加1×sizeof(指針類型),主要原因是希望指針+1后剛好指向下一個元素(而不希望錯位)。
三、指針、數組與sizeof運算符
1、sizeof的錯誤糾正:
? ? ??sizeof是C語言的一個運算符(主要sizeof不是函數,雖然用法很像函數),sizeof的作用是用來返回()里面的變量或者數據類型占用的內存字節數。
2、代碼示例講解:
 1??#include?
 2??#include?
 3
 4
 5???#define?dpChar?char?*
 6???typedef?char?*?tpChar;????????//?typedef用來重命名類型,或者說用來制造用戶自定義類型
 7
 8
 9??//?func完全等同于func1
10?????void?func(int?a[])
11?????{
12???????printf("數組大小?=?%d.\n",?sizeof(a));
13?????}
14
15?????void?func1(int?*a)
16?????{
17?????????printf("數組大小?=?%d.\n",?sizeof(a));
18????}
19
20?????void?func2(int?*a,?int?num)
21???{
22???//?在子函數內,a是傳進來的數組的指針(首地址)
23???//?在子函數內,num是數組的大小
24???}
25
26
27
28??int?main(void)
29?{
30??????int?a[56];
31??????int?b?=?sizeof(a)?/?sizeof(a[0]);?//?整個數組字節數/數組中一個元素的字節數
32??????????printf("b?=?%d.\n",?b);????????????????//?結果應該是數組的元素個數
33
34
35/*????
36???dpChar?p1,??p2;??????????//?展開:char *p1, p2;?相當于char *p1, char p2;
37tpChar?p3,??p4;?????????//?等價于:char *p3, char *p4;??
38printf("sizeof(p1)?=?%d.\n",?sizeof(p1));???????//?4
39printf("sizeof(p2)?=?%d.\n",?sizeof(p2));???????//?1
40printf("sizeof(p3)?=?%d.\n",?sizeof(p3));???????//?4
41printf("sizeof(p4)?=?%d.\n",?sizeof(p4));???????//?4
42?*/4344?/*
45int?a[20];
46func(a);????????????//?4?因為a在函數func內部就是指針,而不是數組
47
48func1(a);
49
50func2(a,?sizeof(a));
51??*/5253/*????
54int?b1[100]?=?{0};
55printf("sizeof(b1)?=?%d.\n",?sizeof(b1));????????
56?//?400?100×sizeof(int)
57
58short?b2[100]?=?{};
59printf("sizeof(b2)?=?%d.\n",?sizeof(b2));???????//?200?100×sizeof(short)
60
61double?b3[100];
62printf("sizeof(b3)?=?%d.\n",?sizeof(b3));???????//?800?100×sizeof(double)
63*/????6465/*
66int?n?=?10;
67printf("sizeof(n)?=?%d.\n",?sizeof(n));?????????//?4
68printf("sizeof(int)?=?%d.\n",?sizeof(int));?????//?4
69??*/7071??/*
72char?str[]?=?"hello";??
73char?*p?=?str;?
74printf("sizeof(p)?=?%d.\n",?sizeof(p));?????????//?4?相當于sizeof(char?*)
75printf("sizeof(*p)?=?%d.\n",?sizeof(*p));???????//?1?相當于sizeof(char)
76printf("strlen(p)?=?%d.\n",?strlen(p));?????????//?5?相當于strlen(str)
77?*/7879??/*
80char?str[]?=?"hello";??
81printf("sizeof(str)?=?%d.\n",?sizeof(str));?????????????//?6
82printf("sizeof(str[0])?=?%d.\n",?sizeof(str[0]));???????//?1
83printf("strlen(str)?=?%d.\n",?strlen(str));?????????????//?5
84??*/????8586??????????return?0;87??}88
說明:
? ? ? ? (1):函數傳參,形參是可以用數組的
? ? ? ? (2):函數形參是數組時,實際傳遞是不是整個數組,而是數組的首元素首地址。也就是說函數傳參用數組來傳,實際相當于傳遞的是指針(指針指向數組的首元素首地址)。
? ? ? (3):strlen是一個C庫函數,用來返回一個字符串的長度(注意,字符串的長度是不計算字符串末尾的'\0'的)。一定要注意strlen接收的參數必須是一個字符串(字符串的特征是以'\0'結尾) 。
四、總結:
? ? ? ? ?今天的分享就結束了,講解的不是很深,但是基礎非常重要,后面會慢慢的增加難度了。所有最好理解的方法就是自己簡單寫代碼測試一下,你就會理解的,這是最近自己找到一個比較好的學習方法,你看別人的示例,還不一定能完全吃透,自己親身搞一下,那收獲是不一樣的。
---歡迎關注公眾號,可以查看往期的文章,可以得到三本經典的c語言進階電子書:
對技術熱愛的一個Linux愛好者(對文章中寫有不對的地方,可以批評指出,虛心向您學習,大家一起進步。群里只能討論技術方面的,發廣告,立刻飛機):
總結
以上是生活随笔為你收集整理的c++ char数组初始化_c专题指针数组与指针的关联的全部內容,希望文章能夠幫你解決所遇到的問題。
                            
                        - 上一篇: bartender一行打印两个二次开发_
 - 下一篇: 求一个古诗个性签名。