標準C程序設計(六)

11 指針
    11.1 理解指針
    在C語言中,指針是一種派生數據類型。它是從C語言的一種基本數據類型創建而來的。指針以內存地址作爲其值。由於內存地址表示在計算機內存中保存程序指令和數據的位置,因而可用指針來直接訪問和操作存儲在內存中的數據。

指針相關的基本概念:
  •  計算機的內存地址指的是指針常量(pointer constant)。我們不能修改他們,只能用來存儲數據值。
  • 我們不能直接保存地址的值,只能利用地址運算符(&),通過保存在該地址中那個的變量來或的該值。這樣獲得的值稱爲指針值(pointer value)。指針值(也就是變量的地址)在程序每次運行時都會發生變化。
  • 一旦我們有了指針值,就可以把它存儲在另一個變量中。包含指針值的變量就成爲指針變量(pointer variable)
      11.2 指針變量初始化
在C語言中,每個變量都必須聲明爲某種類型。由於指針變量包含的是存儲某種數據類型地址,因此在使用之前必須把它們聲明爲指針。指針變量的聲明如下:
   data_type  *pt_name;
上面的聲明語句告訴了編譯器關於變量pt_name的3件事:
  • 星號說明變量pt_name是一個指針變量
  • pt_name需要一個內存空間
  • pt_name是指向data_type類型的變量
      11.3 指針鏈
    普通指針變量聲明: int *p;
指向指針的指針變量聲明:int **p1;我們可以使用指向指針的指針來間接地訪問目標值
      11.4 指針的遞增與比例因子
指針可以通過如下方式遞增: p= p + 2; p = p + 1; p++;
表示是指針p指向其類型的下一個值。例如,如果p爲整形(4個字節)指針,其初始值爲2900,那麼經過++p後,p的值爲2904,而不是2901.也就是說,當指針進行遞增時,所增加的值爲該指針指向的數據類型的‘長度’。這種長度就成爲比例因子。
       11.5 指針與數組   
C語言指向多維數組的指針http://see.xidian.edu.cn/cpp/html/79.html
一維數組中訪問元素x[i]的表達式:*(x + i) 或 *(p + i)
二維數組中訪問元素x[i][j]的表達式:*(*(x + i) + j)
      11.6 指針與字符串
從第8章我們知道字符串可以看做字符數組,聲明和初始化:char str[5] = "good";本章學習指針後,我們還可以使用char類型的指針變量來創建字符串:char *str = "good";還可以通過運行時賦值語句:char *string;string = "good";
注意:string = "good";不是字符串複製,因爲變量string是一個指針,而不是字符串。(正如第8章所指出的,C語言不支持通過賦值操作來把一個字符串複製給另一個字符串)
指針的一個重要使用就是處理字符串表。可通過如下方式聲明:char name[3][25]; 我們知道,每個字符串的長度很少是等長的。這種聲明方式浪費空間,所以我們可以用指針來指向變長的字符串
   char *name[3] = {
          "New Zealand",
          "Australia",
          "India"
     };
下面語句可以用來顯示這3個名字:
 for (int i = 0; i < 3; ++i)
     {
          printf("%s\n", name[i]);
     }
要訪問第i個名字的第j個字符,可以通過:  *(name[i] + j)
注意:*p[3]和(*p)[3]這兩種表示法的區別。由於*比[]的優先級更低,*p[3]表示的是把p聲明爲具有3個指針變量的數組,而(*p)[3]則表示把p聲明爲指向含有3個元素的數組的指針。 
      11.7 指向函數的指針
與變量一樣,函數也屬於某種數據類型,在內存中需要有存儲地址。因此可以聲明一個指向函數的指針。該指針又可以作爲一個參數在另一個函數中使用。聲明:type (*fptr) ();該語句告訴編譯器,fptr爲指向函數的指針,返回type類型的值。用括號把*fptr括起來是必要的。type *gptr();表示把gptr聲明爲函數,他返回一個指向type類型的指針。
      只要把函數名賦給指針,就可以使函數指針指向某個函數。
  double mul(int x, int y);
     double (*p) ();
     p = mul;
函數調用:(*p)(x, y); 等價於 mul(x, y);
/**
功能:使用函數指針作爲函數的參數

知識點:指向函數的指針
版本:2014/06/23
*/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>

#define PI 3.1415926

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

int main(int argc, char const *argv[])
{
	printf("Table of y(x) = 2*x*x-x+1\n");
	table(y, 0.0, 2.0, 0.5);
	printf("\nTable of cos(x) \n");
	table(cos, 0.0, PI, 0.5);

	system("pause");
	return 0;
}
double table (double(*f) (double), double min, double max, double step)
{
	double i, value;
	for ( i = min; i <= max; i += step)
	{
		value = (*f)(i);
		printf("%5.2f %10.4f\n", i, value );
	}
}
double y(double x)
{
	return (2*x*x-x+1);
}
      兼容性與類型轉換
聲明爲指針的變量不只是一個指針類型的變量。它也是指向某種基本數據類型的指針。因此,總是有一種數據類型與指針關聯。我們不能把一種類型的指針賦給另一種類型的指針,儘管兩者都是以內存地址作爲其值的。這成爲指針的不兼容性
     所有指針變量存儲的都是內存地址,這些內存地址是兼容的,但它們所指向的數據類型是不兼容的。對不同類型的指針不能使用賦值運算符。但利用類型轉換運算符,就可以在不兼容的指針類型之間顯示的進行賦值操作,這與我們對基本數據類型所做的是一樣的。
     int x;
     char *p;
     p = (char *) &x;
  在這種情況下,必須確保使用指針p的所有操作都正確的進行了類型轉換。
  這裏有一個例外。這個例外就是空指針(void *)。空指針是通用指針,可以表示任何的指針類型。所有指針類型都可以賦值給空指針,而空指針無需類型轉換就可以賦給任意指針。空指針創建: void (*vp);由於空指針沒有具體類型,因而不能進行間接引用。
       11.8 指針與結構體
struct inventory
     {
          char name[30];
          int number;
          float price;
     } product[2], *ptr;
把product的第0個元素的地址賦給ptr。
       ptr = product;
指針遞增時,使得它指向數組的下一個元素,因此可通過for語句顯示product數組成員信息。
       for ( ptr = product; ptr < product + 2; ++ptr)
       {
            printf("%s %d %f\n", ptr->name,  (*ptr).number, ptr->price );
       }
  • 當使用結構體指針時,應小心各種運算符的優先級。
  • 當把結構體作爲一個參數傳遞給函數時,一般通過以指向結構體的指針作爲傳遞參數,然後使用指針來操作成員
print_invent (struct invent *item)
{
     printf("Name: %s\n", item->name);
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章