前言:指针的学习
在c语言的学习过程中,指针的学习无疑是其中的一道难关,相对来说比较复杂,但是只要从地址和内存管理两方面理解指针,你也许就会发现指针并没有想象中那么难,希望下面的内容能解决你在学习指针中的困扰。
一、指针介绍
1. 为什么要用指针
解决跨区域(不同的作用域 不同代码块)之间的数据交互
例如通过函数来改变数值:
//通过指针传给函数地址 来改变变量的值
//如果使用形式参数则达不到这样的效果
void test(int *a){
*a++;
}
int main(int argc, const char * argv[]) {
int a = 10;
int *pa = &a;
test(pa);
printf("%d\n",a);
return 0;
}
2. 指针的表现形式
-
'*':
1.声明/定义变量的时候 表示一个指针变量
float b = 20;
int c = 10;
int *a; 定义一个指针变量 指向的内存空间只能放整数
注意:定义指针变量的时候画一定要给初值 不确定就给NULL
int *a = b;不行,指针变量只能存地址 不能存具体值
int *a = &b;不行,整型指针只能存整形数据的地址
int *a = &c;正确
float *d = NULL;NULL指向内存的起始地址 0x00
- 除了定义指针变量之外 都是访问某个 地址的值
int *temp = &c; //访问指针变量
*temp = 21;访问temp地址里面的数据 赋值为21
-
'&':
取某个变量的地址,如最熟悉的scanf函数
3. 指针的占用内存
所有的指针类型都占8个字节(64位)
二、指针的运用
1. 函数指针
int test(int a){
return 0;
}
int main(int argc, const char * argv[]) {
int(*pFunc)(int) = test;
return 0;
}
2. 数组与指针的关系
数组名并不是一个变量,没有分配内存空间 例如int a = 10;而指针变量是有内存空间的
int score[5] = {1,2,3,4,5};
printf("%p\n",score);
printf("%p\n",&score);
for (int i = 0; i < 5; i++) {
printf("%d ",*(score + i));
//加i个元素 score+ i = 0x7ffeefbff510 + i*4
}
printf("\n");
printf("%p\n",score); //0x7ffeefbff510
printf("%p\n",score+1); //0x7ffeefbff514
printf("%d\n",*(score+1)); //2
printf("%d\n",*score+1); //2
printf("%d\n",(*score)++); //1
printf("%d\n",score[0]); //2
printf("%d\n",++*score); //3
*(score + i)表示加I个元素,而不是加i个字节
例如整型数据:
score+ i = 0x7ffeefbff510 + i**sizeof(int)
-
区别
定义类型 | 数组 | 指针变量 |
---|---|---|
区别 | 系统会分配内存空间 可以存值 | 只为变量本身分配8个字节内存空间 无法存值 |
struct Person{
char name[10]; //字符有对齐 与最近的对齐
char *address;
int age;
};
//定义结构体struct Person变量 变量名xw
int i;
struct Person xw;
// xw.name = "小王"; //数组一旦定义 地址不能改变
//不能直接给数组赋值
xw.name[0] = 'x'; //系统为这个变量分配内存了
xw.name[1] = 'w';
xw.address = "西南大学"; //常量字符串地址是由系统分配的
//先为address分配内存
xw.address = malloc(2 * sizeof(char));
xw.address[0] = 's'; //字符指针赋值
xw.address[1] = 'n';
xw.age = 30;
//结构体赋值用大括号{}
int i2 = 10;
struct Person zs = {"张三",20};
printf("name:%s\n",xw.name);
printf("address:%s\n",xw.address);
-
结构体对齐规则参考链接:
3. 给指针指向的区域赋值
- 指针变量已经指向某块区域
int a = 10;
int *pA = &a; //指向变量a的内存地址
*pA = 30;
- 指针指向一个数组
int num[10] = {};
int *pNum = num; //指向数组num的首地址
*(pNum + 0) = 20;
pNum[0] = 20;
动态分配内存 malloc realloc free
注意:
1. 自己分配的内存空间 必须自己释放
2. 普通变量的内存是系统分配 所以系统自己释放
3. 常量字符串地址是由系统分配的
char *pName = malloc(3 * sizeof(char));
//判断分配是否成功
if (pName == NULL) {
//分配失败
exit(EXIT_FAILURE);
}
pName[0] = 'j';
pName[1] = 'a';
pName[2] = 'c';
printf("%s\n",pName);
//当之前分配的内存空间不够了 就需要在之前的基础上重新分配
//realloc 必须是之前使用melloc分配过的
//如果是系统分配的内存 不能使用realloc
//用完了就要自己释放内存
pName = realloc(pName, 4*sizeof(char));
pName[3] = 'k';
//手动释放内存
free(pName);
4. 单链表
//定义一个学生的结构体节点
typedef struct Node{
char name[10];
int ID;
float score;
struct Node *next; //32个字节
} Student;
//初始化一个头结点
void initHeader(Student **pHeader){
//动态分配内存
Student *pTemp = malloc(1 * sizeof(Student));
//初始化
pTemp->next = NULL;
//改变外部的值
*pHeader = pTemp;
}
网友评论