[C.C++] C语言指针使用

519 0
Honkers 2025-3-28 03:52:42 来自手机 | 显示全部楼层 |阅读模式

一、C语言指针介绍

1.1、基本概念

在C语言中,指针是一个变量,其值为另一个变量的地址,即内存位置的直接地址。当一个变量被声明为指针类型时,编译器将为该变量分配一个可以存储内存地址的空间。指针在C语言编程中非常重要,它们用于动态内存分配、函数参数传递、数据结构(如链表和树)等。

1.2、指针介绍

(1)指针是一个变量,它存储的是另一个变量的内存地址,而不是直接存储数据值。

(2)指针是有类型的,指针的类型决定了“指针的+-整数的步长”,以及解引用时候的权限。

(3)指针通过取地址运算符(&)来获取变量的地址,而箭头运算符(->)用于访问指向结构体或类的指针成员,它不能直接用于获取变量的地址。

(4)指针之间存在运算,多级指针其实就是指向指针的指针。

二、C语言指针基础

 2.1、指针的定义

以下是常见的指针定义,区分其含义以便更好的理解指针(优先级问题)。

  1. int p; //一个普通的整型变量
  2. int *p; //P先与*结合,说明P是一个指针,然后再与int结合,说明指针指向型为int型.所以P是一个返回整型数据的指针
  3. int **p; //(多级指针略)P先与*结合,再与*结合,然后再与int结合,说明该指针所指向的元素是整型数据
  4. int p[4]; //P先与[]结合,然后与int 结合,说明p是一个整型数组。
  5. int *p[4]; //P先与[]结合,因为其优先级比*高,然后再与*结合,然后再与int 结合,所以P是一个由返回整型数据的指针所组成的数组
  6. int (*p)[4]; //P先与*结合,然后再与[]结合,然后再与int 结合,所以P是一个指向由整型数据组成的数组的指针
  7. int (*p)(int); //P先与指针结合,然后与()结合,然后再与()里的int结合,所以P是一个指向有一个整型参数且返回类型为整型的函数的指针
复制代码

 注意:每定义一个指针,都应该思考这个指针的类型是什么?指针指向的类型是什么?该指针的值是什么?(指向了哪里?)

2.2、指针的基本运算

 (1)地址指向运算

  1. #include <stdio.h>
  2. int main() {
  3. int numb=1;
  4. int *p;
  5. p=&numb;//加地址符,指向numb
  6. (*p)++;
  7. printf("%d %d\n",numb,*p);
  8. int numb1[5]={11,22,33,44,55};
  9. int *p1;
  10. p1=numb1;//数组不需要加地址符
  11. for(int i=0;i<5;i++){//p1的指向会变
  12. printf("%d ",*p1);
  13. p1++;
  14. }
  15. p1=p1-5;//让p1重新指向开始的位置
  16. for(int i = 0; i < 5; i++) {//p1的指向不会变
  17. printf("%d ", *(p1 + i));
  18. }
  19. char a[20]="You are a girl";
  20. int *ptr=(int *)a;
  21. ptr+=5;
  22. printf("\n%d",*ptr);//随机输出,指针类型不能用于强制转化
  23. return 0;
  24. }
复制代码

(2)多级指针运算

  1. #include <stdio.h>
  2. int main() {
  3. int a = 10;
  4. int *p1 = &a;
  5. int **p2 = &p1;
  6. int ***p3=&p2;
  7. printf("%d\n", a);
  8. printf("%d\n", *p1);//p1指向a
  9. printf("%d\n", **p2);//p2指向p1,则三者值都一样
  10. printf("%d\n", ***p3);//p3指向p2,四者值都一样
  11. int b=20;
  12. p1=&b;//p1指向b
  13. printf("%d %d %d\n",*p1,**p2,***p3);//p1指向改变,对应p2,p3都变
  14. b=30;
  15. printf("%d %d %d\n",*p1,**p2,***p3);//b数值改变,p1,p2,p3都变
  16. int *k=&a;
  17. p2=&k;
  18. printf("%d %d\n",*p1,***p3); //p2指向改变,p3变,p1不变
  19. return 0;
  20. }
复制代码

(3)指针间运算

  1. #include <stdio.h>
  2. int main() {
  3. int arr[] = {10, 20, 30, 40, 50};
  4. int *p1 = arr; // 指向数组的第一个元素
  5. int *p2 = arr + 2; // 指向数组的第三个元素
  6. // 指针加法
  7. printf("p1 + 1 = %p\n", p1 + 1); // 移动到下一个元素
  8. // 指针减法
  9. printf("p2 - 1 = %p\n", p2 - 1); // 移动到前一个元素
  10. // 指针差值
  11. printf("p2 - p1 = %ld\n", p2 - p1); // 计算两个指针之间的元素个数
  12. // 指针自增
  13. p1++;
  14. printf("p1++ = %p\n", p1); // 自增后指向下一个元素
  15. // 指针自减
  16. p2--;
  17. printf("p2-- = %p\n", p2); // 自减后指向前一个元素
  18. // 指针比较
  19. if (p1 == p2) {
  20. printf("p1 == p2\n");
  21. } else {
  22. printf("p1 != p2\n");
  23. }
  24. // 指针间接引用
  25. printf("*p1 = %d\n", *p1); // 访问指针p1所指向的值
  26. return 0;
  27. }
复制代码

2.3、const修饰指针

(1) 指向常量的指针

  1. const int *ptr;
复制代码

其中ptr是一个指向const int的指针。你不能通过ptr修改它所指向的值,但可以改变ptr本身,使其指向其他地址。

  1. const int value = 10;
  2. const int *ptr = &value;
  3. // *ptr = 20; // 错误:不能通过ptr修改value的值
  4. int anotherValue = 30;
  5. ptr = &anotherValue; // 可以改变ptr指向的地址
复制代码

(2)常量指针 

  1. int *const ptr;
复制代码

其中 ptr是一个常量指针。你可以通过ptr修改它所指向的值,但不能改变ptr本身,使其指向其他地址。

  1. int value = 10;
  2. int *const ptr = &value;
  3. int anotherValue=30;
  4. *ptr = 20; // 可以通过ptr修改value的值
  5. // ptr = &anotherValue; // 错误:不能改变ptr指向的地址
复制代码

(3)指向常量的常量指针

  1. const int *const ptr;
复制代码

其中 ptr是一个指向const int的常量指针。你既不能通过ptr修改它所指向的值,也不能改变ptr本身,使其指向其他地址。

  1. const int value = 10;
  2. int anotherValue=30;
  3. const int *const ptr = &value;
  4. // *ptr = 20; // 错误:不能通过ptr修改value的值
  5. // ptr = &anotherValue; // 错误:不能改变ptr指向的地址
复制代码

三、C语言指针的应用

3.1、指针内存分配问题

在C语言中,指针的内存分配主要有两种方式:静态分配动态分配

(1)静态分配

静态分配是在编译时完成的,内存空间在程序运行期间是固定的。通常用于局部变量和全局变量。例如:

  1. int value = 10; // 静态分配
  2. int *ptr = &value; // 指针指向静态分配的内存
复制代码

(2)动态分配 

动态分配是在程序运行时完成的,使用标准库函数malloc、calloc或realloc来分配内存,使用free来释放内存。

  1. int *ptr = (int *)malloc(sizeof(int)); // 动态分配
  2. if (ptr != NULL) {
  3. *ptr = 10; // 使用动态分配的内存
  4. }
  5. free(ptr); // 释放动态分配的内存
复制代码

动态内存分配函数

malloc(size_t size):分配指定大小的内存块,返回指向该内存块的指针。

calloc(size_t num, size_t size):分配指定数量的内存块,并初始化为零。

realloc(void *ptr, size_t size):调整之前分配的内存块的大小。

free(void *ptr):释放之前分配的内存块。 

扩展:计算本地电脑可给指针最多分配多少内存,代码如下:

  1. #include <stdio.h>
  2. #include<stdlib.h>
  3. int main() {
  4. void *p;
  5. int cnt=0;
  6. while((p=malloc(100*1024*1024))) {
  7. cnt++;
  8. }
  9. printf("电脑可分配内存:%d00MB",cnt);
  10. return 0;
  11. }
复制代码

 3.2、指针的常见用途

(1)动态内存分配

C语言使用指针进行动态内存分配,例如malloc,calloc,realloc和free函数。这些函数返回一个指向已分配内存的指针,或者在释放内存时使用指针。

举例:

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. int main() {
  4. /* 使用 malloc 分配内存 */
  5. int *ptr = (int*) malloc(5 * sizeof(int));
  6. if(ptr == NULL) {
  7. printf("没有成功分配内存(Memory not allocated)\n");
  8. return 0;
  9. }
  10. else {
  11. printf("成功分配内存(Memory successfully allocated)\n");
  12. /* 使用这块内存 */
  13. for(int i = 0; i < 5; i++)
  14. ptr[i] = i + 1;
  15. /* 打印数组元素 */
  16. for(int i = 0; i < 5; i++)
  17. printf("%d, ", ptr[i]);
  18. }
  19. /* 使用 realloc 重新分配内存 */
  20. ptr = (int*) realloc(ptr, 10 * sizeof(int));
  21. if(ptr == NULL) {
  22. printf("没有成功分配内存(Memory not allocated)\n");
  23. return 0;
  24. }
  25. else {
  26. printf("\n成功分配内存(Memory successfully allocated).\n");
  27. /* 使用这块内存 */
  28. for(int i = 5; i < 10; i++)
  29. ptr[i] = i + 1;
  30. /* 打印数组元素 */
  31. for(int i = 0; i < 10; i++)
  32. printf("%d, ", ptr[i]);
  33. }
  34. free(ptr); /* 释放内存 */
  35. return 0;
  36. }
复制代码


(2)数组、字符串和结构体

指针用于处理数组和字符串。例如,字符串在C语言中表示为字符数组,通常使用字符指针处理。结构体指针用于动态分配结构体并访问其成员。

举例:

  1. #include <stdio.h>
  2. int main() {
  3. int arr[5] = {1, 2, 3, 4, 5};
  4. int *p1 = arr; // 指向数组的指针
  5. for(int i = 0; i < 5; i++) {
  6. printf("%d ", *(p1 + i)); // 使用指针访问数组元素
  7. }
  8. printf("\n");
  9. char str[] = "Hello, World!";
  10. char *p2 = str; // 指向字符串的指针
  11. while(*p2 != '\0') {
  12. printf("%c", *p2); // 使用指针访问字符串中的字符
  13. p2++;
  14. }
  15. return 0;
  16. }
复制代码

(3)数据结构

许多数据结构,如链表,树,图等,都依赖于指针。这些数据结构的节点通常包含指向其他节点的指针。

举例:

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. // 定义链表节点
  4. typedef struct Node {
  5. int data;
  6. struct Node* next;
  7. } Node;
  8. // 创建新节点
  9. Node* createNode(int data) {
  10. Node* newNode = (Node*)malloc(sizeof(Node));
  11. if(newNode == NULL) {
  12. printf("不能创建新结点(Unable to create a new node)\n");
  13. exit(0);
  14. }
  15. newNode->data = data;
  16. newNode->next = NULL;
  17. return newNode;
  18. }
  19. // 插入新节点到链表的末尾
  20. void insertNode(Node** head, int data) {
  21. Node* newNode = createNode(data);
  22. if(*head == NULL) {
  23. *head = newNode;
  24. return;
  25. }
  26. Node* temp = *head;
  27. while(temp->next != NULL) {
  28. temp = temp->next;
  29. }
  30. temp->next = newNode;
  31. }
  32. // 打印链表
  33. void printList(Node* head) {
  34. Node* temp = head;
  35. while(temp != NULL) {
  36. printf("%d -> ", temp->data);
  37. temp = temp->next;
  38. }
  39. printf("NULL\n");
  40. }
  41. int main() {
  42. Node* head = NULL;
  43. insertNode(&head, 1);
  44. insertNode(&head, 2);
  45. insertNode(&head, 3);
  46. printList(head);
  47. return 0;
  48. }
复制代码

(4)函数参数的传递

如果想在函数中修改变量的值,或者传递大型数据结构(如数组或结构)而不复制整个结构,那么可以使用指针。这被称为“通过引用传递”。

  1. #include <stdio.h>
  2. //通过指针接收一个整数,并将其值加一
  3. void addOne(int* ptr) {
  4. (*ptr)++; // 增加指针ptr所指向的值
  5. }
  6. int main() {
  7. int num = 0;
  8. printf("原始数据: %d\n", num);
  9. addOne(&num);
  10. printf("修改后: %d\n", num);
  11. return 0;
  12. }
复制代码

(5)函数指针

可以创建指向函数的指针,这在编写可插入函数、回调函数或者函数表等高级编程任务时非常有用。

举例:用 C语言编写程序,定义两个函数 mean 和 square 分别计算三个数的平均值和平方和,在主函数中输入三个数并调用它们,要求使用函数指针,当用户输入1时求平均值,输入2时求平
方和。

  1. #include <stdio.h>
  2. double mean(int a, int b, int c){
  3. return (a+b+c)/3.0;
  4. };
  5. int square(int a, int b, int c){
  6. return(a*a+b*b+c*c);
  7. };
  8. int main() {
  9. int choice;
  10. int num1, num2, num3;
  11. double result;
  12. double (*func_ptr)(int, int, int);//函数指针
  13. printf("请输入三个整数:");
  14. scanf("%d %d %d", &num1, &num2, &num3);
  15. printf("请选择操作:\n");
  16. printf("1. 求平均值\n");
  17. printf("2. 求平方和\n");
  18. scanf("%d", &choice);
  19. if (choice == 1) {
  20. func_ptr = mean;
  21. } else if (choice == 2) {
  22. func_ptr = square;
  23. } else {
  24. printf("无效选择。\n");
  25. return 1;
  26. }
  27. result = func_ptr(num1, num2, num3);
  28. if (choice == 1) {
  29. printf("三个数的平均值为:%.2f\n", result);
  30. } else if (choice == 2) {
  31. printf("三个数的平方和为:%.2f\n", result);
  32. }
  33. return 0;
  34. }
复制代码

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Honkers

荣誉红客

关注
  • 4010
    主题
  • 36
    粉丝
  • 0
    关注
这家伙很懒,什么都没留下!

中国红客联盟公众号

联系站长QQ:5520533

admin@chnhonker.com
Copyright © 2001-2025 Discuz Team. Powered by Discuz! X3.5 ( 粤ICP备13060014号 )|天天打卡 本站已运行