第11章 指针基础

作者: 橡树人 | 来源:发表于2020-03-01 07:41 被阅读0次

英文原版:P241

因为指针非常重要,所以本书打算用3个章节来讲述指针相关内容:第11章讲述C语言的基础,第12章和第17章会介绍指针的高级应用

本章的主要内容

  • 11.1节介绍指针变量的声明。
  • 11.2节介绍指针变量的初始化,及地址操作符和间接操作符。
  • 11.3节介绍使用指针来给变量赋值。
  • 11.4节介绍指针作为函数参数。
  • 11.5节介绍指针作为函数返回值。

11.1节 指针变量

如何理解指针?
第一步:理解为什么需要指针?
第二步:指针是什么?
...
第n步:待补充

为什么需要指针?

  • 首先,不能用整数来存储地址。因为虽然可用数来表示地址,但是地址的取值范围可能不同于整数的范围。
  • 其次,可使用指针变量来存储地址。

指针是什么?

指针就是地址,指针变量就是存储地址的变量

基础知识补充:

  • 内存是以字节为单位划分的,每个字节由8个信息位组成。
  • 为了区分每个字节,对每个字节都进行编号,即每个字节都有一个唯一的地址。
  • 如果内存中有n个地址,则可认为地址就是一个在0到n-1之间的数。
  • 可执行程序一般是由代码(对应的是C源文件里的语句)和数据(对应的是C源文件里的变量)组成。
  • C程序里的每个变量需要至少一个字节的存储单元。

概念1 变量的地址

变量的地址就是存储该变量值的首个字节的地址

例1 变量的地址:首字节的地址
假设在地址2000和2001存储着变量i的值,则i的地址就是2000。
使用指针变量p来存储变量i的地址,称作p指向i。

11.1.1节 声明指针变量

格式:

// p是一个指向int类型对象的指针变量
int *p;

C语言对指针的要求:

  • 每个指针变量只能指向一种特定类型的对象(引用类型对象)。
  • 对引用类型是什么没有限制。
  • 甚至,一个指针变量可指向另一个指针。

注意:

  • 声明一个变量为指针变量的效果只是给该变量预留存储空间,并不会使其指向一个对象。
  • 在使用指针变量前必须将指针变量初始化。

例1 声明指针变量1

int *p;
int i, j, a[10], b[10], *p, *q;

例2 声明指针变量2

int *p;
double *q;
char *r;

11.2节 取地址运算符和间接寻址运算符

  • 取地址运算符:&
  • 间接寻址运算符:*

11.2.1节 取地址运算符&

格式:

&x //该表达式的值是变量x在内存中的地址

例1 使用取地址运算符将指针变量初始化

int i, *p;
...
p = &i;

例2 在声明时将指针变量初始化

int i;
int *p = &i;

例3 将指针变量的声明和初始化放在一起

int i, *p = &i;

11.2.2节 间接寻址运算符

格式:

*p //如果p是一个指针,则*p表示p当前指向的对象,该表达式的值就是该对象的值

注意:

  • 永远不要对未初始化的指针变量使用间接寻址运算符
  • 当源代码中出现没初始化的指针变量时,编译器会发出警告信息,务必要注意任何您得到的警告信息。

例1 输出变量i的值

int i, *p = &i;
...
printf("%d\n", *p);

例2 理解*p和变量i的等价关系

int i;
int *p = &i;

i = 1;
printf("%d\n", i);// 输出1
printf("%d\n", *p);// 输出1

*p = 2;
printf("%d\n", i);// 输出2
printf("%d\n", *p);// 输出2

例3 对未初始化的指针变量使用间接寻址运算符*

int *p;

printf("%d\n", *p);//可能会打印垃圾信息,导致程序崩溃或者有其他副作用

解释:
如果指针变量p还没初始化,则尝试使用p的值将导致未定义的行为。

int *p;
*p = 1;

解释:
指针变量p还没初始化,尝试给*p赋值是非常危险的。

  • 如果p包含的是有效内存地址,则*p=1;会尝试修改保存在前述有效地址里的数据。
  • 如果该赋值语句修改的内存单元属于该程序,则后果可能只是是出错;
  • 如果该赋值语句修改的内存单元属于操作系统,则很可能会导致系统崩溃;

11.3节 使用指针来赋值

C语言允许:只要左边的指针变量和右边的指针变量具有相同的类型,就可使用赋值运算符来来拷贝指针

例1 使用赋值运算符来拷贝指针

int i, j, *p, *q;

...

p = &i; //指针变量初始化

q = p; //使用指针来给指针赋值

*p = 1;

*q = 2;

例2 间接寻址运算符赋值

int i, j, *p, *q;

p = &i;
q = &j;
i = 1;

*q = *p;

11.4节 使用指针作为函数参数

例1 计算一个double数的整数部分和分数部分
函数调用

decompose(3.141519, &i, &d);

函数原型

void decompose(double x, long *int_part, double *frac_part); 

函数定义

void decompose(double x, long *int_part, double *frac_part)
{
    *int_part = (long)x;
    *frac_part = x - *int_part;
}

例2 使用指针读取整数

int i;
...
scanf("%d", &i);

或者

int i, *p;
...
p = &i;
scanf("%d", p);

注意:

如果一个函数的参数是指针类型,但调用该函数传递的却不是指针类型,则会有可怕的后果。

例3 传递非指针参数值给指针参数

decompose(3.141519, i, d);//这条语句会导致程序修改存储在未知内存地址里的数据。

程序示例:求一个数组中的最大值和最小值

源文件:maxmin.c

#include <stdio.h>

#define N 10

void max_min(int a[], int n, int *max, int *min);

int main(void)
{
    int b[N], i, big, small;

    printf("Enter %d numbers: ", N);
    for (i=0; i<N;i++) {
        scanf("%d", &b[i]);
    }

    max_min(b, N, &big, &small);

    printf("Largest: %d\n", big);
    printf("Smallest: %d\n", small);

    return 0;
}

void max_min(int a[], int n, int *max, int *min)
{
    int i;

    *max = *min = a[0];
    for(i=1; i<N; i++){
        if(a[i]>*max) {
            *max = a[i];
        }else {
            *min = a[i];
        }
    }
}

11.5节 指针作为函数返回值

  • 返回指针类型的函数参数作为返回值;
  • 返回指向外部变量的指针作为返回值;
  • 返回指向局部非静态变量的指针作为返回值;
  • 返回指向数据元素的指针作为返回值;

注意:永远不要返回指向局部变量的指针作为返回值

例1 错误示例:返回指向局部变量的指针作为返回值

int * f(void)
{
  int i;
  ...
  return &i;
}

编译器会发出警告:函数返回了局部变量的地址

例2 返回值是指向int类型的指针
函数调用

int i, j, *p;
...
p = max(&i, &j);

函数定义

int *max(int *a, int *b)
{
  if (*a > *b) {
    return a;
  }else {
    return b;
  }
}

例3 返回指向数组元素的指针作为返回值

int *find_middle(int a[], int n)
{
  return &a[n/2];
}

相关文章

  • 第11章 指针基础

    英文原版:P241 因为指针非常重要,所以本书打算用3个章节来讲述指针相关内容:第11章讲述C语言的基础,第12章...

  • go - 学习笔记

    基础 函数 指针 结构体 接口 错误 协程 通道 基础 函数 指针 结构体 接口 错误 协程 通道

  • 关于指针

    《POINTERS ON C》一书总结指针以下方面:指针基础警告总结编程提示 指针基础的总结 计算机内存中的每一个...

  • 2019-07-27

    今天看了php基础 之 指针

  • C语言基础一

    一、基本数据类型 二、指针 1、基本 2、修改值 4、交换 5、多级指针 三、数组和数组指针 1、基础 数组指针,...

  • Golang基础(三)——复杂类型

    Golang基础(三)——复杂类型 @([07] golang)[Go总结] [TOC] 指针 定义 指针变量可以...

  • protoc-生成go指针

    protoc-生成go指针 这里指的是为结构体中基础类型生成go指针,嵌套结构体默认就是指针 为什么需要生成指针?...

  • C语言多级指针

    多级指针 指针中保存着其他指针的地址,我们就称之为多级指针 多级指针的定义 在要保存的指针变量的基础上加一颗星即可...

  • Go基础——指针

    `指针的使用以下结果x还是5 不不能改变初始化值。 zero函数中 z的地址很main函数的地址是不相同的所以根本...

  • swift基础_指针

    一.swift指针类型 swift认为指针是不安全的,所有指针的类的前缀为unsafe UnsafePointer...

网友评论

    本文标题:第11章 指针基础

    本文链接:https://www.haomeiwen.com/subject/dwmtkhtx.html