标准C程序设计(六)

来源:互联网 发布:视频点播数据分析报告 编辑:程序博客网 时间:2024/04/30 02:53
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.1415926double 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);}

0 0
原创粉丝点击