一剪廉、數(shù)組的定義
1、定義
數(shù)組:指針的特殊化朴肺。
它也是內(nèi)存分配(空間申請)的一種形式窖剑,而不是一種全新的數(shù)據(jù)結(jié)構(gòu)。
其目的就是為了定義一個連續(xù)的空間戈稿。
2西土、2個屬性:
大小
-
讀取方式
數(shù)據(jù)類型 數(shù)組名[m]: []:把數(shù)組名升級為一個連續(xù)空間 m:連續(xù)空間的個數(shù)。 數(shù)據(jù)類型:表示內(nèi)存以何方式切割鞍盗。 int a[100]; // 100個int這么大的連續(xù)空間 a[10] // 使用方式與指針是一樣的
(1)m 就是一個建議符需了,只是在申請的時候用一下。后面使用的時候般甲,編譯器無法知道[]
里面的數(shù)是否越界肋乍。
int a[100]; // 理論上,a的空間只有100個敷存,但是只是建議墓造;還是可以越界的。
(2)經(jīng)典錯誤1:數(shù)組名是一個常量符號锚烦,只是一個標(biāo)簽常量觅闽,是無法改變的,一定不要放到=
的左邊
char buf[100];
buf = "hello world"; // 錯誤涮俄!
buf++; // 錯誤蛉拙!
數(shù)組名是一個常量,指針是一個變量禽拔。
二刘离、數(shù)組空間的初始化(數(shù)組空間的賦值問題)
原理:按照標(biāo)簽逐一賦值。(空間的賦值沒有投機(jī)取巧的辦法睹栖,只能這樣做)
int a[10];
a[0] = x;
a[1] = y;
...
問題:
但如果這樣賦值硫惕,程序員的工作量很大。
偷懶辦法:讓編譯器進(jìn)行一些自動處理野来,幫助程序員寫如上的逐一賦值的程序恼除。
方法:空間在定義時,就告知編譯器初始化情況,這叫空間的第一次賦值豁辉。
int a[10] = 空間;
C語言本身/CPU內(nèi)部本身令野,一般不支持空間和空間的拷貝,只支持int徽级、int(4B)等之間小的拷貝气破。
int a[10] = {10, 20, 30}; -- > 學(xué)習(xí)arm匯編后,可以進(jìn)行反匯編餐抢。
其內(nèi)部相當(dāng)于執(zhí)行一個拷貝的過程现使。只是不同編譯器調(diào)用不同的函數(shù)來做拷貝。
這句定義旷痕,其實CPU還是做了:
a[0] = 10;
a[1] = 20;
a[2] = 30;
a[3] = 0 / 隨機(jī)值; (不同編譯器可能有所不同)
...
所以碳锈,一定不要這樣認(rèn)為:數(shù)組初始化一步就可以完成了!
數(shù)組空間的初始化和變量的初始化欺抗,本質(zhì)上是不同的售碳。
尤其在嵌入式的裸機(jī)開發(fā)中,數(shù)組空間的初始化往往需要一些庫函數(shù)的輔助绞呈,或者程序員的人為設(shè)計贸人。
1、字符空間(軟件的最小空間:char)
char buf[10] = {'a','b','c'};
// 1. buf如果當(dāng)成普通內(nèi)存來看,這樣寫沒有問題
// 2. buf如果當(dāng)成一個字符串來看,最后一定加上一個'\0'
字符串的重要屬性:結(jié)尾一定有個'\0'
(1)buf當(dāng)成字符串的寫法:
char buf[10] = {'a','b','c', '\0'};
char buf[10] = {"abc"};
// buf當(dāng)成字符串最合理的寫法
// C語言編譯器看到雙引號,就會自動在末尾加上'\0'
char buf[10] = "abc";
char buf[] = "abc";
(2)經(jīng)典錯誤2:
char buf[10] = "abc";
// buf有空間瞻离,再把abc逐一地拷貝到buf中
// 通過初始化方法完成了常量區(qū)向變量區(qū)的拷貝。
// 因此力惯,對buf變量區(qū)的值進(jìn)行修改是可以的;但無法對“abc”常量區(qū)進(jìn)行改動召嘶。
buf[2] = 'e'; //對變量區(qū)進(jìn)行修改父晶,沒有問題
char *p = "abc";
// p直接指向abc的地址
p[2] = 'e'; // 錯誤!不能對常量區(qū)進(jìn)行修改
(3)經(jīng)典錯誤1:數(shù)組名是一個常量符號弄跌,只是一個標(biāo)簽常量甲喝,是無法改變的,一定不要放到=
的左邊铛只。
char buf[100] = "abc"; // 數(shù)組空間的初始化埠胖,是空間的第一次賦值,可以直接這樣寫
buf = "hello world"; // 錯誤淳玩!
// 想把空間的值變?yōu)槠渌背罚@是進(jìn)行空間的第二次賦值,就不能直接這樣寫了蜕着,只能逐一處理:
buf[0] = 'h';
buf[1] = 'e';
...
buf[n] = 'd';
buf[n+1] = 0;
C語言編譯器只支持第一次空間賦值(初始化)時谋竖,直接=
來一次賦值红柱;第二次開始,必須進(jìn)行逐一賦值蓖乘。
問題:
第二次賦值锤悄,是很多人都有的需求,而逐一賦值工作量太大啦嘉抒!
鑒于此零聚,C語言提供了一套字符拷貝函數(shù)。
2些侍、字符拷貝函數(shù)(strcpy握牧、strncpy)
字符拷貝函數(shù):內(nèi)存空間和內(nèi)存空間的逐一賦值功能的一個封裝體。
注意:一旦空間中出現(xiàn)了0這個特殊值娩梨,字符拷貝函數(shù)就將結(jié)束。
也就是說览徒,只有遇到\0
狈定,strcpy和strncpy才會結(jié)束拷貝;否則會一直拷貝习蓬。
(1)strcpy
char *strcpy(char *dest, const char *src);
使用strcpy實現(xiàn)第二次空間賦值:
char buf[10] = "abc";
// buf = "hello world";
strcpy(buf, "hello world"); // 使用strcpy實現(xiàn)了第二次空間賦值纽什!
該函數(shù)存在嚴(yán)重的內(nèi)存泄漏問題,在工程中絕對不能使用躲叼!
char buf[10] = "abc";
strcpy(buf, "hello world, i am lixingzhi. How are you ? ...");
// buf只有10個連續(xù)空間芦缰,但是strcpy時字符串的字符多于10個,導(dǎo)致內(nèi)存泄漏
(2)strncpy
char *strncpy(char *dest, const char *src, size_t n);
3枫慷、非字符空間
字符空間:可以使用ASCII碼來解碼的空間让蕾,其目的是讓人看的(%s
看字符空間的內(nèi)容,人可以看懂)
字符空間有字符串和結(jié)束標(biāo)志(\0)或听。
非字符空間:
數(shù)據(jù)采集探孝,是8bit或其倍數(shù)為單位來進(jìn)行采集的。
所以需要開辟一個存儲這些數(shù)據(jù)的空間誉裆。
char buf[10]; // 看到char顿颅,第一反映就是:一定是個string(字符串)
unsigned char buf[10]; // 看到unsigned char,一定是個data(普通數(shù)據(jù)足丢,非字符串)
注意:非字符空間的第二次賦值粱腻,不能用strcpy和strncpy:
unsigned char *p = sensor_base; // sensor的數(shù)據(jù)
strcpy(buf, p);
// strcpy遇到\0才會結(jié)束。sensor_base里很可能沒有\(zhòng)0斩跌,或者剛開始就是低電平(0)
問題:
字符空間的拷貝绍些,結(jié)束標(biāo)志為\0
;那么非字符空間拷貝的結(jié)束標(biāo)志是什么耀鸦?
非字符空間沒有結(jié)束標(biāo)志遇革,只能定義拷貝的個數(shù)。
因此其拷貝的三要素:
- src
- dest
- 拷貝的個數(shù)
4、memcpy
// man memcpy:
#include <string.h>
void *memcpy(void *dest, const void *src, size_t n);
// void *:非字符空間標(biāo)識符
// n:非字符空間的大小
例1:
int buf[10];
int sensor_buf[100];
// memcpy(buf, sensor_buf, 10); 錯誤B芸臁锻霎! 10是10個字節(jié)(char)
memcpy(buf, sensor_buf, 10 * sizeof(int)); // 拷貝的是10個int大小
例2:
unsigned char buf[10];
unsigned char sensor_buf[100];
memcpy(buf, sensor_buf, 10 * sizeof(unsigned char));
三、用指針表示數(shù)組
1揪漩、一維數(shù)組與一級指針
int b[100];
int *p1 = b; // 數(shù)組名就是數(shù)組首地址旋恼,可以賦給一個指針
2、指針數(shù)組與多級指針(二級指針)
int b[100]; // 100個空間都存的是int整型值
// 指針數(shù)組
char *a[100]; // 100個空間都存的是*(指針)奄容,指針對取的方式是char(一個字節(jié)一個字節(jié)地操作)
sizeof(a) = 100 * 4; // 1個地址4個字節(jié)
// 二級指針
char **a ;
// 指針數(shù)組和二級指針冰更,都通過a[0]、a[1]這樣的方式訪問
3蜀细、多維數(shù)組(二維數(shù)組)
(1)Q:二維數(shù)組與二級指針有關(guān)嗎?
// 定義一個指針戈盈,指向int b[5][6]的首地址
// 錯誤5煜巍:
int **p2 = b;
例1:
// 001.c
#include <stdio.h>
int main()
{
int a[5][6]; // 二維數(shù)組
int **p2 = a; // 二級指針
return 0;
}
二維數(shù)組與二級指針沒有一點關(guān)系归斤,完全不一樣。
二級指針:只是描述地址的線性關(guān)系刁岸,是地址的一個存儲器脏里。
二維數(shù)組:一塊一塊地讀內(nèi)存。
(2)Q:二維數(shù)組該如何用指針表示虹曙?
int a; // 一個int型變量a
int *p; // 一個int型指針p
int a[5];
int *p[5];
int (*p)[5];
例2:
// 002.c
#include <stdio.h>
int main()
{
int a[5][6];
int (*p2)[6] = a; // 指針表示二維數(shù)組
return 0;
}
(3)多維數(shù)組
int b[2][3][4]; // 多維數(shù)組
int (*p)[3][4] = b; // 指針表示多維數(shù)組