天天看点

8.1指针用法初识8.1 指针用法初识

8.1 指针用法初识

  • 8.1 指针用法初识
    • 一、指针是什么
      • (一) 含义
      • (二) 通过一个简单程序来认识指针
        • 深层理解 p = &i;
        • 指针与指针变量
    • 二、指针的重要性
    • 三、指针的定义与分类
      • 概况
      • (一) 基本类型指针
        • 初识
        • 基本类型指针的常见错误
          • 读写修改未分配权限空间的值
          • 野指针
        • 基本类型指针案例——互换两个数字
          • 1. 不用函数
          • 2. 不用指针的函数能否实现数字互换呢?
          • 3. 用指针写函数互换两个变量的值
        • 附注
      • (二) 指针和数组
      • (三) 指针和函数

一、指针是什么

(一) 含义

地址是内存单元的编号

指针就是地址

(二) 通过一个简单程序来认识指针

# include <stdio.h>

int main(void)
{
    int * p; 
    // 定义了一个变量叫P,  
    //int * 是变量类型 ,p是变量名 
    //所谓 int * 数据类型,就是存放整型变量地址的数据类型,
    //其中 int 也叫基类型,指定此指针变量可以指向的变量的类型。
    //表示p只能存放 int型 变量的地址。
    //为什么要指定基类型? 因为不同类型数据所占用的内存单元大小和存放方式不一致。
    int i =3;
    p = &i; //正确
    p=i; //Error 类型不一致,P 只能存放整形变量的 “地址” ;而 i 是一个整型变量。
    p = 55; //Error 同上
    return 0;
}
           

深层理解 p = &i;

1. P 保存了i 的地址,因此P指向了i

2. P不是i , i 也不是P。

3. 更准确的说,修改P的值不影响i的值,修改 i 的值,也不影响P的值

4. P是指针变量(能存放其他变量的地址)

i 是一个普通变量(只能存放值)

5. 如果一个指针指向了某个普通变量,则 *指针变量 就完全等同于 普通变量

例子: 如果 P 是一个指针变量,并且P存放了普通变量 i 的地址,

则P指向了普通变量 i ; * P 就完全等同于普通变量i

或者说: 在所有出现 * P 的地方都可以替换成i; 在所有出现 i 的地方都可以替换成 * P

6. * P就是以P的内容(P的内容是 i 的地址)为地址的变量

8.1指针用法初识8.1 指针用法初识

指针与指针变量

  1. 指针就是地址,地址就是指针
  2. 地址就是内存单元的编号
  3. 指针变量就是存放地址(指针)的变量
  4. 指针和指针变量是两个不同的概念
  5. 但是要注意
    1. 通常我们叙述时,会把指针变量简称为指针
    2. 实际他们含义并不一样

二、指针的重要性

  1. 通过指针可以一些复杂的数据结构(树、链表、图)
  2. 快速的传递数据,减少内存耗用
  3. 是函数可以返回一个以上的值
  4. 能直接访问硬件
  5. 能方便地处理字符串
  6. 是理解面向对象语言中引用的基础

总结:指针是C语言的灵魂

三、指针的定义与分类

概况

一、地址

① 内存单元的编号

② 从0开始的非负整数

③ 范围: 和内存大小、地址总线的条数(CPU)、操作系统等因素有关。[这段写得可能有错,因为没学过组成原理!!!]

例如:

4G 内存,32位CPU

物理地址:0——(2^32-1)

二、指针

① 指针就是地址,地址就是指针

② 指针变量就是存放内存单元的编号,或者说指针变量就是存放地址的变量。

③ 指针和指针变量是两个不同的概念,但是要注意,通常我们叙述时,会把指针变量简称为指针,实际他们含义并不一样。

④ 指针的本质就是一个操作首先的非负整数。(指针不能相加,相乘,相除;只能进行想减)

(一) 基本类型指针

初识

int * P;
int i=3;
p = & i;
           

基本类型指针的常见错误

读写修改未分配权限空间的值
一、
int main (void)
{
    int *P; 
    /*
        定义P,没初始化,给P分配了一块空间,里边是垃圾值
        但是垃圾值也是有指向的,指向一处未知空间,暂且把这个记为X
    */
    int i =5;
    *P=i; 
    /*
        * P 以 P 的内容为地址的值。 
        现在P的内容为一个垃圾地址,这个地址指向X,
        *P 等同于X,但是系统没给分配修改X的权限,这句却要修改人家,必然是错的。
    */
    printf("%d\n",*P);
    return 0;
}
           
二、
int main (void)
{
    int *P;
    int *q;
    int i =5;
    P=&i;
    *P=*q;//语法上没错,但是没实际意义,输出结果,每次运行基本都不一样
    printf("%d\n",*P);
    return 0;
}
           
三、
int main (void)
{
    int *P;
    int *q;
    int i =5;
    P=&i;
    P=q; // q 是垃圾值,q 赋给P,P也变成垃圾值
    printf("%d\n",*P); //error
    /*
        q的空间是属于本程序的,所以本程序可以读写q的内容,
        但是如果q的内部是垃圾值,则本程序不能读写*q的内容
        因为此时*q所代表的内存单元的控制权限并没有分配给本程序
    */
    return 0;
}
           
野指针

见动态内存部分

基本类型指针案例——互换两个数字

1. 不用函数
int main(void)
{
    int a = 5;
    int b = 3;
    int c;
    c = a;
    a = b;
    b = c;
    printf("a=%d;b=%d\n",a,b);
    return 0;
}
           
2. 不用指针的函数能否实现数字互换呢?
void huhuan (int a ,int b)
{
    int t;
    t=a;
    a=b;
    b=t;  
    printf("函数内:a=%d;b=%d\n",a,b); 
    return;
}
int main(void)
{
    int a=5;
    int b=3;
    huhuan(a,b);
    printf("函数调用完:a=%d;b=%d\n",a,b); 
    return 0;
}
//输出
函数内:a=3;b=5
函数调用完:a=5;b=3
           

可见,这样的函数,互换操作的是形参,对真正的实参不起作用。

程序运行,从主函数main开始,当遇到huhuan这个函数时,转到函数huhuan执行,

主函数调用huhuan,将两个实参a,b具体的值传到huhuan函数的形参部分,huhuan拿到形参具体的值(5,3),此时,系统自动为形参a,b分配内存空间,现在函数形参a=5,b=3;

函数体语句是对形参a,b进行的操作。

一旦huhuan函数执行完毕,系统为形参开辟的内存空间将被自动释放,对实参不起任何作用。

3. 用指针写函数互换两个变量的值

①.错误写法

void change(int *p,int*q)
{
    int *t; // 必须是 int * 类型,否则类型不一致报错
    t=p;
    p=q;
    q=t;
    /*
        此函数交换的是p,q的内容,
        a,b 的值并没有换。
        p,q是代表a,b地址的值。
        注意 a,b的地址是固定的,不能说交换a,b的地址。
        因为a,b是静态局部变量,一旦分配好空间,就一直是在一个地方,一个地址。
    */
    return;
}
int main(void)
{
    int a=3;
    int b=5;
    change(&a,&b);
    printf("函数调用完:a=%d;b=%d\n",a,b);
    return 0;
}
//输出
change函数调用完:a=3;b=5
           
8.1指针用法初识8.1 指针用法初识

改变的是p,q里面存放的地址,并不能改变a,b的地址;任何语言都不可能改变静态变量已经分配好的地址。

② 正确写法

void ZZhuhuan(int *p,int *q)
    {
        int t;
        t=*p;
        *p=*q;
        *q=t; 
        return;
    }

    int main(void)
    {
        int a = 3;
        int b = 5;
        ZZhuhuan(&a,&b);
        printf("ZZhuhuan函数调用完:a=%d;b=%d\n",a,b);
        return 0;
    }
    //输出:
    ZZhuhuan函数调用完:a=5;b=3
           

附注

星号*的含义:

  1. 乘法
  2. 定义指针变量 int * P
  3. 指针运算符(取地址的逆运算符),放在已经定义好的指针变量的前面。如果P是一个已经定义好的指针变量,则*P表示以P的内容的为地址的变量

不用指针,函数只能返回一个值。

通过指针,可以使函数返回一个以上的值。

如何通过被调函数修改主调函数普通变量的值?

  1. 实参必须为该普通变量的地址
  2. 形参必须是指针变量
  3. 被调函数体内,通过* 形参名=…… 的方式就可以修改主调函数相关变量的值。

(二) 指针和数组

见 8.2 指针和数组

(三) 指针和函数

见 8.3 指针和函数

继续阅读