前言
C语言中的初阶指针
一、指针是什么
1.把内存划分为一个个的内存单元,这个内存单元的大小是1个字节
2.每个字节都给一个唯一的编号,这个编号我们称为地址,地址在C语言中也叫:指针
编号 == 地址 == 指针
(1)指针理解的2个要点:
1.指针是内存中一个最小单元的编号,也就是地址
2.平时口语中说的指针,通常指的是指针变量,是用来存放内存地址的变量
#include<stdio.h>
int main()
{
int a = 10; int a = 10;
int* pa = &a; int* pa = &a;
return 0;
}
a是整形,占用4个字节的内存空间,每个字节都有对应的地址
&a -得到的是a的地址(指针),其实得到的是a所占内存中4个字节中第一个字节的地址,pa是指针变量
(2)总结:
指针变量,用来存放地址的变量。(存放在指针中的值都被当成地址处理)。那这里的问题是:
经过仔细的计算和权衡我们发现一个字节给一个对应的地址是比较合适的。对于32位的机器,假设有32根地址线,那么假设每根地址线在寻址的时候产生高电平(高电压)和低电平(低电压)就是(1或者0)
这里就有2的32次方个地址。
每个地址标识一个字节,那我们就可以给(2^32Byte == 2^32/1024KB == 2^32/1024/1024MB == 2^32/1024/1024/1024GB == 4GB)4G的空间进行编址。
(3)这里我们就明白:
·在32位的机器上,地址是32个0或者1组成二进制序列,那地址就得用4个字节的空间来存储,所以一个指针变量的大小就应该是4个字节。
那如果在64位机器上,如果有64个地址线,那一个指针变量的大小是8个字节,才能存放一个地址。
(4)总结😗
●指针变量是用来存放地址的,地址是唯一标示一个内存单元
●指针的大小在32位平台是4个字节,在64位平台是8个字节。
二、指针和指针类型
(1)指针类型决定了,在解引用指针的时候能访问几个字节
int main()
{
int a = 0x11223344;
int* pa = &a;//可以访问四个字节
*pa = 0;
char* pc = &a ; //可以访问一个字节
*pc = 0;
return 0;
}
(2)指针类型决定了指针进行+1、-1的时候,一步走多远
pa+n – +nsizeof(int)
pc+n – +nsizeof(char)
总结😗
指针的类型决定了,对指针解引用的时候有多大的权限(能操作几个字节)。
比如: char的指针解引用就只能访问一个字节,而int的指针的解引用就能访问四个字节。
三、野指针
概念:野指针就是指针指向的位置是不可知的(随机的、不正确的、没有明确限制的)
野指针成因:
(1)指针未初始化
(2)指针越界访问
(3)指针指向的空间释放
如何规避野指针:
1.指针初始化
2.小心指针越界
3.指针指向空间释放,及时置NULL
4.避免返回局部变量的地址
5.指针使用之前检查有效性
四、指针运算
(1)指针+ -整数
例一:
#include<stdio.h>
int my_strlen(char* str)
{
int count = 0;
while (*str != '\0')
{
count++;
str++;
}
return count;
}
int main()
{
int len=my_strlen("abcdef");
printf("%d\n", len);
return 0;
}
例二:
#define N_VALUES 5
float values[N_VALUES];
float* vp;
for (vp = &values[0]; vp < &values[N_VALUES];)
{
*vp++ = 0;
}
(2)指针-指针
指针-指针
地址-地址
1.两个指针指向同一块空间,指针类型是一致的
2.指针-指针得到的是指针和指针之间的元素个数(有正负)
随着数组下标的增长地址是由低到高变换的
#include<stdio.h>
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
int n = &arr[9] - &arr[0];
printf("%d\n", n);
return 0;
}
#include<stdio.h>
int my_strlen(char* str)
{
char* start = str;
while (*str != '\0')
{
str++;
}
return str - start;
}
int main()
{
int len=my_strlen("abcdef");
printf("%d\n", len);
return 0;
}
(3)指针的关系运算
#define N_VALUES 5
float values[N_VALUES];
float* vp;
for (vp = &values[N_VALUES]; vp > &values[0];)
{
*--vp = 0;
}
标准规定:
允许指向数组元素的指针与指向数组最后一个元素后面的那个内存位置的指针比较,但是不允许与指向第一个元素之前的那个内存位置的指针进行比较。
也就是p1可以和p3比较但是p1不可以和p2比较所以不建议采用下面类型的代码
#define N_VALUES 5
float values[N_VALUES];
float* vp;
for (vp = &values[N_VALUES-1]; vp >= &values[0];vp--)
{
*vp = 0;
}
五、指针和数组
指针的大小:4/8个字节,指针是存档地址的,地址的存放需要多大空间指针变量的大小就是多少。
数组的大小:取决于数组元素个数和每个元素类型
指针可以指向数组元素
因为指针可以运算,所以借助于指针可以访问数组
#include<stdio.h>
int main()
{
int arr[10] = { 0 };
int *p=arr;//&arr[0]首元素地址
int i = 0;
for (i = 0; i < 10; i++)
{
*p = i + 1;
p++;
}//两种写法上面是第一种,下面是第二种
p = arr;//因为上面p已经指向10了所以让p等于首元素地址重新开始
for (i = 0; i < 10; i++)
{
*(p + i) = i + 1;
printf("%d ", *(p+i));
}
return 0;
}
六、二级指针
A (即B的地址)是指向指针的指针,称为 二级指针 ,用于存放二级指针的变量称为 二级指针变量 .根据B的不同情况,二级指针又分为指向指针变量的指针和指向数组的指针。 为了获取指针的存放地址。 首先任何值都有地址 ,一级 指针 的值虽然是地址,但这个地址做为一个值亦需要空间来存放,是空间就具有地址 ,这就是存放地址这一值的空间所具有的地址,二级指针就是为了获取这个地址。
#include<stdio.h>
int main()
{
int a = 10;//a是要在内存中申请4个字节的空间
int* pa=&a;//0x0012ff40,pa是指针变量用来存放地址,也要向内存中申请4/8个字节
int** ppa = &pa;
printf("%d\n", **ppa);
return 0;
}
七、指针数组
#include<stdio.h>
int main()
{
int a = 10;
int b = 20;
int c = 30;
//指针数组-存放指针的数组
int* arr[] = { &a,&b,&c };
int i = 0;
for (i = 0; i < 3; i++)
{
//arr[i]是地址
printf("%d ", *(arr[i]));
}
return 0;
}
#include<stdio.h>
int main()
{
char* arr[5];//数组的每个类型都是char*类型的
char** p = arr;//所以&arr[0]-是char**
return 0;
}
总结
以上则是对C语言中初阶指针的简单了解