c語言二級指標
二級指標做輸入_第1種記憶體模型 直接利用二級指標
首先看指標陣列(變數為指標) 也就是陣列中存的都是地址
#include<stdio.h> void main() { int i = 0, j = 0; int num = 0; char *myArray[] = {"aaaaaa","cccccc","bbbbbb","111111"};//這裡定義的是指標所指向的記憶體 num = sizeof(myArray)/sizeof(myArray[0]); for(i = 0;i < num;i++) { printf("1:%s\n",myArray[i]); printf("2:%s\n",*(myArray+i)); } }
兩種輸出結果一樣說明指標陣列儲存的是指標
#include<stdio.h> #include<string.h> void main() { int i = 0, j = 0; int num = 0; char *tmp; char *myArray[] = {"aaaaaa","cccccc","bbbbbb","111111"}; num = sizeof(myArray)/sizeof(myArray[0]); //利用冒泡原理進行排序 for(i = 0;i < num;i++) { for(j = i;j < num;j++) { if(strcmp(myArray[i],myArray[j])>0) { tmp = myArray[i]; myArray[i] = myArray[j]; myArray[j] = tmp; } } } for(i = 0;i < num;i++) { printf("%s\n",myArray[i]); } }
下面進行封裝
#include<stdio.h> #include<string.h> void printMyArray(char **myArray,int num); void sortMyArray(char **myArray,int num); void main() { int num = 0; char *myArray[] = {"aaaaaa","cccccc","bbbbbb","111111"}; num = sizeof(myArray)/sizeof(myArray[0]); sortMyArray(myArray, num); printMyArray(myArray, num); } void printMyArray(char **myArray,int num) { int i = 0; for(i = 0;i < num;i++) { printf("%s\n",myArray[i]); } } void sortMyArray(char **myArray,int num) { int i = 0, j = 0; char *tmp = NULL; //利用冒泡原理進行排序 for(i = 0;i < num;i++) { for(j = i;j < num;j++) { if(strcmp(myArray[i],myArray[j])>0) { tmp = myArray[i]; myArray[i] = myArray[j]; myArray[j] = tmp; } } } }
其實陣列的名稱退化為陣列的首地址 放在指標陣列同樣會退化成指標的指標也就是二級指標
二級指標做輸入_第2種記憶體模型 利用二維陣列
二維陣列指標表示,C語言指標引用二維陣列詳解
首先了解一下二維陣列的指標
指標變數可以指向一維陣列中的元素,當然也就可以指向二維陣列中的元素。但是在概念和使用方法上,二維陣列的指標比一維陣列的指標要複雜一些。要理解指標和二維陣列的關係首先要記住一句話:二維陣列就是一維陣列,這句話該怎麼理解呢?
假如有一個二維陣列:
- int a[3][4] = {{1, 3, 5, 7}, {9, 11, 13, 15}, {17, 19, 21, 23}};
其中,a 是二維陣列名。a 陣列包含 3 行,即 3 個行元素:a[0],a[1],a[2]。每個行元素都可以看成含有 4 個元素的一維陣列。而且 C 語言規定,a[0]、a[1]、a[2]分別是這三個一維陣列的陣列名。如下所示:
a[0]、a[1]、a[2] 既然是一維陣列名,一維陣列的陣列名錶示的就是陣列第一個元素的地址,所以 a[0] 表示的就是元素 a[0][0] 的地址,即 a[0]==&a[0][0];a[1] 表示的就是元素 a[1][0] 的地址,即 a[1]==&a[1][0];a[2] 表示的就是元素 a[2][0] 的地址,即 a[2]==&a[2][0]。
所以二維陣列a[M][N]中,a[i]表示的就是元素a[i][0]的地址,即:
a[i] == &a[i][0]
我們知道,在一維陣列 b 中,陣列名 b 代表陣列的首地址,即陣列第一個元素的地址,b+1 代表陣列第二個元素的地址,…,b+n 代表陣列第 n+1 個元素的地址。所以既然 a[0]、a[1]、a[2]、…、a[M–1] 分別表示二維陣列 a[M][N] 第 0 行、第 1 行、第 2 行、…、第 M–1 行各一維陣列的首地址,那麼同樣的道理,a[0]+1 就表示元素 a[0][1] 的地址,a[0]+2 就表示元素 a[0][2] 的地址,a[1]+1 就表示元素 a[1][1] 的地址,a[1]+2 就表示元素 a[1][2] 的地址……a[i]+j 就表示 a[i][j] 的地址,即:
a[i]+j == &a[i][j]
將式一代入式二得:
&a[i][0]+j == &a[i][j]
在一維陣列中 a[i] 和 *(a+i) 等價,即:
a[i] == *(a+i)
這個關係在二維陣列中同樣適用,二維陣列 a[M][N] 就是有 M 個元素 a[0]、a[1]、…、a[M–1] 的一維陣列。將式四代入式二得(式五):
*(a+i)+j == &a[i][j]
由式二和式五可知,a[i]+j 和 *(a+i)+j 等價,都表示元素 a[i][j] 的地址。
上面幾個公式很“繞”,理清楚了也很簡單,關鍵是把式二和式五記住。
二維陣列的首地址和陣列名
下面來探討一個問題:“二維陣列 a[M][N] 的陣列名 a 表示的是誰的地址?”在一維陣列中,陣列名錶示的是陣列第一個元素的地址,那麼二維陣列呢? a 表示的是元素 a[0][0] 的地址嗎?不是!我們說過,二維陣列就是一維陣列,二維陣列 a[3][4] 就是有三個元素 a[0]、a[1]、a[2] 的一維陣列,所以陣列 a 的第一個元素不是 a[0][0],而是 a[0],所以陣列名 a 表示的不是元素 a[0][0] 的地址,而是 a[0] 的地址,即:
a == &a[0]
而 a[0] 又是 a[0][0] 的地址,即:
a[0] == &a[0][0]
所以二維陣列名 a 和元素 a[0][0] 的關係是:
a == &(&a[0][0])
即二維陣列名 a 是地址的地址,必須兩次取值才可以取出陣列中儲存的資料。對於二維陣列 a[M][N],陣列名 a 的型別為 int(*)[N],所以如果定義了一個指標變數 p:
int *p;
並希望這個指標變數指向二維陣列 a,那麼不能把 a 賦給 p,因為它們的型別不一樣。要麼把 &a[0][0] 賦給 p,要麼把 a[0] 賦給 p,要麼把 *a 賦給 p。前兩個好理解,可為什麼可以把 *a 賦給 p?因為 a==&(&a[0][0]),所以 *a==*(&(&a[0][0]))==&a[0][0]。
除此之外你也可以把指標變數 p 定義成 int(*)[N] 型,這時就可以把 a 賦給 p,而且用這種方法的人還比較多,但我不喜歡,因為我覺得這樣定義看起來很彆扭。
如果將二維陣列名 a 賦給指標變數 p,則有:
p == a
那麼此時如何用 p 指向元素 a[i][j]?答案是以“行”為單位進行訪問。陣列名 a 代表第一個元素 a[0] 的地址,則 a+1 就代表元素 a[1] 的地址,即a+1==&a[1];a+2 就代表 a[2] 的地址,即 a+2==&a[2]……a+i 就代表 a[i] 的地址,即(式七):
a+i == &a[i]
將式六代入式七得:
p+i == &a[i]
等式兩邊作“*”運算得:
*(p+i) == a[i]
等式兩邊同時加上j行:
*(p+i) + j == &a[i][j]
式八就是把二維陣列名 a 賦給指標變數 p 時,p 訪問二維陣列元素的公式。使用時,必須先把 p 定義成 int(*)[N] 型,然後才能把二維陣列名 a 賦給 p。那麼怎麼把 p 定義成 int(*)[N] 型呢?關鍵是 p 放什麼位置!形式如下:
- int (*p)[N] = a; /*其中N是二維陣列a[M][N]的列數, 是一個數字, 前面說過, 陣列長度不能定義成變數*/
下面編一個程式來用一下:
- # include <stdio.h>
- int main(void)
- {
- int a[3][4] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
- int i, j;
- int (*p)[4] = a; //記住這種定義格式
- for (i=0; i<3; ++i)
- {
- for (j=0; j<4; ++j)
- {
- printf("%-2d\x20", *(*(p+i)+j)); /*%-2d中, '-'表示左對齊, 如果不寫'-'則預設表示右對齊;2表示這個元素輸出時佔兩個空格的空間*/
- }
- printf("\n");
- }
- return 0;
- }
輸出結果是:
1 2 3 4
5 6 7 8
9 10 11 12
如果把 &a[0][0] 賦給指標變數 p 的話,那麼如何用 p 指向元素 a[i][j] 呢?在前面講過,對於記憶體而言,並不存在多維陣列,因為記憶體是一維的,記憶體裡面不分行也不分列,元素都是按順序一個一個往後排的,所以二維陣列中的每一個元素在記憶體中的地址都是連續的,寫一個程式來驗證一下:
- # include <stdio.h>
- int main(void)
- {
- int a[3][4] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
- int i, j;
- for (i=0; i<3; ++i)
- {
- for (j=0; j<4; ++j)
- {
- printf("%#X\x20", &a[i][j]);
- }
- printf("\n");
- }
- return 0;
- }
輸出結果是:
0X18FF18 0X18FF1C 0X18FF20 0X18FF24
0X18FF28 0X18FF2C 0X18FF30 0X18FF34
0X18FF38 0X18FF3C 0X18FF40 0X18FF44
我們看到地址都是連續的。所以對於陣列 a[3][4],如果把 &a[0][0] 賦給指標變數 p 的話,那麼:
- p == &a[0][0]; p + 1 == &a[0][1]; p + 2 == &a[0][2]; p + 3 == &a[0][3];
- p + 4 == &a[1][0]; p + 5 == &a[1][1]; p + 6 == &a[1][2]; p + 7 == &a[1][3];
- p + 8 == &a[2][0]; p + 9 == &a[2][1]; p + 10 == &a[2][2]; p + 10 == &a[2][3];
如果仔細觀察就會發現有如下規律:
p+i*4+j == &a[i][j]
其中 4 是二維陣列的列數。
所以對於二維陣列 a[M][N],如果將 &a[0][0] 賦給指標變數 p 的話,那麼 p 訪問二維陣列元素 a[i][j] 的公式就是:
p + i*N +j == &a[i][j]
下面把驗證式八的程式修改一下,驗證一下上式:
- # include <stdio.h>
- int main(void)
- {
- int a[3][4] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
- int i, j;
- int *p = &a[0][0]; //把a[0][0]的地址賦給指標變數p
- for (i=0; i<3; ++i)
- {
- for (j=0; j<4; ++j)
- {
- printf("%-2d\x20", *(p+i*4+j));
- }
- printf("\n");
- }
- return 0;
- }
輸出結果是:
1 2 3 4
5 6 7 8
9 10 11 12
結果是一樣的。兩種方法相比,第二種方法更容易接受,因為把 &a[0][0] 賦給指標變數 p 理解起來更容易,而且 p 定義成 int* 型從心理上或從感覺上都更容易接受。
以上轉自 http://c.biancheng.net/view/227.html
因此可以看出 利用二維陣列同樣可以達到二級指標的作用去對字串操作
二級指標做輸入_第3種記憶體模型 開闢記憶體空間
開闢記憶體空間儲存二維指標從而形成二級指標陣列
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
void main()
{
char **p2 = NULL;
int num = 5;
int i,j;
char *tmp = NULL;
p2 = (char**)malloc(sizeof(char*)*num);
for(i = 0; i < num; i++)
{
p2[i] = (char *)malloc(sizeof(char)*100);
sprintf(p2[i],"%d%d%d",i+1,i+1,i+1);
}
printf("排序之前:\n");
for(i = 0;i < num; i++)
{
printf("%s\n",p2[i]);
}
for(i = 0;i < num; i++)
{
for(j = i+1;j< num;j++)
{
if(strcmp(p2[i],p2[j])<0);
{
tmp = p2[i];
p2[i] = p2[j];
p2[j] = tmp;
}
}
}
printf("排序之後:\n");
for(i = 0;i < num; i++)
{
printf("%s\n",p2[i]);
}
//釋放記憶體
for(i = 0;i< num;i++)
{
if(p2[i] != NULL)
{
free(p2[i]);
p2[i] = NULL;
}
if(p2[i]=NULL)
{
free(p2[i]);
}
}
}
現在我們在氣泡排序的時候交換的是指標 下面我們來交換記憶體塊
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
void main()
{
char **p2 = NULL;
int num = 5;
int i,j;
char tmpbuf[100];
p2 = (char**)malloc(sizeof(char*)*num);
for(i = 0; i < num; i++)
{
p2[i] = (char *)malloc(sizeof(char)*100);
sprintf(p2[i],"%d%d%d",i+1,i+1,i+1);
}
printf("排序之前:\n");
for(i = 0;i < num; i++)
{
printf("%s\n",p2[i]);
}
for(i = 0;i < num; i++)
{
for(j = i+1;j< num;j++)
{
if(strcmp(p2[i],p2[j])<0);
{
strcpy(tmpbuf,p2[i]);
strcpy(p2[i],p2[j]);
strcpy(p2[j],tmpbuf);
}
}
}
printf("排序之後:\n");
for(i = 0;i < num; i++)
{
printf("%s\n",p2[i]);
}
//釋放記憶體
for(i = 0;i< num;i++)
{
if(p2[i] != NULL)
{
free(p2[i]);
p2[i] = NULL;
}
if(p2[i]=NULL)
{
free(p2[i]);
}
}
}
下面進行封裝
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
char **getMem(int num);
void printMyArray(char **myArray,int num);
void sortMyArray(char **myArray,int num);
void getMem_free(char **p2,int num);
void main()
{
char **p2 = NULL;
int num = 5;
int i,j;
char tmpbuf[100];
p2 = getMem(num);
printf("排序之前:\n");
printMyArray(p2,num);
sortMyArray(p2,num);
printf("排序之後:\n");
printMyArray(p2,num);
getMem_free(p2,num);
p2 = NULL;//將p2釋放
}
char **getMem(int num)
{
int i;
char **p2;
p2 = (char**)malloc(sizeof(char *)*num);
if(p2 == NULL )
{
return NULL;
}
for(i = 0;i < num;i++)
{
p2[i] = (char *)malloc(sizeof(char)*100);
sprintf(p2[i],"%d%d%d",i+1,i+1,i+1);
}
return p2;
}
void printMyArray(char **myArray,int num)
{
int i = 0;
for(i = 0;i < num;i++)
{
printf("%s\n",myArray[i]);
}
}
void sortMyArray(char **myArray,int num)
{
int i = 0, j = 0;
char *tmp = NULL;
//利用冒泡原理進行排序
for(i = 0;i < num;i++)
{
for(j = i;j < num;j++)
{
if(strcmp(myArray[i],myArray[j])>0)
{
tmp = myArray[i];
myArray[i] = myArray[j];
myArray[j] = tmp;
}
}
}
}
void getMem_free(char **p2,int num)
{
int i = 0;
for(i = 0;i< num;i++)
{
if(p2[i] != NULL)
{
free(p2[i]);
p2[i] = NULL;
}
if(p2[i]=NULL)
{
free(p2[i]);
}
}
}