C语言入门笔记(7)--指针

物协 C Gateway Course 7 指针

一、指针的概念

1.1 变量和地址

在C语言中,变量在内存中存储,每个变量有一个地址,可以类比为酒店中的房间号。例如:

void main() {
    int x = 10, y = 20;
}

这段代码中,变量xy分别被赋值为10和20,可以将内存看作是酒店,每个变量就是一个房间。变量的地址可以暂时用pxpy表示。

1.2 指针变量和指针的类型

指针变量存储着地址信息,就像一张房卡存储着房间号。指针变量的类型需要与所指向的变量类型匹配,类似于只能用特定类型的房卡打开相应类型的房间。

int *px;    // int类型的指针变量
float *pf;  // float类型的指针变量
char *pc;   // char类型的指针变量

二、变量的指针与指针变量

2.1 指针变量的定义及使用

2.1.1 指针变量的定义
  • 指针变量的定义形式如:数据类型 *指针名;
// 分别定义了 int、float、char 类型的指针变量
int *x;
float *f;
char *ch;
  • 在定义指针变量时,必须确定指针的类型,就像普通变量需要确定数据类型一样。
2.1.2 指针变量的使用
  • 取地址运算符 & 用于取操作对象的地址。
int a;
int *pa; // 声明一个指针变量
pa = &a; // 通过取地址符&,获取 a 的地址,赋值给指针变量
  • 指针运算符 *(间接寻址符): 通过操作对象的地址,获取存储的内容。
// 通过间接寻址符,获取指针指向的内容
printf("%d", *pa);
2.1.3 “&” 和 “*” 的结合方向
  • &* 都是右结合的。
int x = 10;
int *px = &x;

// *&x 的含义是,先获取变量 x 的地址,再获取地址中的内容
// 因为 "&" 和 "*" 互为逆运算,所以 x = *&x

2.2 指针变量的初始化

2.2.1 指针变量与变量的关系
  • 指针变量与变量的关系可以类比为房卡和房间的关系。
// 利用取地址获取 x 的地址,在指针变量 px 定义时,赋值给 px
int x;
int *px = &x;

// 定义指针变量,分别赋值“NULL”和“0”
int *p1 = NULL, *p2 = 0;
2.2.2 指针运算
2.2.2.1 赋值运算
  • 指针变量可以相互赋值,也可以赋值某个变量的地址,或者赋值一个具体的地址。
int *px, *py, *pz, x = 10;
px = &x;        // 赋予某个变量的地址
py = px;        // 相互赋值
pz = 4000;      // 赋值具体的地址
2.2.2.2 指针与整数的加减运算
  • 指针变量的自增自减运算。
int x, y, z;

int *px = &x;   // 定义一个指针,指向 x
printf("x = %d", *px);  // 获取 x 的内容

printf("y = %d", *(px + 1));  // px + 1,指向 x 的下一个单元,即 y
printf("z = %d", *(px + 2));  // px + 2,指向 x 的下两个单元,即 z
2.2.2.3 关系运算
  • 关系运算符用于比较指针的大小或与常量比较。
int num[2] = {1, 3};
int *px = &num[0], *py = &num[1];
int *pz = &num[0];
int *pn;

if (py > px) {
    printf("py 指向的存储地址大于 px 所指向的存储地址");
}

if (pz == px) {
    printf("px 和 pz 指向同一个地址");
}

if (pn == NULL || pn == 0) {
    printf("pn 是一个空指针");
}

三、指针与数组

3.1指向数组的指针

  • 数组名即为数组的首地址,通过指针可以访问数组的元素。
int nums[5] = {4, 5, 3, 2, 7};
int *p = nums;  // 或者 p = &nums[0];

printf("nums[0] = %d\n", *p);          // 输出结果为 nums[0] = 4
printf("nums[1] = %d\n", *(p + 1));    // 输出结果为 nums[1] = 5

for (int i = 0; i < 5; i++) {
    printf("nums[%d] = %d", i, *(p + i));
}

3.2 字符指针与字符数组

  • 字符指针和字符数组用于存储字符串。
char *sentence = "Do not go gentle into that good night!";

printf("%s", sentence);      // 输出整个字符串
printf("%c", sentence[0]);    // 获取字符串的第一个字符
printf("%d", strlen(sentence));  // 获取字符串的长度
  • 利用字符指针将字符数组内容复制到字符数组。
char sentence[] = "Do not go gentle into that good night!", word[100];
char *ch = word;

for (int i = 0; sentence[i] != '\0'; i++) {
    *(ch + i) = sentence[i];
}

*(ch + i) = '\0';

printf("ch = %s, word = %s", ch, word);

3.3 多级指针及指针数组

3.3.1 多级指针
  • 多级指针是指向指针的指针,形成多级关系。
int *pi, i = 10;
int **ppi

;

pi = &i;
ppi = &pi;

printf("i = %d", **ppi);  // 获取 i 的内容
3.3.2 指针数组
  • 指针数组是由指针变量组成的数组,可以操作多个数组。
int nums[5] = {2, 3, 4, 5, 2};
int *p[5];
int **pp;

for (int i = 0; i < 5; i++) {
    p[i] = &nums[i];
}

pp = p;

for (int i = 0; i < 5; i++) {
    printf("%d", **pp);
    pp++;
}

3.4 指针与多维数组

3.4.1 多维数组的地址
  • 多维数组可以看成一维数组的数组,不同维度的关系需要逐级分析。
int nums[2][2] = {
    {1, 2},
    {2, 3}
};

printf("数组首地址为 %d", nums);  // 数组首地址
printf("第二个维度的首地址为 %d", nums[0]);  // 第二个维度的首地址
printf("第三个维度的首地址为 %d", nums[0][0]);  // 第三个维度的首地址
3.4.2 多维数组的指针
  • 利用指针数组可以操作多维数组。
int nums[2][2] = {
    {1, 2},
    {2, 3}
};

int *p[2] = {nums[0], nums[1]};

printf("nums[0][0] = %d", **p);
printf("nums[1][0] = %d", **(p + 1));
printf("nums[0][1] = %d", *(*p + 1));

3.5总结与注意事项

  • 指针变量是一种特殊的变量,存储的是地址而非具体的值。
  • 指针和数组有密切关系,通过指针可以操作数组的元素。
  • 多级指针和指针数组可以用于处理复杂的数据结构和多维数组。

注意:指针变量在使用前必须初始化,未初始化的指针可能导致未知的错误。

四、指针与函数

在C语言中,函数参数可以是intcharfloat等基本数据类型,但通过指针,我们可以实现更灵活的函数参数传递。本节将学习指针作为函数参数、函数返回值以及指向函数的指针。

4.1 函数参数为指针

考虑一个简单的交换两个变量值的函数:

void swap(int *x, int *y);

int main() {
    int x = 20, y = 10;
    swap(&x, &y);
    printf("x = %d, y = %d", x ,y);
    return 0;
}

void swap(int *x, int *y) {
    int t;
    t = *x;
    *x = *y;
    *y = t;
}

在这个例子中,swap函数的参数是指针,通过传递变量的地址,实现了变量值的交换。

4.2 函数的返回值为指针

函数可以返回指针,从而实现返回值为数组的效果:

int s;

int *sum(int x, int y) {
    s = x + y;
    return &s;
}

int main() {
    int *result = sum(10, 9);
    printf("10 + 9 + %d", *result);
    return 0;
}

这里,sum函数返回一个指向s的指针,实现了返回值为数组的目的。

4.3 指向函数的指针

虽然C语言中函数不能嵌套定义,也不能将函数作为参数传递,但是函数有一个特性,即函数名为该函数的入口地址。我们可以定义一个指针指向该地址,将指针作为参数传递。

#include <string.h>

void check(char *x, char *y, int (*p)());

int main() {
    // string.h库中的函数,使用之前需要声明该函数。字符串比较函数
    int strcmp();
    char x[] = "Zack";
    char y[] = "Rudy";
    
    // 定义一个函数指针
    int (*p)() = strcmp;

    check(x, y, p);

    return 0;
}

void check(char *x, char *y, int (*p)()) {
    if (!(*p)(x, y)) {
        printf("相等");
    } else {
        printf("不相等");
    }
}

在这个例子中,p是一个函数指针,指向strcmp函数。通过check函数将函数指针作为参数传递,实现了对字符串的比较。

函数指针的定义形式为数据类型 (*函数指针名)();,在进行“*”操作时,可以理解为执行该函数。需要注意,函数指针不同于数据指针,不能进行+整数操作。

  • 15
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值