一、內存含義數組
二、內存是溝通CPU與硬盤的橋樑ide
三、物理存儲器和存儲地址空間函數
四、物理存儲器:實際存在的具體存儲器芯片編碼
五、存儲地址空間:對存儲器編碼的範圍。咱們在軟件上常說的內存是指這一層含義spa
六、內存地址操作系統
七、內存中的每個數據都會分配相應的地址指針
注:windos電腦在作數據存儲時採用小端對齊。blog
注:Linux 電腦在作數據存儲時採用大端對齊。排序
注意:&能夠取得一個變量在內存中的地址。可是,不能取寄存器變量,由於寄存器變量不在內存裏,而在CPU裏面,因此是沒有地址的。
注意:&是取地址符號是升維度的、*是取值符號是將維度的。
注意:在定義指針類型必定要和變量的類型對應上。內存
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <string.h> #include <stdlib.h> #include <math.h> #include <time.h> int main(void) { // 定義指針變量存儲變量地址 int a = 10; // 指針類型:數據類型* int* p; p = &a; // 經過指針間接改變變量的值 *p = 100; printf("%p\n", &a); printf("%p\n", p); printf("%d\n", a); printf("%d\n", *p); return 0; }
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <string.h> #include <stdlib.h> #include <math.h> #include <time.h> int main(void) { char ch = 'a'; char* p = &ch; // 全部指針類型存儲都內存地址,內存地址都是一個無符號十六進制整形數 // 32位操做系統全部指針類型:內存佔用4字節 // 64位操做系統全部指針類型:內存佔用8字節 printf("%d\n", sizeof(int*)); printf("%d\n", sizeof(char*)); return 0; }
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <string.h> #include <stdlib.h> #include <math.h> #include <time.h> int main(void) { int arr[] = { 1,2,3,4,5,6,7,8,9,10 }; // P 和 arr 不一樣點 // 指向數組指針 int* p = arr; // 相同點 //p[i] //*(p+i) // 不一樣點 // p 是變量、arr是常量 // p 是一個指針4個字節大小 // arr 是一個數組是40個字節大小 printf("指針類型大小%d\n", sizeof(p)); printf("數組大小%d\n", sizeof(arr)); // 數組做爲函數參數會化爲指針、丟失數組的精度 // 經過 int* 將指針變爲值 // void BubbleSort(int arr[]) // void BubbleSort(int* arr[],int len) return 0; }
指針變量也是變量,是變量就能夠任意賦值,不要越界便可(32位爲4字節,64位爲8字節),可是,任意數值賦值給指針變量沒有意義,由於這樣的指針就成了野指針,此指針指向的區域是未知(操做系統不容許操做此指針指向的內存區域)。因此,野指針不會直接引起錯誤,操做野指針指向的內存區域纔會出問題。野指針和有效指針變量保存的都是數值,爲了標誌此指針變量沒有指向任何變量(空閒可用)
int a = 100; int *p; p = a; //把a的值賦值給指針變量p,p爲野指針, ok,不會有問題,但沒有意義 p = 0x12345678; //給指針變量p賦值,p爲野指針, ok,不會有問題,但沒有意義 *p = 1000; //操做野指針指向未知區域,內存出問題,err
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <string.h> #include <stdlib.h> #include <math.h> #include <time.h> int main(void) { // 野指針 -> 指針變量指向一個未知的空間 // 不建議將一個變量的值直接賦值給指針 // 程序中容許存在野指針 int* p = 100; // 操做系統將0-255做爲系統佔用不容許訪問操做 // 操做野指針對應的內存空間可能報錯 printf("%d\n", *p); return 0; }
C語言中,能夠把NULL賦值給此指針,這樣就標誌此指針爲空指針,沒有任何指針。
// 空指針 int *p = NULL; // NULL是一個值爲0的宏常量: #define NULL ((void *)0)
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <string.h> #include <stdlib.h> #include <math.h> #include <time.h> int main(void) { // 空指針是指內存地址編號爲0的空間 int* p = NULL; // 操做空指針對應的空間必定會報錯 *p = 100; printf("%d\n", *p); // 空指針能夠用做條件判斷 if (p == NULL) { } return 0; }
void *指針能夠指向任意變量的內存空間。
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <string.h> #include <stdlib.h> #include <math.h> #include <time.h> int main(void) { int a = 10; // 萬能指針能夠接受任意類型變量的內存地址 void * p = &a; // 再經過萬能指針修改變量的值時,須要找到變量對應的指針類型 *(int*)p = 100; printf("%d\n", a); printf("%d\n", *(int*)p); // printf("萬能指針在內存佔得字節大小:%d\n", sizeof(void*)); return 0; }
const 修飾能夠約束指針類型或值得修改,但使用+1級別指針也可讓const無效。
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <string.h> #include <stdlib.h> #include <math.h> #include <time.h> int main(void) { // 一、 // 常量:不容許修改 // 存儲空間:棧區(可指針間接修改) const int a = 10; // 指針間接修改常量值 int* p = &a; *p = 100; printf("%d\n", a); // 二、 // const 修飾指針類型(內存空間) int a = 10; int b = 20; const int* p = &a; // 能夠修改指針變量的值 // 不能夠修改指針內存空間的值:*p = 100; p = &b; printf("%d\n", *p); // 三、 // const 修飾指針變量 int c = 10; int d = 20; int* const p = &c; // 能夠修改指針類型(內存空間)的值 // 不能夠修改指針內存空間的值:p = &d; *p = 100; printf("%d\n", *p); // 四、 // const 修飾指針變量、類型(內存空間) // 只讀指針 int e = 10; int f = 20; // 不能夠修改指針內存空間的值:*p = 100; // 不能夠修改指針內存空間的值:p = &f; const int* const p = &e; // 二級指針操做 // 可經過二級指針修改一級指針內存空間的值: int** pp = &p; // *pp是一級指針的值(內存空間) *pp = &b; // **pp是變量的值、**表明將了一個維度 **pp = 100; printf("%d\n", *p); return 0; }
#include <stdio.h> #include <stdlib.h> #include <string.h> int main(void) { //const修飾一個變量爲只讀 const int a = 10; //a = 100; //err //指針變量, 指針指向的內存, 2個不一樣概念 char buf[] = "aklgjdlsgjlkds"; //從左往右看,跳過類型,看修飾哪一個字符 //若是是*, 說明指針指向的內存不能改變 //若是是指針變量,說明指針的指向不能改變,指針的值不能修改 const char *p = buf; // 等價於上面 char const *p1 = buf; //p[1] = '2'; //err p = "agdlsjaglkdsajgl"; //ok char * const p2 = buf; p2[1] = '3'; //p2 = "salkjgldsjaglk"; //err //p3爲只讀,指向不能變,指向的內存也不能變 const char * const p3 = buf; return 0; }
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <string.h> #include <stdlib.h> #include <math.h> #include <time.h> int main(void) { // 定義int類型 const int a = 10; // 直接不能夠修改 // a = 100; //err // 經過一級指針修改 int* p = &a; *p = 100; // 定義char類型 char ch1[] = "hello"; char ch2[] = "hello"; // 指向常量指針:能夠修改指針變量的值、不能夠修改指針變量指向內存空間的值 const char* p = ch1; // *p = 'm';//err // p = ch2;//ok // p[2] = 'm';//err // 定義char類型 char ch3[] = "hello"; char ch4[] = "hello"; // 常量指針:能夠修改指針變量指向內存空間的值、不能夠修改指針變量的值 char* const p = ch3; // p = ch4;//err // p[2] = 'm';//ok // *(p + 2) = 'm';//ok // 定義char類型 char ch5[] = "hello"; char ch6[] = "hello"; // 不可修改變量與內存 const char* const p = ch5; // p = ch6;//err // p[2] = 'm';//err // *p = 'm';//err // 二級指針 char** p1 = &p; // *p1 = ch2;//ok // *(*p1+1) = 'm';//ok return 0; }
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <string.h> #include <stdlib.h> #include <math.h> #include <time.h> int main(void) { int arr[] = { 1,2,3,4,5,6,7,8,9,10 }; // 數組名是一個常量 不容許賦值 // 數組名是數組首元素地址 // aar = 100; //err // 建立指針變量 int* p; p = arr; printf("%p\n", p); // 打印數組第一個值 printf("%d\n", *p); printf("%p\n", arr); // *取值(arr內存地址+1) 、至關於arr[1] printf("%d\n", *(arr + 1)); // 指針類型變量+1:等同於內存地址+sizeof(類型) printf("%d\n", *(p + 1)); // 指針p++:等同於內存地址+sizeof(類型) *p = 123; p++; printf("%p\n", arr); printf("%p\n", p); for (int i = 0; i < 10; i++) { // 打印數組值 printf("%d\n", p[i]); printf("%d\n", *(p + i)); // 打印數組值 printf("%d\n", *p++); } // 兩個指針相減 獲得的結果是兩個指針的偏移量(步長) // 全部的指針類型 相減結果都是int類型 // 3c 40 +1 至關於 sizeof(int) 40/sizeof(int) int step = p - arr; printf("%d\n", step); return 0; }
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <string.h> #include <stdlib.h> #include <math.h> #include <time.h> // 方式一:數組方式實現 void my_strcpy01(char* dest, char* ch) { int i = 0; // 非0爲真值 while (ch[i]) { dest[i] = ch[i]; i++; } dest[i] = 0; } // 方式二:以指針偏移量 void my_strcpy02(char* dest, char* ch) { int i = 0; while (*(ch+i)) { *(dest + i) = *(ch + i); i++; } *(dest + i) = 0; } // 方式三:以指針運算方式實現 void my_strcpy03(char* dest, char* ch) { while (*ch) { *dest = *ch; // 指針+1至關於指向數組下一個元素 內存地址變化了sizeof(char) dest++; ch++; } *dest = 0; } // 方式四:以指針加運算方式實現 void my_strcpy04(char* dest, char* ch) { // 第一步:*ch 取值 *dest 取值 // 第二部:*dest = *ch 賦值 // 第三部:判斷 值是否非0 // 第四部:ch++ dest++ while (*dest++ = *ch++); } int main(void) { // 指針運算、字符串拷貝 char ch[] = "hello world"; char dest[100]; my_strcpy04(dest, ch); printf("%s\n", dest); return 0; }
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <string.h> #include <stdlib.h> #include <math.h> #include <time.h> int main(void) { int arr[] = { 1,2,3,4,5,6,7,8,9,10 }; int* p = arr; // 指針的加減運算和指針的類型有關 p = &arr[3]; p--; p--; p--; // 內存地址相差:12 / sizeof(int) = 偏移量 int step = p - arr; // 指針操做數組時下標容許時負數 // p[-2] = *(p-2); printf("%d\n", p[-2]); printf("%p\n", p); return 0; }
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <string.h> #include <stdlib.h> #include <math.h> #include <time.h> int main(void) { // 指針和運算符的操做 int arr[] = { 1,2,3,4,5,6,7,8,9,10 }; int* p = arr; // 野指針 // p = p + arr; //err // p = p*arr; //err // p = p*4; //err // p = p/4; //err // p = p%4; //err // 指針判斷可使用、> = < ? && || ... // p = &arr[3] // if (p > arr) { printf("真\n");} // 野指針能夠相減 // p = 100; // int step = arr - p; ///printf("%d\n",step) return 0; }
指針數組,它是數組,數組的每一個元素都是指針類型。
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <string.h> #include <stdlib.h> #include <math.h> #include <time.h> int main(void) { // 定義數組 數據類型 數據名[元素個數] = {值1,值2} // 定義指針數組 int a = 10; int b = 20; int c = 30; int* arr[3] = { &a,&b,&c }; // arr[0]:爲指針數組地址 // *arr[0]:爲指針對應值 printf("%d\n", arr[0]); printf("%d\n", *arr[0]); for (int i = 0; i < sizeof(arr)/sizeof(arr[0]); i++) { // 打印數組內每一個值 printf("%d\n", *arr[i]); } // 指針數組大小 = 對應類型 * 元素個數 printf("指針數組大小:%d\n", sizeof(arr)); printf("指針數組大小:%d\n", sizeof(arr[0])); return 0; }
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <string.h> #include <stdlib.h> #include <math.h> #include <time.h> int main(void) { // 指針數組裏面元素存儲的是指針 int a[] = { 1,2,3 }; int b[] = { 4,5,6 }; int c[] = { 7,8,9 }; // 指針數組時一個特殊的二維數組模型 // 指針數組對應於二級指針 int* arr[] = { a,b,c }; // 打印內存地址 // arr 是指針數組的首地址 printf("%p\n", arr[0]); printf("%p\n", a); printf("%p\n", &a[0]); for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { // 經過二維數組方式打印全部值 printf("%d", arr[i][j]); // 經過偏移量方式打印 printf("%d", *(arr[i]+j)); // 經過偏移量與指針運算方式打印 printf("%d", *(*(arr + i) + j)); } puts(""); } return 0; }
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <string.h> #include <stdlib.h> #include <math.h> #include <time.h> // 數組名作函數參數,函數的形參會退化爲指針 // 經過數組寫法實現 void my_strcat01(char* ch1, char* ch2) { int i = 0; while (ch1[i] != '\0') { i++; } int j = 0; while (ch2[j] != '\0') { ch1[i + j] = ch2[j]; j++; } ch1[i + j] = 0; } // 經過指針加偏移量方式實現1 void my_strcat02(char* ch1, char* ch2) { int i = 0; while (ch1[i] != '\0') { i++; } int j = 0; while (*(ch2 + j) != '\0') { *(ch1 + i + j) = *(ch2 + j); j++; } ch1[i + j] = 0; } // 經過指針加偏移量方式實現2 void my_strcat03(char* ch1, char* ch2) { while (*ch1)ch1++; while (*ch1++ = *ch2++); } int main(void) { char ch1[100] = "hello"; char ch2[] = "world"; my_strcat02(ch1, ch2); printf("%s\n", ch1); return 0; }
int a = 10; int *p = &a; //一級指針 *p = 100; //*p就是a int **q = &p; //*q就是p //**q就是a int ***t = &q; //*t就是q //**t就是p //***t就是a
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <string.h> #include <stdlib.h> #include <math.h> #include <time.h> int main(void) { int a[] = { 1,2,3 }; int b[] = { 4,5,6 }; int c[] = { 7,8,9 }; int* arr[] = { a,b,c }; // 指針數組和二級指針創建關係 int** p = arr; // 對應:arr[0][0]、a[0] printf("%d\n", **p); // 二級指針加偏移量:至關於跳過了一個覺得數組大小 // 一級指針加偏移量:至關於跳過了一個元素 //對應:arr[0][1]、a[1] printf("%d\n", *(*p+1)); //對應:arr[1][1]、b[1] printf("%d\n", *(*(p + 1) + 1)); for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { // 經過偏移量與指針運算方式打印 printf("%d", *(*(arr + i) + j)); } puts(""); } return 0; }
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <string.h> #include <stdlib.h> #include <math.h> #include <time.h> int main(void) { //*ppp==**pp==&p //**ppp==*pp=p==&a //***ppp==**pp==*p=a int a = 10; int b = 20; int* p = &a; int** pp = &p; int*** ppp = &pp; // pp:二級指針變量的值 // *pp:一級指針的值 // **pp:變量的值 // 等價於:p=&b // *pp = &b; // 等價於:a = 100 //**pp = 100; // 野指針 // *p = 100; printf("%d\n", *p); return 0; }
字符指針經過指針處理字符
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <string.h> #include <stdlib.h> #include <math.h> #include <time.h> int main(void) { // 棧區字符串 char ch[] = "hello world"; // 數據區常量區字符串、不容許修改內容 // hello world 對應內存地址爲只讀,大小相同 char* p = "hello world"; char* p1 = "hello world"; // ch[2] = 'm'; // 可修改 // p[2] = 'm'; //err return 0; }
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <string.h> #include <stdlib.h> #include <math.h> #include <time.h> int main(void) { // 樣式一 // 能夠作修改 // 指針數組 char ch1[] = "hello"; char ch2[] = "world"; char ch3[] = "dabaobei"; char* arr1[] = { ch1,ch2,ch3 }; // 樣式二 // 不能作修改、但能夠排序 // 字符串數組 char* arr2[] = { "hello","wojjrld","zzzzz" }; // 字符串排序 for (int i = 0; i < 3 - 1; i++) { for (int j = 0; j < 3 - 1 - i; j++) { // 找首字符進行比較 if (arr2[j][0]>arr2[j + 1][0]) { // 交換指針數組進行排序 char* temp = arr2[j]; arr2[j] = arr2[j + 1]; arr2[j + 1] = temp; } } } // 打印 for (int i = 0; i < 3; i++) { printf("%s\n", arr2[i]); } return 0; }
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <string.h> #include <stdlib.h> #include <math.h> #include <time.h> // 數組實現 int my_strlen01(char* ch) { // 計算字符串有效長度 int i = 0; while (ch[i] != '\0')i++; return i; } // 指針實現 int my_strlen02(char* ch) { char* temp = ch; while (*temp != '\0')temp++; return temp - ch; } int main(void) { char ch[] = "hello world"; int len = my_strlen02(ch); printf("%d\n", len); return 0; }
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <string.h> #include <stdlib.h> #include <math.h> #include <time.h> // 指針做爲函數參數傳遞 void swap(int* a, int* b) { int temp = *a; *a = *b; *b = temp; } int main(void) { int a = 10; int b = 20; // 值傳遞 // 形參不影響實參的值 // swap(a, b); // 地址傳遞 // 形參能夠改變實參的值 swap(&a, &b); printf("%d\n", a); printf("%d\n", b); return 0; }
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <string.h> #include <stdlib.h> #include <math.h> #include <time.h> void remove_space(char* ch) { // 便利字符串有效個數 char* ftemp = ch; // 記錄非空格字符串 char* rtemp = ch; while (*ftemp) { if (*ftemp != ' ') { *rtemp = *ftemp; rtemp++; } ftemp++; } *rtemp = 0; } int main(void) { char ch[] = " h e ll o w o r lld"; remove_space(ch); printf("%s\n", ch); return 0; }
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <string.h> #include <stdlib.h> #include <math.h> #include <time.h> // 數組方式 char* my_strchr01(char* str,char ch) { int i = 0; while (str[i]) { if (str[i] == ch) { return &str[i]; } i++; } return NULL; } // 指針方式 char* my_strchr02(char* str, char ch) { while (*str) { if (*str == ch) { return str; } str++; } return NULL; } int main(void) { char str[] = "hello world"; char* p = my_strchr02(str,'w'); if (p == NULL) { printf("未找到:"); } printf("%s\n", p); return 0; }
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <string.h> #include <stdlib.h> #include <math.h> #include <time.h> char* my_strchr(char* src, char* dest) { // 用於循環便利源字符串指針 char* fsrc = src; // 記錄每次相同字符串首地址 char* rsrc = src; char* tdest = dest; while (*fsrc) { rsrc = fsrc; while (*fsrc == *tdest && *fsrc!='\0') { fsrc++; tdest++; } if (*tdest == '\0') { return rsrc; } // 回滾 // 目標字符串更新到起始位置 tdest = dest; fsrc = rsrc; fsrc++; } return NULL; } int main(void) { char src[] = "hello world"; char dest[] = "llo"; char* p = my_strchr(src,dest); printf("%s\n", p); return 0; }
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <string.h> #include <stdlib.h> #include <math.h> #include <time.h> // 數組實現 int getstrcount01(char* ch) { int i = 0; int count = 0; while (ch[i]) { if (ch[i] != ' ') { count++; } i++; } return count; } // 指針實現 int getstrcount02(char* ch) { int count = 0; while (*ch) { if (*ch != ' ')count++; ch++; } return count; } int main(void) { char ch[] = " hello world "; int len = getstrcount(ch); printf("%d\n", len); return 0; }
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <string.h> #include <stdlib.h> #include <math.h> #include <time.h> int main(void) { //97+26 ASCLL碼 // 統計字符串出現次數 char ch[] = "helloworldfdjklfdjklfdsajklfdsa dsa"; // 存儲字符串出現次數 int arr[26] = {0}; for (int i = 0; i < strlen(ch); i++) { // ASCLL碼 a - 字符、++:每找到一個相同就+1 arr[ch[i] - 'a']++; } for (int i = 0; i < 26; i++) { if(arr[i]) printf("字母:%c出現次數:%d\n", i + 'a', arr[i]); } return 0; }
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <string.h> #include <stdlib.h> #include <math.h> #include <time.h> // 數組實現 void inverse01(char* ch) { int i = 0; int j = strlen(ch) - 1; while (i < j) { char temp = ch[i]; ch[i] = ch[j]; ch[j] = temp; i++; j--; } return; } // 指針實現 void inverse02(char* ch) { char* ftemp = ch; char* btemp = ch + strlen(ch) - 1; while (ftemp<btemp) { char temp = *ftemp; *ftemp = *btemp; *btemp = temp; ftemp++; btemp--; } return; } int main(void) { char ch[] = "hello world"; inverse02(ch); printf("%s\n", ch); return 0; }
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <string.h> #include <stdlib.h> #include <math.h> #include <time.h> int symm(char* ch) { char* ftemp = ch; char* btemp = ch + strlen(ch) - 1; while (ftemp < btemp) { if (*ftemp!=*btemp) { return 1; } ftemp++; btemp--; } return 0; } // 判斷:迴文字符串 int main(void) { char ch[] = "abcba"; int value = symm(ch); if (!value) { printf("相同\n"); } else { printf("不相同\n"); } return 0; }