C语言入门系列第六天:指针的学习
期中考试终于结束了,不知道各位同学考的怎么样(相信大家一定都很好),那么不管过去如何,让我们把目标放在更长远的学习上,今天,我们就来学习C语言之中的boss,指针。
当谈到C语言的高级特性时,指针是一个关键概念。指针提供了对内存中存储数据的直接访问,使程序能够高效地操作和管理数据。那么问题来了,什么是指针。
一、什么是指针?
指针是一个变量类型(可以理解为咱们之前学的int、float一样是一个数据类型),它存储了一个内存地址。内存地址指向计算机内存中的一个特定位置,该位置存储了一些数据。通过使用指针,我们可以直接访问和操作存储在内存中的数据。
在C语言中,声明一个指针需要使用星号(*)操作符。
int *ptr;
在上面的代码中,我们声明了一个名为ptr的指针,它可以指向一个整数,我们可以说变量ptr的类型是int*。
二、指针的基本操作
- 获取变量的地址:可以使用取地址操作符(&)获得一个变量的地址。例如:
int num = 10;
int *ptr = #
在上面的代码中,我们使用&
操作符获取了变量num
的地址,并将其赋值给了指针ptr
。
- 访问指针指向的值:可以使用解引用操作符(*)来访问指针指向的值。例如:
int value = *ptr;
在上面的代码中,我们使用*
操作符获取了指针ptr
所指向的值,并将其赋值给了变量value
。
- 修改指针指向的值:可以通过解引用操作符(*)修改指针指向的值。例如:
*ptr = 20;
在上面的代码中,我们将指针ptr
所指向的值修改为20。
做个小小的总结:
#include<stdio.h>
int main()
{
int a = 3; //声明整型变量a
int *p = &a; //让指针p指向a的地址
printf("%d\n%d\n%d\n",a,p,*p);// 输出结果为 3 6684180(地址) 3
return 0;
}
三、指针的应用
指针在C语言中广泛应用于各种场景,下面是一些常见的应用案例:
-
动态内存分配:通过使用指针,我们可以在程序运行时动态地分配和释放内存。
举个例子,在数组的学习之中,我们遇到了一个情况,就是需要根据输入的n 来调整数组的大小,我们采用的的方式是:
int n; scanf("%d",&n); int a[n];
在我们学习了指针之后,就可以采用新的方式进行声明了,接下来介绍一个最常用的函数,malloc:
malloc 是C语言中用于动态分配内存的函数,其名称来自 “memory allocation” 的缩写。这个函数允许在程序运行时请求指定数量的字节的内存空间。动态内存分配对于需要在运行时确定大小或生命周期不确定的数据非常有用。
#include<stdlib.h> void* malloc(size_t size);
这个函数接受一个 size_t 类型的参数,表示需要分配的字节数,然后返回一个 void 指针,指向分配的内存的起始位置。需要注意的是,返回的是 void*,因为 malloc 不知道你要存储的是什么类型的数据,所以返回一个通用的指针。
下面是一个简单的例子,演示如何使用 malloc 分配一块内存,并在程序结束时释放它:
#include<stdio.h> #include<stdlib.h> int main() { // 分配 10 个整数大小的内存空间 int *arr = (int*)malloc(10 * sizeof(int)); //传入元素的个数和元素的字长 if (arr == NULL) { // 检查分配是否成功 fprintf(stderr, "内存分配失败\n"); return 1; // 返回非零值表示程序异常结束 } // 使用分配的内存 for (int i = 0; i<10; ++i) { arr[i] = i * 2; } // 打印数组内容 for (int i = 0; i < 10; ++i) { printf("%d ", arr[i]); } // 释放内存 free(arr); //注意,malloc一定要和free搭配使用,否则会出现内存泄漏 return 0; // 返回零表示程序正常结束
}
在这个例子中,首先使用 malloc 分配了足够存储 10 个整数的内存空间,然后通过类型转换将返回的 void* 指针转换为 int* 类型的指针,方便后续对数组的操作。最后,使用 free 函数释放了动态分配的内存。
使用动态内存分配要小心,一旦分配完成,你就负责管理这块内存,包括在使用完毕后及时释放。否则,可能会导致内存泄漏等问题。 -
传递参数:通过指针,我们可以在函数之间传递数据,使得函数能够直接修改原始数据而不是复制一份数据。这样可以提高程序的效率和节省内存空间。
最常见的就是在我们写交换函数的时候,明明放在主函数里面可以实现的,但是提出来之后就没有办法对原来的数据进行操作了,使用指针传参可以很好的解决这个问题。
#include <stdio.h> // 函数原型 void swap(int *a, int *b); int main() { int x = 5; int y = 10; printf("交换前:x = %d, y = %d\n", x, y); // 调用交换函数 swap(&x, &y); //因为指针指向的是地址,所以在传参的时候要注意不能传入数据本身,而是地址。 printf("交换后:x = %d, y = %d\n", x, y); return 0; } // 函数定义,交换两个整数的值 void swap(int *a, int *b) { int temp = *a; // 保存 a 的值 *a = *b; // 将 b 的值赋给 a *b = temp; // 将保存的 a 的值赋给 b }
-
数组和字符串操作:指针和数组之间有着密切的关系。实际上,数组名在C语言中本质上是指向数组第一个元素的指针。通过指针,我们可以对数组进行遍历、修改和传递。
让我们举例说明:
1.数组和指针的关系: 在 C 语言中,数组名是数组第一个元素的地址。例如:
int numbers[5] = {1, 2, 3, 4, 5}; int *ptr = numbers; // 数组名 numbers 可以被视为指向数组第一个元素的指针
2.数组遍历: 使用指针,可以遍历数组的所有元素。例如:
for (int i = 0; i < 5; ++i) { printf("%d ", *(ptr + i)); // 使用指针遍历数组元素 }
3.指针和数组传递给函数: 当数组传递给函数时,实际上传递的是数组的地址(第一个元素的地址)。函数参数可以声明为指针,接收这个地址。例如:
void printArray(int *arr, int size) { for (int i = 0; i < size; ++i) { printf("%d ", arr[i]); } printf("\n"); } int main() { int numbers[5] = {1, 2, 3, 4, 5}; printArray(numbers, 5); return 0; }
4.字符串和指针: 字符串在 C 语言中通常表示为字符数组,其中的每个字符都存储在一个数组元素中。字符串常量也是字符数组。例如:
char str[] = "Hello"; char *ptr_str = "World";
在这里,str 是一个字符数组,ptr_str 是一个指向字符串常量的指针。
这种指针和数组之间的关系使得在 C 语言中能够更方便地对数组和字符串进行操作,包括遍历、修改和传递给函数等操作。
综上所述:
在C语言中,指针是一项重要的特性,它提供了直接访问内存中存储数据的能力。通过理解指针的概念和操作,我们可以更好地掌握C语言并写出更高效、灵活的程序。
然而,指针的使用需要谨慎,因为它容易引发内存错误(如空指针引用、越界访问等)。因此,在编写使用指针的程序时,务必小心并遵循最佳实践,以确保程序的正确性和稳定性。
大家可以拿出之前写过的题目,使用指针重新写一遍,以此来熟悉对于指针的认识。