您现在的位置是:首页 >技术交流 >初识C语言的指针网站首页技术交流
初识C语言的指针
简介初识C语言的指针
前言
指针在C语言中是非常重要的概念。
指针是什么
- 指针是内存中的最小单元的编号,就是内存地址
- 指针通常指的是指针变量,是用于存放内存地址的变量。
内存的最小单元是1字节。
32位系统中的指针变量大小是始终4个字节,64位系统中的指针变量大小是始终8字节。
在C语言中,可以通过以下方式使用指针变量
#include <stdio.h>
int main()
{
int a = 10;
int* p = &a; // 这里p就是一个指针变量,存放的是a在内存中的地址
return 0;
}
指针类型
指针类型分为以下几种
char *pc;
声明一个指向字符类型的指针变量int *pi;
声明一个指向整数类型的指针变量short *ps;
声明一个指向短整数类型的指针变量long *pl;
声明一个长整数类型的指针变量float *pf;
声明一个单精度浮点数类型的指针变量double *pd;
声明一个双精度浮点数类型的指针变量
以下用char*
和int*
作为例子简述指针类型之间的区别
// 区别1: char*存放char类型变量的地址,int*存放int类型变量的地址
#include <stdio.h>
int main()
{
char str = 'a';
char* pc = &str; // 这里pc是str在内存中的地址
*pc = 'b';
printf("%c
", str); // b
int* pi = &str; // 这里会有一个warnning,提示str是char类型,用int*不兼容
*pi = 10; // err
printf("%d
", str);
return 0;
}
/*
区别2:
char*类型指针加1是往后移一个字节,因为对应的char是占一个字节,
int*类型指针加1是往后移4个字节,因为对应的int是占4个字节
*/
#include <stdio.h>
int main()
{
int n = 10;
int* pi = &n;
printf("%p
", pi); // 00B9F954
printf("%p
", pi + 1); // 00B9F958 跟上面相差4个字节
char str = 'a';
char* pc = &str;
printf("%p
", pc); // 012FFA53
printf("%p
", pc + 1); // 012FFA54 跟上面相差1个字节
return 0;
}
总结:存放不同类型变量的地址,应该使用与之对应类型的指针变量。
操作指针
指针±整数
指针+n = 原指针地址 + (指针对应的数据类型的字节长度 * n)
以下用char*
和int*
作为例子
#include <stdio.h>
int main()
{
int n = 10;
int* pi = &n;
printf("%p
", &n); // 0057FEB0
printf("%p
", pi); // 0057FEB0
printf("%p
", pi + 2); // 0057FEB8 = 0057FEB0 + (4 * 1)
char str = 'a';
char* pc = &str;
printf("%p
", &str); // 0057FE9B
printf("%p
", pc); // 0057FE9B
printf("%p
", pc+3); // 0057FE9E = 0057FE9B + (1 * 3)
return 0;
}
总结:指针对应的数据类型是指针移动的距离的关键因素。
指针的解引用
每个类型的指针操作的空间不同
以下用char*
和int*
作为例子
#include <stdio.h>
int main()
{
int n = 0x11223344; // 这里使用的是16进制,也可以使用10进制 287454020
int* pi = &n;
char* pc = (char*)&n;
// 这里&n在内存监视中是这样的 0x001DF970 44 33 22 11
*pi = 0; // 这里操作完之后,是这样的 0x001DF970 00 00 00 00
n = 0x11223344; // 0x001DF970 44 33 22 11
*pc = 0; // 这里操作完之后,是这样的 0x001DF970 00 33 22 11
return 0;
}
总结:指针操作的空间是这个指针对应的数据类型的大小,例如char*
就是4个,int*
就是1个。
野指针
野指针是指指向未知存储位置的指针。
野指针出现的原因
-
指针未初始化
int main() { int* p; // 这里创建了指针却未初始化,所以它默认是随机值 *p = 10; // error return 0; }
-
指针越界访问
/* 这个数组长度为10,但是在for循环的时候指针最后一次超出了10,造成了指针越界访问 */ int main() { int arr[10] = { 0 }; int sz = sizeof(arr) / sizeof(arr[0]); int* p = arr; for (int i = 0; i < sz + 1; i++) { *p = i; // 在最后一次循环的时候,越界了 p++; } return 0; }
-
指针指向的空间被释放
#include <stdio.h> int* test() { int a = 10; return &a; } int main() { int* p = test(); // 此时p指向的是a的地址,但是a在test函数结束之后就被回收了,所以此时p就是野指针了。 return 0; }
如何避免出现野指针
-
指针创建的时候先初始化:
int* p = NULL;
-
避免指针越界访问
-
在使用指针的时候,先置空,使用时再判断一下是否是
NULL
#include <stdio.h> int main() { int* p = NULL; if (p != NULL) // 这里判断一样 { *p = 1; } return 0; }
-
避免函数返回变量的地址
指针运算
-
指针±整数改变指针的地址
-
指针-指针算出字符串的长度
#include <stdio.h> int main() { int arr[10] = { 0 }; int* p0 = &arr[0]; int* p6 = &arr[6]; printf("%d ", p6 - p0); // 6 return 0; } // 这里使用指针-指针写一个函数算出字符串的长度 int my_strlen(char* arr) { char* p = arr; // 记录下开始的位置 while (*arr != '