1. 程式人生 > >c語言二級指標

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語言指標引用二維陣列詳解

首先了解一下二維陣列的指標

指標變數可以指向一維陣列中的元素,當然也就可以指向二維陣列中的元素。但是在概念和使用方法上,二維陣列的指標比一維陣列的指標要複雜一些。要理解指標和二維陣列的關係首先要記住一句話:二維陣列就是一維陣列,這句話該怎麼理解呢?

假如有一個二維陣列:

  1. 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 放什麼位置!形式如下:

 
  1. int (*p)[N] = a; /*其中N是二維陣列a[M][N]的列數, 是一個數字, 前面說過, 陣列長度不能定義成變數*/

下面編一個程式來用一下:

 
  1. # include <stdio.h>
  2. int main(void)
  3. {
  4. int a[3][4] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
  5. int i, j;
  6. int (*p)[4] = a; //記住這種定義格式
  7. for (i=0; i<3; ++i)
  8. {
  9. for (j=0; j<4; ++j)
  10. {
  11. printf("%-2d\x20", *(*(p+i)+j)); /*%-2d中, '-'表示左對齊, 如果不寫'-'則預設表示右對齊;2表示這個元素輸出時佔兩個空格的空間*/
  12. }
  13. printf("\n");
  14. }
  15. return 0;
  16. }

輸出結果是:
1  2  3  4
5  6  7  8
9  10 11 12

如果把 &a[0][0] 賦給指標變數 p 的話,那麼如何用 p 指向元素 a[i][j] 呢?在前面講過,對於記憶體而言,並不存在多維陣列,因為記憶體是一維的,記憶體裡面不分行也不分列,元素都是按順序一個一個往後排的,所以二維陣列中的每一個元素在記憶體中的地址都是連續的,寫一個程式來驗證一下:

 
  1. # include <stdio.h>
  2. int main(void)
  3. {
  4. int a[3][4] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
  5. int i, j;
  6. for (i=0; i<3; ++i)
  7. {
  8. for (j=0; j<4; ++j)
  9. {
  10. printf("%#X\x20", &a[i][j]);
  11. }
  12. printf("\n");
  13. }
  14. return 0;
  15. }

輸出結果是:
0X18FF18 0X18FF1C 0X18FF20 0X18FF24
0X18FF28 0X18FF2C 0X18FF30 0X18FF34
0X18FF38 0X18FF3C 0X18FF40 0X18FF44

我們看到地址都是連續的。所以對於陣列 a[3][4],如果把 &a[0][0] 賦給指標變數 p 的話,那麼:

 
  1. p == &a[0][0]; p + 1 == &a[0][1]; p + 2 == &a[0][2]; p + 3 == &a[0][3];
  2. p + 4 == &a[1][0]; p + 5 == &a[1][1]; p + 6 == &a[1][2]; p + 7 == &a[1][3];
  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]

下面把驗證式八的程式修改一下,驗證一下上式:

 
  1. # include <stdio.h>
  2. int main(void)
  3. {
  4. int a[3][4] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
  5. int i, j;
  6. int *p = &a[0][0]; //把a[0][0]的地址賦給指標變數p
  7. for (i=0; i<3; ++i)
  8. {
  9. for (j=0; j<4; ++j)
  10. {
  11. printf("%-2d\x20", *(p+i*4+j));
  12. }
  13. printf("\n");
  14. }
  15. return 0;
  16. }

輸出結果是:
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]);
		}
	}
}