C語言 指標基礎篇 陣列,函式與指標的運用 2 14
下面看看如何在函式中運用指標吧
下面是往函式傳入指標的簡單操作,不是傳入陣列的。判斷一個a是否大於b是的話給,是的話對其進行操作,不是的話就直接返回。
1 #include <stdio.h> 2 int main(){ 3 int num1,num2,*p1,*p2; 4 p1 = &num1,p2=&num2; 5 scanf("%d%d",&num1,&num2); 6 7 int fun(int *n1,int *n2); //我們在宣告函式時候,要定義好“指標變數” 8if(*p1<*p2){ 9 fun(p1,p2); //而在傳入值的時候只需要把指標變數傳入進去就行了,這裡沒有*是因為指標變數值需要在宣告的時候加* 10 } 11 printf("max num is:%d\nmin mum is:%d",*p1,*p2); //這裡的*P就是解引用的操作 12 return 0; 13 } 14 int fun(int *n1,int *n2){ //宣告的指標變數和定義的指標變數的名字必須相同 15 int tmp; 16 tmp = *n1; 17 *n1 = *n2;18 *n2 = tmp; 19 return 0; 20 }
下面是函式中在運用傳入指標的時候的錯誤操作
錯誤1:
1 int fun(int *n1,int *n2){ 2 int tmp; 3 tmp = n1; 4 n1 = n2; 5 n2 = tmp; 6 return 0; 7 }
原因:不能達到預期結果,因為這隻交換了p1和p2的值,只是交換了他們的儲存空間,沒有交換內容。並且本身修改後不能傳回實參,即不能傳到main函式,最直接的就是編譯器會直接報錯。
錯誤2:
1 intfun(int *n1,int *n2){ 2 int tmp*; 3 tmp* = *n1; 4 *n1 = *n2; 5 *n2 = *tmp; 6 return 0; 7 }
原因:上述方式,定義了一個未知空間temp,並且通過指標修改了其資料。如果temp中存的是非常重要的內容,那麼程式就會出問題,所以這種方法也是非常不可取的。但是編譯的時候是不會報錯的。
錯誤3:
1 int fun(int n1,int n2){ 2 int tmp; 3 tmp = n1; 4 n1 = n2; 5 n2 = tmp; 6 return 0; 7 }
原因:能傳遞,但是不能輸出交換後的值。
錯誤4:
1 int fun(int *n1,int *n2){ 2 int tmp; 3 tmp = n1; 4 n1 = n2; 5 n2 = tmp; 6 return 0; 7 }
原因:這樣根本就沒有呼叫到傳入的值,所以也不會進行操作。
1 #include <stdio.h> 2 int main(){ 3 int num1,num2,*p1,*p2; 4 p1 = &num1,p2=&num2; 5 scanf("%d%d",&num1,&num2); 6 7 int fun(int *n1,int *n2); 8 if(*p1<*p2){ 9 fun(p1,p2); 10 } 11 printf("max num is:%d\nmin mum is:%d",*p1,*p2); //這裡取的是經過函式操作後的p1和p2,並沒有用返回值。 12 return 0; 13 } 14 int fun(int *n1,int *n2){ 15 int tmp; 16 tmp = n1; 17 n1 = n2; 18 n2 = tmp; 19 return 0; 20 }
而在上面你也可以看到,我們並沒有取返回值。但是我們可以獲取到經過函式操作後的結果。
我們再弄一個例子,輸入三個數。按照大小排列。用指標的方式實現:
1 #include <stdio.h> 2 int main(){ 3 int a,b,c,*p1,*p2,*p3; 4 printf("Please input two num:"); 5 p1 = &a,p2=&b,p3=&c; 6 scanf("%d %d %d",&a,&b,&c); 7 int pd(int *num1,int *num2,int *num3); 8 pd(p1,p2,p3); 9 printf("%d>%d>%d",*p1,*p2,*p3); 10 return 0; 11 } 12 int pd(int *num1,int *num2,int *num3){ 13 int lj(int *n1,int *n2); 14 int i; 15 for (int i = 0; i <3 ; ++i) { 16 if (*num1 < *num2) { 17 lj(num1, num2); 18 } else if (*num1 < *num3) { 19 lj(num1, num3); 20 } else if (*num2 < *num3) { 21 lj(num2, num3); 22 } 23 } 24 return 0; 25 } 26 int lj(int *n1,int *n2){ 27 int tmp; 28 tmp = *n1; 29 *n1 = *n2; 30 *n2 = tmp; 31 return 0; 32 } 33 //這個程式碼有兩個要點: 34 //1,他們的都是靠指標進行返回的,也就是說可以返回多個值 35 //2,在進行邏輯的判斷或其他的操作的時候就把指標轉換成值,如果是函式進行傳值的話就用指標進行傳遞。
把指標作為函式的返回值
方法:1,定義函式的時候型別定義成指標型別。2,返回值是一個地址。
如下例子:
1 #include <stdio.h> 2 int main(){ 3 char str[] = "luotianyi"; 4 5 char* found(char* str,char ch); 6 char* p = found(str,'i'); 7 if (p == NULL){ 8 printf("沒有此字元\n"); 9 } 10 else{ 11 printf("輸出此字元:%s\n",p); //輸出字串,因為陣列的名字是陣列的首地址,又因為是地址。所以不需要加上“&”所以也不需要加上“*”。只有字串才可以,字元不行。 12 } 13 return 0; 14 } 15 //我們先定義函式的型別是指標型別 16 char* found(char* str,char ch){ //這裡的括號裡面的char後面要加上“*”是因為我們在宣告和定義的時候沒有說str是一個數組,因此只能通過 17 //“*”把傳入的首地址轉換為其元素的值,我們才能在下面對其進行操作。如果把宣告和定義換成:char str []也是可以的 18 int i=0; 19 while (str[i]){ 20 if (str[i] == ch){ 21 return &str[i]; //把需要的值進行返回的值的地址進行返回。 22 } 23 i++; 24 } 25 return NULL; 26 }
上面的裡面的判斷使用陣列進行的,而我們可以用指標進行判斷。
如下例子:
1 #include <stdio.h> 2 int main(){ 3 char str[] = "luotianyi"; 4 char* found(char* str,char ch); 5 char* p = found(str,'i'); 6 if (p == NULL){ 7 printf("沒有此字元\n"); 8 } 9 else{ 10 printf("輸出此字元:%s\n",p); //輸出字串,以為陣列名是陣列的首地址。因此不需要加上“&”所以在獲取的時候也不需要加上“*”。只有字串才可以,字元不行。 11 } 12 return 0; 13 } 14 //我們把宣告的型別換成是指標型別 15 char* found(char* str,char ch){ //這裡的括號裡面的char後面要加上“*”是因為我們在宣告和定義的時候沒有說str是一個數組,因此只能通過 16 //“*”把傳入的首地址轉換為其元素的值,我們才能在下面對其進行操作。如果把宣告和定義換成:char str []也是可以的 17 while (*str){ //這裡的“*”就是獲取指標的值,其實與str[i]是一樣的 18 if (*str == ch){ 19 return str; //這裡的str在傳入的時候就已經規定是指標的型別了,因此不需要再次* 20 } 21 str++; //對指標的自加操作 22 } 23 return NULL; 24 }
下面是陣列如何運用指標的
陣列的地址其實是這樣的,例如:int a[2] = {0,1,2};這樣的話其實在記憶體中是對其每一個元素都開闢了一個地址的,假設第一個元素的地址是101,第二個是105,第三個就是這是因為:1,int本身就佔4個位元組,每一個int的元素也是佔4個位元組。2,陣列的地址是具有連貫性的,是一個接著一個的。3,我麼可以通過指標的偏移來取出一個個陣列的內容。而這個的陣列的地址,其實就是第一個元素的地址。下面就讓我們來一個個的證明這些觀點
陣列的地址就是陣列第一個元素的地址
1 #include <stdio.h> 2 int main() 3 { 4 int sz[] = {1,2,3,4}; 5 printf("%p\n",&sz); //取整個陣列的地址 6 printf("%p\n",&sz[0]); //取第一個元素地址 7 return 0; 8 } 9 //輸出結果: 10 //0xffffcc10 11 //0xffffcc10例子
每一個元素佔4個位元組,陣列的地址具有連貫性
1 #include <stdio.h> 2 int main() 3 { 4 int sz[] = {1,2,3,4}; 5 printf("%ld\n",&sz[0]); 6 printf("%ld\n",&sz[1]); 7 printf("%ld\n",&sz[2]); 8 printf("%ld\n",&sz[3]); 9 10 return 0; 11 } 12 //這裡本來應該是用%p輸出地址的,%p輸出的是16進位制的。但是為了方便看改正了%lp 13 /* 14 * 輸出結果 15 *4294954000 16 *4294954004 17 *4294954008 18 *4294954012 19 */例子
看看如何通過指標的偏移,進行呼叫
1 #include <stdio.h> 2 int main() 3 { 4 int sz[] = {1,2,3,4}; 5 int *p = &sz[0]; 6 printf("%d\n",*(p+1)); 7 printf("%d\n",*(p+2)); 8 return 0; 9 }例子
下面我們來看一個如何用指標運用陣列
1 #include <stdio.h> 2 int main() 3 { 4 int sz[] = {1,2,3,4}; 5 int *p; //把陣列的首字元給了指標p 6 int num =0; 7 for (p = &sz[0];p<=&sz[3];p++){ //在這裡我們的迴圈是用地址來定義的,這裡直接定義成&sz也可以,但是有警告 8 num = num + *p; //而我們也可以用地址來獲取到對應的值 9 } 10 printf("num : %d",num); 11 return 0; 12 }例子
下面總結下,有三種方法訪問陣列;
1,下標法
1 #include <stdio.h> 2 int main() { 3 int num[] = {0,1,2,3,4,5,6,7,8,9}; 4 for(int i=1;i<10;i++){ 5 printf("%d\n",num[i]); 6 } 7 return 0; 8 }例子
2,通過陣列名字獲取到期地址,找出地址的值。
1 #include <stdio.h> 2 int main() { 3 int num[] = {0,1,2,3,4,5,6,7,8,9}; 4 printf("%ld\n",num); //這裡可以看出,我們直接訪問這個陣列的話是直接訪問到地址的:4294953968為了 5 // 方便我們用長整型的方法輸出 6 for (int i = 0; i < 10; ++i) { 7 printf("%d\n",*(num+i)); //因為上面直接訪問了 陣列名字得到的是地址,所以我們直接在陣列前面加上*就可以 8 // 直接找到地址所對應的值 9 //這裡加i實際上因為型別的原因是每次加上四個位元組 10 } 11 return 0; 12 }例子
3,用指標變數通過指標的偏移而找到值。
1 #include <stdio.h> 2 int main() { 3 int num[] = {0,1,2,3,4,5,6,7,8,9}; 4 int *p = &num[0]; 5 for(int i=0 ;i<10;i++,p++){ 6 printf("%d\n",*p); 7 } 8 return 0; 9 }例子
陣列的指標偏移1表示指標往右邊移動了一個型別,例如:int的型別加1等於指標地址加上了4個位元組。
指標通過迴圈輸出了陣列所有的元素,然後指標本身就變成了一個野指標。我們可以通過過:野指標-陣列名 =陣列的個數(也可以說是指標的偏移量)
函式傳入陣列
陣列做函式引數,說具體是指向陣列的指標變數做函式引數。
由於陣列名是該陣列的首地址,指標變數的值也是首地址,所以函式的實參和形參都可以指向陣列名或者陣列的指標。於是有了以下四種對應關係:
例子:
1 #include <stdio.h> 2 int main() 3 { 4 float ave(int *b, float num); //這裡的是宣告函式 5 int counter,a[5] = {0}; 6 float all =0, res; 7 8 scanf("%f", &all); 9 for(counter = 0; counter < all; counter++) 10 { 11 scanf("%d", &a[counter]); 12 } 13 res = ave(a, all); //這裡把陣列的名字傳入了函式定義的指標變數。和輸入第一次輸入的次數 14 printf("%f", res); 15 return 0; 16 } 17 18 float ave(int *b, float num) //這裡和上面宣告函式一樣 19 { 20 int i, sum =0; 21 float ave; 22 for(i = 0; i < num; i++) 23 { 24 sum = sum + b[i]; 25 } 26 ave = (float)sum/num; 27 return ave; 28 }
這裡傳入函式ave的是陣列a的首地址,而不是將整個陣列傳入。傳入首地址後,ave函式就按照一定順序去訪問a的儲存空間,從而得到a中的資料。
當然float ave(int *b, float num) 也可以寫為float ave(int b[], float num) 或者float ave(int b[100], float num) 也就是說b[] 後面方括號內可以是任意數字,因為那個數字是沒有意義的,真真起作用的是b和方括號。
總結一下這部分就是:
陣列做形參,其實就是指標做形參。只要指標向函式內傳入陣列首地址,那麼函式形參和實參是指同一陣列。函式內部對陣列所做的處理,就是對主調函式中的實引數組所作的處理,可以傳回主調函式。
指標和字串與函式
f(int arr[ ] ,int n)但是在編譯時是將arr按指標變數處理的,相當於將函式 f 的首部寫成 f ( int* arr,int n)。這兩種寫法是等價的,而%s的輸出可以是字串的地址,而不需要解引用。
輸出字串有三種方法,如下所示。
1 #include <stdio.h> 2 int main(){ 3 char ch1[] ="luotianyi"; //第一種是用陣列的方式輸出字串 4 printf("%s\n",ch1); 5 char *ch2 = "luotianyi"; //第二種是利用指標變數儲存字串 6 printf("%s\n",ch2); 7 printf("luotianyi"); //第三種是直接用把字串放到printf中 8 return 0; 9 }
這三種方法有2個區別,第一種利用陣列的方式儲存是把字串儲存在棧中(也就是可以進行修改的地方,也可以進行輸出)。第二種和第三種是儲存在堆中的(也就是隻能輸出,但是不允許進行修改)。
1 #include <stdio.h> 2 int main(){ 3 char ch1[] ="luotianyi"; 4 ch1[1] = 'w'; //可以進行修改 5 printf("%s\n",ch1); 6 char *ch2 = "luotianyi"; 7 *ch2+1 = 's'; //error: lvalue required as left operand of assignment 8 printf("%s\n",ch2); 9 printf("luotianyi"); 10 return 0; 11 }
下面我們看看字串是如何傳入函式中的,我們分別演示下用指標變數和陣列變數進行。
1 #include <stdio.h> 2 int main(){ 3 char str1[] = "luotianyi"; 4 char* str2 = "my wife"; 5 int strpri(char ch1[],char* ch2) ; 6 strpri(str1,str2); 7 return 0; 8 } 9 int strpri(char ch1[],char* ch2){ //我們分別用兩種方法傳入 10 char* tmp; //建立一個指標對其進行轉換 11 tmp = ch1; 12 ch1 = ch2; 13 ch2 = tmp; 14 ch2[3] = 'z'; 15 printf("%s\n",ch1); //在這裡可以看出指標變數所指向的字串內部雖然不可以改變,但是可以對其整體進行其他的操作。 16 //也就是說字串單個字元的操作是不可以的,但是可以對其整體進行操作 17 printf("%s\n",ch2); //這裡可以看出我們可以對陣列變數的字串進行操作 18 return 0; 19 }例子
堆與棧的區別還有就是棧可以儲存多份一樣的值,而堆只儲存一份,其餘的也要呼叫的話就是多個變數都是指向堆的這一份。
1 #include <stdio.h> 2 int main(){ 3 char* a = "luotianyi"; 4 char* b = "luotianyi"; 5 printf("%ld\n",a); 6 printf("%ld\n",b); 7 return 0; 8 } 9 /* 10 * 4299173896 11 * 4299173896 12 * */堆的示例
指標字串 or 陣列字串
1 #include <stdio.h> 2 int main(){ 3 char* ch[] = {"luotianyi","wsj","woaini"}; //這就是建立一個數組字串或是叫做指標字串 4 for (int i = 0; i < 3; ++i) { 5 printf("%s\n",ch[i]); //輸出全部 6 } 7 printf("%c\n",ch[1][2]); //第一個下標是第幾排,第二個是低階列 8 printf("%c\n",*(*(ch+1)+1)); //外面的數字是第幾橫排,裡面的是橫排的第幾個數字 9 return 0; 10 }
---------------------
部分來源和程式碼出自以下連結
來源:CSDN
原文:https://blog.csdn.net/C2681595858/article/details/53750577
版權宣告:本文為博主原創文章,轉載請附上博文連結!