C语言集训-邹振鹏-第五次作业

120 阅读4分钟

指针

指针的计算机底层逻辑

当一个程序被启动的时候,操作系统将会做下面几件事情:

  1. 把程序的内容(代码段、数据段)从硬盘复制到内存中;
  2. 创建一个数据结构PCB(进程控制块),来描述这个程序的各种信息(例如:使用的资源,打开的文件描述符...);
  3. 在代码段中定位到入口函数的地址,让CPU从这个地址开始执行。 操作系统通过地址来管理内存。

在一般情况下,我们通过变量名对变量进行使用,不过变量名只是一个抽象的概念,在编辑时,编辑器会将其转换为该变量在内存中的地址。
而通过指针,即可直接访问地址。

  1. 指针变量首先是一个变量,所以它拥有变量的所有属性:类型和值。它的类型就是指针,它的值是其他变量的地址。 既然是一个变量,那么在内存中就需要为这个变量分配一个存储空间。在这个存储空间中,存放着其他变量的地址。
  2. 指针变量所指向的数据类型,这是在定义指针变量的时候就确定的。例如:int *p; 意味着指针指向的是一个int型的数据。

指针的简单用法

数组指针

一维数组与指针
int *p,a[10];   //定义一个指向整型的指针和一个一维数组

一维数组中,数组名a相当于数组首元素 a[0] 的地址,即 a 等价于 &a[0]。
数组元素的访问方式:

  • 直接访问:数组名[下标],如a[3].
  • 间接访问:*(数组名 + i),表示a[i]
  • 间接访问:(指针变量)当将数组的地址赋给指针变量P时,如 p = a;
    将数组a的首地址赋给p之后,可以通过p的加减遍历数组元素,
    (p+i) = a[i];
二维数组与指针

用如下的程序判断指针如何指向二维数组


#include<stdio.h>
#define M 3
#define N 4
int main (void)
{
    int *p,a[M][N]={{1,2,3,4},{5,6,7,8},{9,10,11,12}};
    p=&a[0][0];
    printf("The address of different rows:\n");
    printf ("a + 0 = %p\n",a);
    printf ("a + 1 = %p\n",a + 1);
    printf ("a + 2 = %p\n\n",a + 2);

    printf("The same address:\n");
    printf ("a[2] + 1 = %p\n",a[2] + 1);
    printf ("*(a+2) +1 = %p\n",*(a + 2)+1);
    printf ("&a[2][1] = %p\n\n",&a[2][1]);

    printf("The same element:\n");
    printf ("*(a[1] + 3) = %d\n",*(a[1] + 3));
    printf ("*(*(a + 1) + 3) = %d\n",*(*(a + 1)+3));
    printf ("a[1][3] = %d\n", a[1][3]);
    return 0;
}

image.png

image.png

从上面的程序我们可以看出,二维数组的存储结构为顺序存储,

  • i行的首元素地址:a[1]+0<-->* (a + i) +0 <--> &a[i][0]
  • i行的1列元素地址:a[1]+1<-->* (a + i) +1 <--> &a[i][1]
  • i行的2列元素地址:a[1]+2<-->* (a + i) +2 <--> &a[i][2]
  • i行的j列元素地址:a[1]+j<-->* (a + i) +j <--> &a[i][j]
    通过访问符‘*’, 二维数组a[i][j]有以下几种方法
*(a[i] + j) <--> *(*(a + i) + j) <-->*&a[i][j]<-->a[i][j]

注意:二维数组中,虽然i行首地址和首元素的地址数值上相同,但其的性质不相同,首地址加一变为下一行的首地址,而首元素的地址加一变为下一个元素的地址

指针数组

定义的一般形式

int *a[n];

由于[]的优先级高于*,a[n]表示a是一个数组,类型为int *


#include <stdio.h>
int main(){
    int a = 16, b = 932, c = 100;//定义一个指针数组
    
    int *arr[3] = {&a, &b, &c};//也可以不指定长度,直接写作 int *arr[]
    //定义一个指向指针数组的指针
    int **parr = arr;
    printf("%d, %d, %d\n", *arr[0], *arr[1], *arr[2]);
    printf("%d, %d, %d\n", **(parr+0), **(parr+1), **(parr+2));

    return 0;
}

指针和字符串

一般形式:

char *str = "I love China!"

表示将字符串“I love China!”的地址给str
可以用 &str输出

其他用法

指向结构体
指向函数
·····

指针的简单操作

可以在子函数中改变主函数中的值
如上次的2000题

#include <stdio.h>
void swap(char*p1,char*p2);
int main(void)
{
    char c1,c2,c3,c;
    char*p1,*p2,*p3;

    scanf("%c%c%c",&c1,&c2,&c3);
    swap(&c1,&c2);
    swap(&c1,&c3);
    swap(&c2,&c3);
    printf("%c %c %c",c1,c2,c3);
}
void swap(char*p1,char*p2)
{
    char c;
    if(*p1>*p2){
        c = *p2;
        *p2 = *p1;
        *p1 = c;
    }
}

我在swap函数中用指针改变其指向的值(主函数中),从而达到判断大小,交换值的目的

指针指向类型和指针类型的区别

指针的类型是指针自身的类型,而指针所指向的类型是指针指向的数据(内存)的类型。

课后习题

10.12.1

#include <stdio.h>
int main(void)
{
    int ref[] = { 8,4,0,2};
    int *ptr;
    int index;

    for(index = 0,ptr = ref;index < 4;index++,ptr++)
        printf("%d %d\n",ref[index],*ptr);
    
    return 0;
}

运行结果

image.png

10.12.2

ref 有4个元素

10.12.3

ref地址是ref[0]的地址,ref + 1表示 ref[1]的地址,ref为数组名,不能自增,无指向

10.12.4

a.

  • ptr 值是12
  • (ptr + 2)的值为16 b.
  • ptr 值是12
  • (ptr + 2)的值为1

10.12.5

a.
**ptr的值为12
**(ptr+1)为16
b.
**ptr的值为12
**(ptr+1)为14