第五节 指针

1. 指针和指针变量的基本概念

  • 指针的定义:指针是变量的地址,指向某个数据类型的值。声明指针时,需要指定指针指向的数据类型。

  • 语法

    数据类型 *指针名;

    int *p; // 定义指针变量

    p = &var_runoob;

  • 指针变量:就是存储这个地址的变量
  • 语法

            数据类型 *指针变量名 [初始地址值];

  1.1 const修饰的指针变量

 从左往右看,跳过类型,看修饰那个字符:

*  ,值不能修改   //const int *p=&a;

指针变量  ,指向不能改  //int * const p1=&a 

2. 指针的基本操作  

  • 取地址运算符 &
    使用 & 可以获取变量的地址。

    int a = 10; int *p = &a; // p 指向 a 的地址

  • 解引用运算符 *
    使用 * 可以访问指针指向地址的值。

    int b = *p; // b 被赋值为 a 的值,即 10

 2.1 间接修改变量的值

//通过指针间接修改变量的值
int num=10;
int *p=#
*p=20;
printf("%d\n",*p);

2.2 指针常用运算

格式: 指针+(-)整数

指针与整数的加减运算,表示指针所指向的内存地址和移动。指针移动的单位,与指针指向的数据类型有关。数据类型占据多少个字节,每单位就移动多少个字节。

2.3 指针步长

指针指向的地址相对于当前地址的偏移量。步长取决于所指向的数据类型。

注!!!指针p+ 不是地址加一,而是指针指向的下一个数据遍历数组

  只有连续的同类型区域,指针加减才有意义

 2.4 指针遍历

// 一维数组的遍历  
// 1、利用sizeof遍历  
for (int i = 0; i < sizeof(list1) / sizeof(list1[0]); i++) {  
    printf("%d===", list1[i]);  
}  
printf("\n");

// 2、利用指针进行遍历  
int* p = list1;  
for (int i = 0; i < 4; i++) {  
    printf("%d=====", *(p + i));  
}  
//二维数组遍历
int list[3][3] = { {1,4,7},{2,5,8},{3,6,9} };
//索引遍历
for (int i = 0;i < 3;i++) {
	for (int j = 0;j < 3;j++) {
		printf("%d    ", list[i][j]);
	}
	printf("\n");
}
// 利用指针遍历二维数组
int* p = &list[i][j];
for (int i = 0;i < 9;i++) {
	printf("%d    ", *(p + i));
	if ((i + 1) % 3 == 0) {
		printf("\n");
	}
}

 2.5 指针大小

 sizeof()测得是指针变量指向存储地址的大小

     32位平台,指针都是32位(4字节)

     64位平台,指针都是64位(8字节)

2.6 指针的类型

  • 基本类型指针:如 int*char*float* 等
  • 指向指针的指针:指向另一指针,例如 int** pp;
  • 函数指针:指向函数的指针,能够通过指针调用函数

 3. 二级指针(多级指针)

二级指针:就是指向一个一级指针变量地址的指针。

多级指针:就是指针的指针。

格式:数据类型** 指针变量

 int a=10;
int *p=&a;
int* *pp=&p;

 重!!! 指针本身也是个变量,需要内存取存储,指针也有自己的地址

指针内存存储的是他所指向变量的地址

//动态创建二维数组
#include <stdio.h>  
#include <stdlib.h>  

int main() {  
    int rows = 3; // 行数  
    int cols = 4; // 列数  
    int **array; // 二级指针  

    // 动态分配内存  
    array = (int **)malloc(rows * sizeof(int *));  
    for (int i = 0; i < rows; i++) {  
        array[i] = (int *)malloc(cols * sizeof(int));  
    }  

    // 初始化数组  
    for (int i = 0; i < rows; i++) {  
        for (int j = 0; j < cols; j++) {  
            array[i][j] = i * cols + j; // 填充一些值  
        }  
    }  

    // 打印数组  
    printf("二维数组的内容:\n");  
    for (int i = 0; i < rows; i++) {  
        for (int j = 0; j < cols; j++) {  
            printf("%d ", array[i][j]);  
        }  
        printf("\n");  
    }  

    // 释放内存  
    for (int i = 0; i < rows; i++) {  
        free(array[i]); // 先释放每一行  
    }  
    free(array); // 再释放行指针  

    return 0;  
}

4. 指针与数组

  • 数组名在大多数情况下被视为指向数组首元素的指针,可以使用指针遍历数组。

 4.1 一维数组和指针

#include <stdio.h>  

int main() {  
    int arr[] = {10, 20, 30, 40, 50};  
    int *ptr = arr; // 指针指向数组的首元素  

    // 输出数组元素和指针指向的元素  
    for (int i = 0; i < 5; i++) {  
        printf("arr[%d] = %d\n", i, arr[i]);  
        printf("ptr[%d] = %d\n", i, *(ptr + i));  
    }  

    return 0;  
}

 4.2 指针访问数组元素

int a[10]={1,2,3,4,5};

int *p=&a[0];

a[0]; 表示a[0]的值

 地址;&s[0],p,a

 值;a[0],*p,*a

a[i]; 表示a[i]的值

地址;&a[i],p+i,a+i

值; a[i],*(p+i),*(a+i)

重!!*和[ ]效果一样,都是操作指针所指向的内存

4.3 指针带下标使用

 获取数组元素值得三种表示形式:

(1)a[i][j]  下标法

 (2)*(a[i]+j)  一维数组名

(3)*(*(a+i)+j)  二维数组名

5. 示例代码

示例 1:基本指针操作
#include <stdio.h>

int main() {

int a = 5;

int *p = &a; // p 保存 a 的地址 printf("a 的值: %d\n", a);

printf("p 指向的值: %d\n", *p); // 解引用 p,得到 a 的值 *p = 10; // 通过指针修改 a 的值

printf("修改后 a 的值: %d\n", a);

return 0;

}
 字符数组和字符指针变量

字符数组由若干个元素组成,每个元素放一个字符。 数组名是个常量,不可重新赋值

字符指针变量中存放的是地址,绝不是将字符串放入字符指针变量。指针变量是个变量,可以多次赋值。

字符指针可直接赋值为字符串,保存实际上是字符串得首地址是个常量。这时不能修改

 字符串数组的表示

 二位字符数组:

#include <stdio.h>  

int main() {  
    // 定义一个3行5列的二维字符数组  
    char array[3][5] = {  
        {'H', 'e', 'l', 'l', 'o'},  
        {'W', 'o', 'r', 'l', 'd'},  
        {'C', '!', '!', '!', '!'}  
    };  

    // 打印二维字符数组内容  
    for (int i = 0; i < 3; i++) {  
        for (int j = 0; j < 5; j++) {  
            printf("%c ", array[i][j]);  
        }  
        printf("\n");  
    }  

    return 0;  
}

 字符指针数组:

#include <stdio.h>  

int main() {  
    // 定义一个字符指针数组,存储三条字符串  
    char *array[] = {  
        "Hello",  
        "World",  
        "C Programming"  
    };  

    // 获取数组的大小  
    int size = sizeof(array) / sizeof(array[0]);  

    // 打印字符指针数组内容  
    for (int i = 0; i < size; i++) {  
        printf("%s\n", array[i]);  
    }  

    return 0;  
}
示例 2:
数组指针

数组指针:能够指向数组的指针

#include <stdio.h>

int main() {

int array[] = {1, 2, 3, 4, 5};

int *p = array; // p 指向数组的首元素

for (int i = 0; i < 5; i++) {

printf("array[%d] = %d\n", i, *(p + i)); // 使用指针访问数组

}

return 0;

}
 指针数组

是数组,是存放指针的数组

格式;数据类型 *指针数组名[大小];  //int *arr[5];

#include <stdio.h>  

int main() {  
    // 定义一个指针数组,数组中的元素是指向字符串的指针  
    const char *fruits[] = {  
        "Apple",  
        "Banana",  
        "Cherry",  
        "Date",  
        "Elderberry"  
    };  

    // 计算数组的大小  
    int size = sizeof(fruits) / sizeof(fruits[0]);  

    // 遍历指针数组并打印每个字符串  
    for (int i = 0; i < size; i++) {  
        printf("%s\n", fruits[i]);  
    }  

    return 0;  
}
示例 3:指向指针的指针
#include <stdio.h>

int main() {

int a = 10; int *p = &a; // p 是指向 a 的指针

int **pp = &p; // pp 是指向指针 p 的指针

printf("通过 pp 访问 a: %d\n", **pp); // 二级解引用 **pp = 20;

// 通过指向指针的指针修改 a 的值

printf("修改后 a 的值: %d\n", a);

return 0;

}
示例 4:函数指针
#include <stdio.h>

void greet() {

printf("Hello, World!\n");

}

int main() {

void (*func_ptr)() = greet; // 定义函数指针指向函数 greet func_ptr(); // 调用函数 return 0;

}
示例 5:通过指针修改函数参数
#include <stdio.h>

void modify(int *p) {

*p = 30; // 修改指针指向的值

}

int main() {

int a = 20;

printf("修改前 a 的值: %d\n", a);

modify(&a); // 传递 a 的地址

printf("修改后 a 的值: %d\n", a);

return 0;

}

6. 动态内存分配

使用指针可以动态地分配内存(使用 malloccallocrealloc),并在使用完后释放内存(使用 free)。

示例 6:动态内存分配
#include <stdio.h>

#include <stdlib.h>

int main() {

nt *arr; int n = 5; // 动态分配内存

arr = (int *)malloc(n * sizeof(int));

if (arr == NULL) {

printf("内存分配失败\n");

return 1;

}

// 初始化数组 for (int i = 0; i < n; i++) {

arr[i] = i + 1; // 数组元素初始化为 1 到 5

}

// 打印数组元素 for (int i = 0; i < n; i++) {

printf("arr[%d] = %d\n", i, arr[i]);

}

// 释放分配的内存

free(arr);

return 0;

}

结论

指针是 C 语言的核心组成部分,理解指针的操作对于有效使用 C 语言至关重要。指针能够提高程序的灵活性和效率,但也需要小心管理,以避免内存泄漏和非法内存访问等问题。希望以上内容能帮助你更深入地理解 C 语言中的指针。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值