C/C++ 指針小結——指針與其它數據類型(數組、字符串、函數、結構體)的關係

1、指針與數組和字符串

一、指針與數組

當聲明數時,編譯器在連續的內存空間分配基本地址和足夠的儲存空間,以容納數組的全部元素。基本地址是數組第一個元素(索引爲0)的存儲位置。編譯器還把數組名定義爲指向第一個元素的常量指針。數組

元素的地址是經過索引和數據類型的比例因子來計算的;例如: x[3]的地址 = 基本地址 + (3 x 整型數據的比例因子)函數

如何表示元素a[i][j]的(其中:int *p; p = a;);prototype

0 1 2 3 4 5
1
2
3
4
  • p----指向第 0 行的指針;
  • p + i----指向第 i 行的指針;
  • *(p+i)----指向第 i 行的第一個元素的指針;
  • *(p+i)+j----指向第 i 行第 j 個元素的指針;
  • *((p+i)+j)----存儲在(i, j)單元(即第 i 行第 j 列)的值。

數組 a 的基本地址爲 &a[0][0],從這個地址開始,編譯器按行爲全部的元素分配連續的存儲空間。例如:指針

int a[3][4] ={
	{15,27,11,35},
	{22,19,31,17},
	{31,23,14,36}
}

數組a的存儲以下:code

|15 |27| 11| 35 |22 |19 |31 |17 |31 |23 |14 |36 | |--索引

若是把 p 聲明爲整型指針,而且初始地址爲a[0][0](),那麼:內存

a[i][j] = *(p+4*i+j);

二、指針與字符串

C語言支持另外一種建立字符串的方法,即便用char類型的指針變量。例如:字符串

char *str = "good";

上述聲明語句建立了一個文本字符串,而後將其地址保存在指針變量str中;這樣指針 str 就指向字符串 「good」 的第一個字符,以下所示:編譯器

|g(str) | o | o | d | \0 | |--it

由此,能夠用指針訪問整個字符串:

printf("%s",str);
put(str);

固然,也能夠用指針來訪問字符串中的單個字符。

三、指針數組

指針的一項重要的應用就是處理字符串表,特別是處理行的長度可變的「凹凸不平的數組」時;例如:

char *name[3] = { "New Zealand", "Australia", "India" };

上面的聲明語句只分配了28個字符,這足以保存全部的字符,具體以下:

|N| e |w | |Z |e |a |l |a| n| d| \0| |-- |A| u| s| t| r| a| l| i| a| \0| |I| n| d| i| a| \0| 下面的語句能夠用來顯示着三個名稱:

for(i = 0; i <= 2; i++)  printf("%s\n",name[i]);

要訪問第 i 個名稱的第 j 個字符,能夠這樣編寫語句:

char c = *(name[i]+j);

2、指針與函數

一、將指針做爲函數的參數

使用指針傳遞變量地址的函數調用過程稱爲引用調用(咱們已經說過,傳遞變量實際值的過程稱爲 「按值調用」)。引用調用提供了一種機制,讓被調用的函數能夠修改調用函數中存儲的值。 請注意如下代碼:

//例一
void exchange(int *a, int *b)
{
	int t;
	t=*a;
	*a=*b;
	*b=t;
}
void main()
{
	int x, y;
	x = 100;
	y = 200;
	printf("%d ,%d\\n",x,y);
	exchange(&x,&y);
	printf("%d ,%d\\n",x,y);
}
//例二
void exchange(int *a, int *b)
{
	int *t;
	t=a;
	a=b;
	b=t;
	printf("%d ,%d\n", *a, *b);
}

void main()
{
	int x, y;
	x = 100;
	y = 200;
	printf("%d ,%d\n", x, y);
	exchange(&x,&y);
	printf("%d ,%d\n", x, y);
}

代碼例二並不會使x,y的值發生互換,由於當函數指針a,b得到x,y的地址後,做爲值進行儲存,交換a,b的值並無改變其值(x,y的地址)指向的x,y的值。

二、函數返回指針

指針是C語言的一種數據類型,所以也可使用函數返回一個指向調用函數的指針。請看下面的代碼:

int  *larger(int* , int*);/*prototype*/

main()
{
	int a = 10;
	int b = 20;
	int  *p;
	p = larger(&a, &b);/*Function call*/
	printf("%d",p);
}
int *larger(int *x, int *y)
{
	if(*x > *y)
		return(x);/*address of a*/
	else
		return(y);/*address of b*/
}

注意:返回的地址必須是調用函數中變量的地址。若是返回的是指向被調用函數中局部變量的地址;將產生錯誤。

三、指向函數的指針

與變量同樣,函數也屬於某種數據類型,在內存中也須要有儲存地址。所以能夠聲明一個指向函數的指針。如同指向字符數組的指針,能夠接收任意大小的字符數組同樣,指向函數的指針能夠指向任意的函數,如此能夠減小函數的數量,使函數的功能更增強大。指向函數的指針聲明以下:

type (*fptr)();

該語句告訴編譯器,fptr爲指向函數的的指針,返回type類型的值。用括號把*fptr括起來是必要的。記住,下面的語句:

type *gptr();

表示的是把gptr聲明爲函數,它返回一個指向type類型的指針。

請仔細關注如下代碼:

#include<stdio.h>
#include<math.h>
#define PI 3.1415926

double table(double (*f)(), double, double, double);
double y(double);
double cos(double);

double table(double (*f)(), double min, double max, double step)
{
    double a, value;
    for(a = min;a <= max; a+=step){
        value = (*f)(a);
        printf("%5.2f %10.4f\n,a,value");
    }
}

double y(double x)
{
    return (2*x*x-x+1);
}

void main()
{
    printf("table of y(x) = 2*x*x-x+1\n\n");
    table(y, 0.0, 2.0, 0.5);
    printf("table of cos(x)\n\n");
    table(cos, 0.0, PI, 0.5);
}

3、指針與結構體

在前面章節中,咱們討論把結構體做爲參數傳遞給函數。咱們還看到這樣的實例,其中函數接收整個結構體的副本,並在運行後把他返回給調用函數。正如咱們前面介紹的那樣,該方法不管是在運行速度仍是在內存使用上都不是高效的。經過以指向結構體的指針做爲傳遞參數,而後使用指針來操縱結構體成員,就能夠克服該缺點。請看如下函數:

print_invent(struct *item)
{
    printf("Name: %s\n", item->name);
    printf("price:%f\n", item->price);
}

該函數能夠用下面的語句來調用:

print_invent(&product);

請關注如下兩點:

  1. 數組名錶示的是第0個元素的地址。結構體變量的數組名也是如此;
  2. 運算符「->」、「.」、「()」和「[]」的有先級最高。正確理解優先級及關聯性很是重要。
相關文章
相關標籤/搜索