声明:以下文字总结纯个人理解及手打。
一.指针的定义
指针的定义是指一个变量用来存放另一个变量的地址。这个地址可以是一个内存地址,也可以是文件中的位置,甚至是网络中某个设备的地址。在程序设计中,指针变量用来存储和操作地址信息,可以实现数据的快速访问和操作。在定义指针变量时,需要在变量名前面加上星号(*),表示该变量是一个指针变量。例如,int *p表示定义了一个指向整型变量的指针变量p。
其中 图中指针变量名为 i_pointer *表示该变量是一个指针变量。
直接访问和间接访问
二.指针变量的说明
1.什么是指针变量???
指针变量是指专门用来存放变量地址的变量,也可以称之为专门用来存地址,都是可以的,也就是说指针和地址是等价的。指针变量是一个变量,它占用的空间取决于程序是32位还是64位,如果是64位程序,指针变量占用8个字节,如果是32位程序,指针变量占用4个字节。在定义指针变量时必须指定类型,并且指针变量必须是相同类型的才能使用。指针变量的本质是为了做间接访问操作。(考研中会强调为32位程序)
2.指针变量和地址的关系
指针变量和地址的关系是等价的。一个变量的地址可以称为该变量的指针,而一个指针变量是专门用来存放变量地址的。在程序中,通过指针变量可以直接访问该指针所指向的变量,因此指针变量也被称为间接访问方式。
3.指针变量和地址的区别
指针变量和地址的区别在于: 指针变量是一个专门用来存储地址(即内存中变量的位置)的变量,这个地址可以理解为指向某个变量或对象的“指针”。而地址本身是用来标识内存中特定位置的一个数值。指针变量和地址在本质上是等价的,都是用来在程序中引用特定的内存位置。 当提到一个变量的“地址”时,实际上是指该变量在内存中的位置。这个位置可以被看作是该变量的“指针”。因此,一个变量的地址也可以被称为该变量的指针。 在程序中,通过使用指针变量,可以直接访问和操作内存中的变量或对象,而无需知道这些变量或对象的实际内存地址。指针变量使得程序可以更高效地访问和操作内存中的数据,简化了编程过程。 总之,指针变量和地址在本质上是等价的,都是用来在程序中引用特定的内存位置。指针变量是一种特殊的变量,它存储的是一个内存地址,通过这个地址可以访问和操作内存中的数据。
特别注意:
取地址操作符为&
取值操作符为*
&*之间是相互等价的 两者同时出现时抵消
如:&*p=p
4.指针变量初始化
指针变量初始化是取地址来赋值,不能随机写个数。
注:定义多个指针变量时:
错误示范:int *a,b,c (其中b,c并非是指针 而是int)
正确写法:int *a ,*b,*c
三,指针的传递性
指针的传递是指将变量的地址作为参数传递给函数,以便在函数内部通过间接访问来修改该变量的值。在函数调用中,将变量的地址作为参数传递给函数意味着函数将地址存储在它的局部变量中。然后,使用这个地址间接访问该变量,从而可以修改该变量的值
1.如change为指针的传递 执行实则将实参数赋值给了形参 不影响最后i的值
#include <stdio.h>
void change(int j) //j是形参
{
j=5;
}
int main() {
int i=10;
printf("%d\n",i);
change(i); //实际上执行change(i)时将实参数给了形参 j=i
printf("%d",i);
return 0;
}
运行结果:
2.如下方代码可以通过该代码运行结果,来了解指针的传递性
#include <stdio.h>
void change(int *j) //j是形参
{
*j=5;
}
int main() {
int i=10;
printf("%d\n",i);
change(&i); //实际上执行change(i)时将实参数给了形参 j=&i
printf("%d",i);
return 0;
}
运行结果:
为什么这里的i变成了5呢?
个人理解:
change(&i); //实际上执行change(i)时将实参数给了形参 j=&i
i的地址赋给了j 假定&i=00ff18 通过change(&i); 将j同为j地址=00ff18 *j将00ff18地址的值变成5 使得i=5
(图仅自己理解画出,如有错误我将及时更改)
四,指针的偏移
指针的偏移是指针变量中存储的地址值进行加减操作的一种方式(对指针乘除是没有意义的),用于访问和操作内存中的不同位置。指针偏移的使用场景在于需要访问和操作内存中不同位置的数据,这些数据可能是数组、结构体或其他数据结构中的元素。
1.指针偏移的注意事项
在进行指针偏移时,需要注意以下几点:
1. 指针偏移的长度是其基类型的长度,也就是sizeof int。
2. 指针偏移的结果是地址的增量,增量的大小是基类型的长度。
3. 加法操作和减法操作都是有效的,可以向前或向后偏移,但不可以进行乘除操作。
4. 指针偏移的结果可以用于访问和操作内存中的不同位置,包括数组、结构体或其他数据结构中的元素。
指针偏移:
#include <stdio.h>
#define N 5 //引用符号常量N
//符号常量的定义如下:
//符号常量是一种用于表示特定值或表达式的标识符
//在程序中定义后,它将不能被修改或重新定义。
//符号常量通常用于表示一些固定的值,例如数组的大小、最大整数等。
int main() {
int a[N]={1,2,3,4,5}; //其中数组名内存储了数组的起始地址,a中存储的就是一个地址值
int *p; //定义指针变量p
p=a; //这里没有使用&a 原因是a在这里就是代表一个地址 无需写&a
int ;
for (int i = 0; i < N; ++i)
{
printf("%3d",a[i]);
}
return 0;
}
运行调试
将指针逆向输出
五,指针与动态内存申请
1.动态内存申请的理解
malloc是C语言中的内存分配函数,它用于动态地从操作系统的堆空间中申请一块指定大小的内存区域,并返回该内存区域的首地址。 上图中使用malloc函数申请动态堆空间
scanf是输入申请的空间大小
free函数 释放申请的空间 free函数中不能写成free(p+1),free(p+2)等 ,free函数里要是最初malloc的地址
特别注意:1.使用strcpy函数 要调用 #include <string.h>
2.对于malloc不定义是表示无类型的指针 需要写成(char*)malloc()表示为 字符类型
整型类型表示:(int*)malloc()
2.个人总结
个人对指针变量和内存申请做了以下总结:
指针是用于存储内存地址的变量,而动态内存申请是在程序运行时动态地分配内存的过程。
1. 指针变量:
* 指针是一种变量,它存储了一个内存地址。
* 在大多数编程语言中,指针用特殊的语法来声明和操作。
* 指针可以用来保存对象、数组、函数等的内存地址。
2. 指针的算术运算:
* 通过加法和减法等算术运算,可以操作指针。
* 加法运算可以使指针向前(或向后)移动一定数量的位置。
*减法运算可以使指针向后(或向前)移动一定数量的位置。
3. 动态内存分配:
* 在程序运行时,可以动态地分配内存空间。
* 动态内存分配常用于处理大型数据结构(例如字符串或数组),这些数据结构的大小在编写程序时无法确定。
* 通过使用特殊的函数(如`malloc`、`calloc`或`realloc`),可以在程序运行时动态地分配内存。
4. 内存管理:
* 内存管理涉及分配、使用和释放内存的过程。
* 使用`malloc`等函数分配的内存必须使用`free`函数进行释放,以避免内存泄漏。
* 在某些编程语言(如C++)中,可以使用智能指针来进行自动内存管理。
5. 指针与数组:
* 在许多编程语言中,数组的名称可以作为指向数组第一个元素的指针使用。
* 通过使用指针和数组,可以更高效地访问和处理大型数据结构。
6. 指针与函数:
* 函数的参数可以通过传值(例如使用普通变量)或传引用(例如使用指针)的方式传递。
* 通过指针作为函数参数,可以传递大型数据结构(如数组)或避免数据复制。
7. 注意事项:
* 指针操作需要谨慎处理,因为错误的指针操作可能导致程序崩溃或未定义行为。
* 在使用动态内存分配时,要注意检查分配是否成功,并正确释放分配的内存。
* 在使用指针时,要注意空指针和野指针的问题,避免访问未定义的内存区域。