您好,登錄后才能下訂單哦!
1野指針強化:
#include <stdio.h> #include <stdlib.h> #include <string.h> // 野指針產生的原因 //指針變量和它指向的內存空間變量是兩個不同的概念 //釋放了指針所指向的內存空間,但是指針變量本省沒有重置為NULL //造成釋放的時候,通過if(p1 != NUll) //避免方法: // 1)定義指針的時候,初始化成NULL // 2)釋放指針所指向的內存空間,把指針重置成NULL int main() { char *p1 = NULL; p1 = (char *)malloc(100); if (p1 == NULL) { printf("沒有分配到堆空間 \n"); return 0; } strcpy(p1, "1234567890"); printf("%s \n", p1); if (p1 != NULL) { free(p1); //p1 = NULL;//如果沒有這個步驟,下面的再次釋放就導致程序出錯(VS2013) } if (p1 != NULL) { free(p1); } }
NULL 地址寫入數據
不可預料的地址寫入數據
不斷改變指針的指向:
#include <stdio.h> #include <stdlib.h> #include <string.h> int main() { char buf[20] = { 'a', '1', 'b', '2', 'c', '3', 'd', '4', 'e', '5' }; char *p1 = NULL; char *p2 = NULL; p1 = &buf[0]; p1 = &buf[1]; p1 = &buf[2]; int i = 0; for (i = 0; i < 10; i++) { p1 = &buf[i]; printf("%c ", *p1); } p2 = (char *)malloc(20); strcpy(p2,"1234567890"); for (i = 0; i < 10; i++)//不斷的修改指針的值,相當于不斷改變指針的指向 { p1 = p2+i;//注意p2的步長是char printf("%c ",*p1); } free(p2); system("pause"); } 編譯運行: C:\Users\chunli>gcc main.c & a a 1 b 2 c 3 d 4 e 5 1 2 3 4 5 6 7 8 9 0 請按任意鍵繼續. . .
字面量:
#include <stdio.h> #include <stdlib.h> #include <string.h> int main() { //結論:字面量不能取地址,沒有放在棧區,也沒有放在堆區,因為沒法取其地址 //我覺得放在代碼區 int i = 0; //字面量 0 0不能取地址 for (i = 0; i < 10; i++) //字面量 10 10不能取地址 { printf("Hello World! \n"); } } 便于運行: C:\Users\chunli>gcc main.c & a Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World!
從0級指針到1級指針:
#include <stdio.h> #include <stdlib.h> #include <string.h> int fun1() { int a = 20; return a; } int fun2(int a) { a = 30; } int fun3(int *a) { *a = 40; } int main() { int a = 10; int *p = NULL; p = &a; printf("%d \n",*p); fun1(); printf("%d \n", *p); fun2(a); //只是把a的數值傳過來,用來初始化函數的值,除此之外,函數內與a沒有任何關系了 printf("%d \n", *p); fun3(&a); //只有把a的地址傳過來,才能對a進行修改 printf("%d \n", *p); system("pause"); } /* 編譯運行: 10 10 10 40 請按任意鍵繼續. . . */
從1級指針到2級指針:
#include <stdio.h> #include <stdlib.h> #include <string.h> void fun1(char **p2) //只有這種方法才能修改一級指針的數值 { *p2 = 0xff; //間接修改一級指針的值,而不是修改一級指針指向的內存塊 } void fun2(char *p2) //這種方法永遠也不可能修改傳過來的一級指針的數值 { //char *p2 就相當于是在這里定義了一個p2指針變量,和外界的一級指針沒有任何關系 p2 = 0xf; } int main() { char *p1 = NULL; char *p2 = NULL; //直接修改p1的值 p1 = 0x22; p2 = 0x55; //間接是修改p1的值 p2 = &p1; //把p1的地址裝入p2 *p2 = 100; //把變量p1的值修改為100 printf("%d \n",p1); //把p1的數值打印出來 fun1(&p1); //間接修改一級指針的值,而不是修改一級指針指向的內存塊 printf("%d \n", p1); //把p1的數值打印出來 fun2(p1); printf("%d \n", p1); //把p1的數值打印出來 system("pause"); } /* 編譯運行: 100 255 255 請按任意鍵繼續. . . */
【重要概念】
間接賦值(*p) 是指針存在的最大意義
#include <stdio.h> #include <stdlib.h> #include <string.h> void fun1(char **myp1, int *mylen1, char **myp2, int *mylen2) { int ret = 0; char *tmp1 = NULL; char *tmp2 = NULL; //間接賦值 tmp1 = (char *)malloc(100); strcpy(tmp1, "1234567890"); *mylen1 = strlen(tmp1);// 1級指針 *myp1 = tmp1; //2級指針 tmp2 = (char *)malloc(200); strcpy(tmp2, "abcdefg"); *mylen2 = strlen(tmp2);// 1級指針 *myp2 = tmp2; //2級指針 } int main() { /* 原來p1的值是NULL,通過函數調用,p1指向了一塊內存區域 */ char *p1 = NULL; char *p2 = NULL; int len1 = 0; int len2 = 0l; int ret = 0; fun1(&p1, &len1, &p2, &len2); if (ret != 0) { printf("error :%d \n", ret); } printf("%s \n", p1); printf("%s \n", p2); if (p1 != NULL) { free(p1); p1 = NULL; } if (p2 != NULL) { free(p2); p2 = NULL; } system("pause"); return ret; } /* 編譯運行: 1234567890 abcdefg 請按任意鍵繼續. . . */
間接賦值的成立條件:
#include <stdio.h> #include <stdlib.h> #include <string.h> void fun1(int *p) { *p = 50; } int main() { //條件1,定義了2個變量 int a = 0; int *p = NULL; //條件2,建立關聯 p = &a; //條件3,*p間接修改 *p = 10; printf("%d \n",a); //一級指針與函數 fun1(&a); //把實參的地址傳給形參,建立關聯 printf("%d \n", a); system("pause"); return 0; } /* 編譯運行: 10 請按任意鍵繼續. . . */
//間接賦值的應用場景
#include <stdio.h> #include <stdlib.h> #include <string.h> /* 間接賦值成立的三個條件: 條件1:定義變量(實參),定義變量(形參) 條件2:建立關聯 條件3:形參去間接的修改了實參的值 */ //間接賦值的應用場景 // 條件1 2 3 寫在一個函數中 int main() { char from[100] = { 0 }; char to[100] = { 0 }; char *p1 = from; char *p2 = to; strcpy(from,"112233445566"); while (*p1 != '\0') { *p2++ = *p1++; } printf("%s \n",to); system("pause"); return 0; } /* 編譯運行: 112233445566 請按任意鍵繼續. . . */
字符串與一級指針 專題 --- //字符數組的初始化
#include <stdio.h> #include <stdlib.h> #include <string.h> //字符串與一級指針 專題 --- //字符數組的初始化 // 1 C語言中的字符串是以數字0結尾的 // 2 在C語言中沒有字符串類型,通過字符數組來模擬字符串 // 3 字符串的內存分配可以在堆上 棧上 常量區 int main() { char buf1[100] = { 'a', 'b', 'c', 'd' };//除前面4個外,其他全是0 printf("%d \n",buf1[99]); //char buf2[2] = { 'a', 'b', 'c', 'd' };//大于初始化的內存個數,編譯器報錯 char buf3[] = { 'a', 'b', 'c', 'd' };//這不是以0結尾的字符串 char buf4[] = "abcd"; //數組的大小是5,字符長度是4 int size = sizeof(buf4); int len = strlen(buf4); printf("size=%d, len=%d \n",size,len); system("pause"); return 0; } /* 編譯運行: 0 size=5, len=4 請按任意鍵繼續. . . */
字符串與一級指針 專題 -- 用數組和指針操作字符串
#include <stdio.h> #include <stdlib.h> #include <string.h> //字符串與一級指針 專題 -- 用數組和指針操作字符串 //普通指針與數組變量名字的區別 int main() { int i = 0; char *p1 = NULL; char buf1[128] = "abcdefg"; for (i = 0; i < strlen(buf1);i++) { printf("%c ",buf1[i]); } //用指針操作字符串 p1 = buf1;//buf代表數組元素的地址,這句話是錯誤的。應該說,buf代表數組首元素的地址 for (i = 0; i < strlen(buf1); i++) { printf("%c ", *(p1 + i)); //效果一樣 printf("%c ", *(buf1 + i)); //效果一樣 相當于buf1[i] //[] 到* 的推導過程 //buf1[i] => buf1[0+i] => *(buf+i) ,buf代表數組首元素的地址 //其實[] 與 * 操作數組,沒有多大的區別,只是中括號便于人們的閱讀 } //不允許的操作 //buf1 = buf1 + 1; 左操作數必須為左值 system("pause"); return 0; } // 中括號[]的本質:和*是一樣,只不過是符合程序員的閱讀習慣 // buf是一個指針,只讀的常量,buf是一個常量指針。 //為什么這么做? //buf是一個常量指針,析構內存的時候,保證buf空間完整釋放 /* 編譯運行: a b c d e f g a a b b c c d d e e f f g g 請按任意鍵繼續. . . */
一級指針 內存模型的建立
#include <stdio.h> #include <stdlib.h> #include <string.h> //一級指針 內存模型的建立 int main() { char buf1[20] = "aaa"; char buf2[] = "bbbb"; char *p1 = "11111111111111"; char *p2 = malloc(100); strcpy(p2,"333333"); system("pause"); return 0; //見圖 } /* 編譯運行: */
字符串做函數參數
#include <stdio.h> #include <stdlib.h> #include <string.h> //字符串做函數參數 int main() { char a[] = "i am a student"; char b[64]; int i = 0; for (i = 0; *(a + i) != '\0'; i++) { *(b + i) = *(a + i); //'\0' 并不會存入 } b[i] = '\0'; //'\0' 并不會存入 printf("%s \n",b); system("pause"); return 0; } /* 編譯運行: i am a student 請按任意鍵繼續. . . */
字符串拷貝,3種方法
#include <stdio.h> #include <stdlib.h> #include <string.h> //字符串拷貝,3種方法 void copy_str1(char *from, char *to) { while (*from != '\0') //當遇到0就跳出來了 { //指針的指向不斷變化,小心啊 // ++ 優先級高 *to++ = *from++; //'\0' 并不會存入 //相當于先 *to = *from, 在to++ from++ } *to = '\0'; return; } void copy_str2(char *from, char *to) //優化一下 { while ((*to = *from) != '\0') //先把值賦過去,再判斷 { *to++; *from++; } } //經典程序之一 字符串拷貝 void copy_str(char *from, char *to) //再優化一下 { while (*to++ = *from++); //先把值賦過去,再判斷 } int main() { char *from = "Hello"; char buf[100] = {0}; copy_str(from,buf); printf("%s \n",buf); system("pause"); return 0; } /* 編譯運行: i am a student 請按任意鍵繼續. . . */
經典程序之一 字符串拷貝
#include <stdio.h> #include <stdlib.h> #include <string.h> //字符串拷貝,3種方法 //經典程序之一 字符串拷貝 //不要輕易改變形參的值 int copy_str(char *from, char *to) //再優化一下 { char * tmp_to = to; //引進一個輔助 if (from == NULL || to == NULL) return -1; while (*to++ = *from++); //先把值賦過去,再判斷 //不能出現 printf("%s \n",to)這樣的語句,因為to已經改變了 printf("%s \n",tmp_to); return 0; } int main() { int ret = 0; char *from = "Hello"; //char *buf = NULL; char buf[20] ; ret = copy_str(from,buf); if (ret != 0) { printf("fun copy_str error %d \n", ret); } printf("%s \n",buf); system("pause"); return ret; } /* 編譯運行: i am a student 請按任意鍵繼續. . . */
項目開發字符串模型 do while 模型
#include <stdio.h> #include <stdlib.h> #include <string.h> //項目開發字符串模型 do while 模型 int main() { int count = 0; char *p = "11abcd123abcd234abcd23abcd2345abcd"; do { p = strstr(p, "abcd"); if (p != NULL) { count++; p = p + strlen("abcd"); } else { break; } } while (*p != '\0'); printf("%d \n" ,count); system("pause"); return 0; } /* 編譯運行: */
項目開發字符串模型 while 模型
#include <stdio.h> #include <stdlib.h> #include <string.h> //項目開發字符串模型 while 模型 int main() { int count = 0; char *p = "11abcd123abcd234abcd23abcd2345abcd"; while (p=strstr(p,"abcd")) { count++; p = p + strlen("abcd"); if (*p == '\0') { break; } } printf("%d \n" ,count); system("pause"); return 0; } /* 編譯運行: */
項目開發字符串模型 while 模型 -- API封裝
#include <stdio.h> #include <stdlib.h> #include <string.h> //項目開發字符串模型 while 模型 -- API封裝 int getCount(char *String/*in*/, char *sub/*i*/, int *count/* out*/) { int tmp_count = 0; int ret = 0; char *p = String; if (String == NULL || sub == NULL) { ret = -1; printf("fun getCount error String == NULL || sub == NULL %d \n ",ret); return ret; } while (p = strstr(p, sub)) { tmp_count++; p = p + strlen(sub); if (*p == '\0') { break; } } *count = tmp_count; return 0; } int main() { int ret = 0; int count = 0; char *p1 = "11abcd123abcd234abcd23abcd2345abcd"; char *p2 = "abcd"; ret = getCount(p1,p2,&count); if (ret != 0) { printf("fun fetCount error %d \n",ret); } printf("%d \n" ,count); system("pause"); return ret; } /* 編譯運行: */
練習題:
第一題,我的答案:
#include <stdio.h> #include <stdlib.h> #include <string.h> int str_del(const char *str1/*in*/, char * str2/*out*/) { int ret = 0; if (str1 == NULL || str2 == NULL) { ret = -1; printf("fun str_del str1 == NULL || str2 == NULL error: %d \n",ret); return ret; } char *p = str1; while (*p == ' ') { p++;//跳出空格 } strcpy(str2, p);//從第一個非空格開始,寫入原字符串 int len = strlen(str2); if (str2[len-1] == ' ')//如果最后一位有空格 { p = str2+len-1;//找到最后一個空格的位置 while (*p == ' ') { *p = 0; p--; } } return ret; } int main() { int ret = 0; char *str1 =" abc 123 "; char str2[128]; ret = str_del(str1,str2); if (ret != 0) { printf("error in fun str_del code:%d\n",ret); return ret; } printf("%s", str2); system("pause"); return ret; } /* 編譯運行: abc 123請按任意鍵繼續. . . */
第二題,我的答案:
#include <stdio.h> #include <stdlib.h> #include <string.h> int getstr(const char *str1/*in*/, char * str2/*out*/, char * str3/*out*/) { int ret = 0; if (str1 == NULL || str2 == NULL || str3 == NULL) { ret = -1; printf("fun str_del str1 == NULL || str2 == NULL || str3 == NULL error: %d \n",ret); return ret; } char *p1 = str1; char *p2 = str2; char *p3 = str3; int i = 0; while (*p1 != '\0') { if (i % 2) *p2++ = *p1; else *p3++ = *p1; i++; p1++; } return ret; } int main() { int ret = 0; char *string ="1a2b3c4da1b2c3d4"; char str1[128] = { 0 }; char str2[128] = { 0 }; ret = getstr(string,str1,str2); if (ret != 0) { printf("error in fun str_del code:%d\n",ret); return ret; } printf("str1=%s\n", str1); printf("str2=%s\n", str2); system("pause"); return ret; } /* 編譯運行: str1=abcd1234 str2=1234abcd 請按任意鍵繼續. . . */
指針經典話語:
1,指針指向誰,就把誰的地址賦給指針;
2,指針變量 和 它指向的內存空間變量是兩個不同的概念
3,理解指針的關鍵是內存,沒有內存哪里來的指針
變量的本質是一個固定大小的數據塊,變量名就是數據塊的編號
內存的使用范圍:
main函數可以在棧分配內存/堆分配內存/全局分配內存,可以給子函數使用
子函數在棧分配的內存不能給主函數使用,但是堆內存與全局變量是可以給main使用
編譯器會為每個程序分配一個內存4區,主函數與子函數公用這個內存4區
建立正確程序運行內存布局圖是學好C的關鍵!
指針鐵律1:指針是一種數據類型
1)指針也是一種變量,占有內存空間,用來保存內存地址
2)*p 操作內存;
3)*就像一把鑰匙,通過一個地址(&a),去修改a變量的標示的內存空間
4)不斷的給指針賦值,相當于不停的改變指針的指向。
5) 指針是一種數據類型,是指它指向內存空間的數據類型
指針鐵律1:間接賦值(*p) 是指針存在的最大意義
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。