==初版有很多知识点深奥,还没来得及整理完成。==

1.指针的基本概念

指针的定义:

指针是一个变量,它存储的是另一个变量的内存地址带类型的地址:不同的类型占的内存地址不一样:int一般占4个字节

指针与变量之间的关系:

指针和变量都是存储在内存中的实体。变量存储的是数据值,而指针存储的是数据值的地址。通过指针,我们可以间接地访问和操作变量的值。

指针的声明与初始化

声明**数据类型 *名字**:int *a;

初始化:名字 = 地址a = &b(其中a与b的数据类型要一致)

取地址运算符&:是一个一元运算符,写在一个数据对象的左边,可以获取一个数据对象的首地址和所需存 储空间大小

取值运算符*:

取值运算符是一个一元运算符,写在一个指针的左边,可以根据指针中存储的首地址和空间大小找到目标数据对象

1
2
3
4
5
int n = 123;
int* pn = &n;
printf("%u\n", pn); // 打印n的首地址
printf("%d\n", *pn);// 根据`pn`中的首地址与大小,找到的数据对象的值
指针类型的大小:sizeof(pn)

2.指针的基本操作

指针的运算

  1. 整形与指针类型的加减

    作用:实现指针的移动,并未改变指针的值

    +n: 指针类型+1后,将首地址后移动了 sizeof(目标数据对象) 字 节

    -n:指针类型-1后,将首地址向移动了 sizeof(目标数据对象) 字 节

    1. sizeof(目标数据对象) 被称作步长
  2. 同类型指针类型的相减

    作用:计算数组元素个数:通过指向数组首元素和尾元素的指针相减,可以快速得到数组的元素个数。

    1. 结果为两首地址的差值除以步长

3.指针与数组

1,数组名作为指针

数组名可以被当作指向其第一个元素的指针。

2,数组元素的访问

1
2
int element1 = arr[2]; // 索引访问,等同于 *(arr + 2)  
int element2 = *(ptr + 2); // 指针运算访问

3, 指针运算与数组

指针运算(如加法、减法)与数组紧密相关。例如,给指针加上一个整数n,相当于将指针向前移动n个元素(每个元素的大小由指针类型决定)。这常用于遍历数组:

1
2
3
for (int *p = arr; p < arr + 5; ++p) {  
printf("%d ", *p);
}

4, 数组传递给函数

当数组作为参数传递给函数时,实际上传递的是指向数组第一个元素的指针。因此,在函数内部,我们无法知道数组的实际大小,但我们可以访问数组的元素:

1
2
3
4
5
6
void print_array(int *arr, int size) {  
for (int i = 0; i < size; ++i) {
printf("%d ", arr[i]); // 或 printf("%d ", *(arr + i));
}
printf("\n");
}

4.多级指针指针数组

特别篇:指针数组与数组指针

  • 指向数组的指针(数组指针):通常用于表示固定大小的多维数组。例如,int (*ptr)[cols] 是一个指向有 cols 个整数的数组的指针
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    #include <stdio.h>  

    int main() {
    int arr[3][4] = {{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}};
    int (*ptr)[4] = arr; // ptr指向一个包含4个整数的数组

    // 访问数组元素
    for (int i = 0; i < 3; i++) {
    for (int j = 0; j < 4; j++) {
    printf("%d ", (*ptr)[i * 4 + j]); // 复杂,不推荐这样使用
    printf("%d ", ptr[i][j]); // 推荐使用这种方式
    }
    printf("\n");
    }

    return 0;
    }
  • 指针数组是一个数组,其元素是指针。它可以用于存储多个指向不同类型或相同类型数据的指针。例如,int *ptrs[size] 是一个有 size 个 int * 类型元素的数组。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    #include <stdio.h>  

    int main() {
    int a = 1, b = 2, c = 3;
    int *ptrs[3] = {&a, &b, &c}; // ptrs是一个指针数组,存储三个int指针

    // 访问指针指向的值
    for (int i = 0; i < 3; i++) {
    printf("%d ", *ptrs[i]);
    }

    return 0;
    }

5.指针与函数

1. 函数指针

2. 指针作为函数参数

函数可以接受指针作为参数,这使得函数能够直接访问和操作指针所指向的数据。这种能力在处理数组、字符串以及动态分配的内存时尤为重要。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <stdio.h>  

void print_array(int *arr, int size) {
for (int i = 0; i < size; ++i) {
printf("%d ", arr[i]); // 等同于 printf("%d ", *(arr + i));
}
printf("\n");
}

int main() {
int arr[] = {1, 2, 3, 4, 5};
print_array(arr, 5); // 传递数组名,它会被视为指向数组第一个元素的指针
return 0;
}

3. 指针作为函数返回值

4. 修改函数外部的变量

6.指针与字符串

字符串与字符数组

在C语言中,字符串是以字符数组的形式存储的,并且以空字符(’\0’)作为结尾标志。例如:

1
2
char str[] = "Hello, world!"; // 字符数组初始化字符串
//在这个例子中,str 是一个字符数组,它包含了14个字符(包括结尾的空字符)。

1.字符串名作为指针

在C语言中,当你声明一个字符数组并初始化为一个字符串时,字符串名(即数组名)可以作为一个指向该字符串首字符的指针来使用。例如:

1
2
3
char str[] = "Hello, world!";  
printf("%s\n", str); // 使用字符串名作为指针传递给printf函数
//在这个例子中,str 是一个指向字符串 "Hello, world!" 第一个字符 'H' 的指针。因此,printf 函数能够通过这个指针遍历整个字符串,直到遇到空字符。

2.字符指针与字符串字面量

除了字符数组之外,字符串还可以以字符串字面量的形式出现。字符串字面量是一个常量字符数组,存储在程序的只读数据段中。当你将一个字符串字面量赋值给一个字符指针时,你实际上是在让这个指针指向字符串字面量的首字符。例如:

1
2
3
char *ptr = "Hello, world!"; // 字符指针指向字符串字面量  
printf("%s\n", ptr); // 使用字符指针传递给printf函数
//在这个例子中,ptr 是一个字符指针,它指向了字符串字面量 "Hello, world!" 的首字符。注意,你不能修改通过字符指针指向的字符串字面量中的字符,因为它们是只读的。

3.修改字符串

如果你需要修改字符串的内容,你应该使用字符数组而不是字符指针指向的字符串字面量。因为字符串字面量是只读的,尝试修改它们会导致未定义的行为(通常是程序崩溃)。

1
2
3
4
5
6
7
8
char str[] = "Hello, world!"; // 字符数组,可以修改  
str[0] = 'h'; // 修改成功,输出将是 "hello, world!"

char *ptr = "Hello, world!"; // 字符指针指向字符串字面量,不能修改
ptr[0] = 'h'; // 尝试修改,但会导致未定义的行为(通常是程序崩溃)



7.**动态内存分配与指向它的指针变量(不太会)

8.指针的注意事项

1.空指针(NULL指针)

  • 在声明指针变量后,如果没有初始化,它将包含一个不确定的值(垃圾值),这可能导致未定义的行为。因此,通常建议将指针初始化为NULL,表示它不指向任何有效的内存位置。
  • 在使用指针之前,始终检查它是否为NULL,以避免尝试访问无效的内存地址。

2.指针运算

  • 指针运算(如递增、递减、加法、减法)在C语言中很常见,但必须谨慎使用。指针运算的结果必须指向有效的内存区域,否则可能导致未定义的行为。

3.指针类型

指针的类型决定了它所指向的内存的大小和解释方式。将一种类型的指针强制转换为另一种类型(类型转换或强制类型转换)可能会导致不可预测的结果,


Author: Jie
Reprint policy: All articles in this blog are used except for special statements CC BY 4.0 reprint polocy. If reproduced, please indicate source Jie !
 Previous
2024-05-12 Jie
Next 
2024-05-05 Jie
  TOC