目录
1. 指针的概念
在C语言中,指针用于存储变量的内存地址,通过指针指向变量的内存地址,程序就可以间接访问和操作变量的值。
2.内存和地址
内存是计算机中的一种硬件组件,用于存储正在运行的程序和数据。而地址是指内存中存储单元的编号,用于标识和访问这些存储单元。在计算机中,内存被划分为许多小单元,每个单元都有一个唯一的地址。这些地址通常按照字节为单位进行编号,⼀个字节空间⾥⾯能放8个⽐特(1Byte=8 bit)
在计算机中,将内存单元的编号称为地址 ,在C语言中又给地址取了一个新名字,叫做指针,所以内存单元的编号=地址=指针
3.指针变量和地址
3.1 取地址操作符--(&)
在C语⾔中创建变量其实就是向内存申请空间存放变量中的值:
我们创建了一个整形变量a, 向内存申请了4个字节的空间大小,用来存放0,并且每个字节都有地址,那我们要怎么样得到a变量的地址呢?这时候我们就要通过取地址操作符 - &取出a的地址:
通过上图我们可以发现 &a 取出的是a所占4个字节中地址较⼩的字节的地址,虽然整型变量占⽤4个字节,但是我们只要知道了第⼀个字节地址,就能够顺藤摸⽠访问到4个字节的数据。
3.2 指针变量
什么是指针变量呢?上面我们通过取地址操作符,将a的地址取出来后,为了方便后续的使用,也是需要存储起来的,那我们就可以将这样的地址存放在指针变量中,所以指针变量也是⼀种变量,这种变量就是⽤来存放地址(指针)的,存放在指针变量中的值都会理解为地址。例如:
int main()
{
int a = 0;
int* p = &a;
return 0;
}
既然指针变量是一种变量,想必也会有变量的类型,从上面的代码中,我们可以这么理解:创建了一个指针变量p用来存放a的地址,而 int *就是指针变量p的类型,* 是在说明p是指针变量,⽽前⾯的 int 是在说明p指向的是整型(int) 类型的对象。
如果有⼀个char类型的变量ch,ch的地址,就应该放在 char *类型的指针变量中,例如:
int main()
{
char ch = 'a';
char* pc = &ch;
return 0;
}
3.3 解引用操作符--(*)
我们拿到了地址(指针),就可以通过地址(指针)找到地址(指针) 指向的对象,这个过程就需要通过解引用操作符去实现:
*pa 的意思就是通过pa中存放的地址,找到指向的空间, *pa其实就是a变量;所以*pa = 20,这个操作符是把a的值改成了20,其实这⾥是把a的修改交给了pa来操作,这样对a的修改,就多了⼀种的途径。
3.4 指针变量所占的空间大小
指针变量的⼤⼩和类型是⽆关的,只要指针类型的变量,在相同的平台下,⼤⼩都是相同的。
int main()
{
printf("%zd\n", sizeof(char*));
printf("%zd\n", sizeof(short*));
printf("%zd\n", sizeof(int*));
printf("%zd\n", sizeof(double*));
return 0;
}
在32位平台下地址是32个bit位,指针变量⼤⼩是4个字节
64位平台下地址是64个bit位,指针变量⼤⼩是8个字节
4.指针变量类型的意义
4.1 指针的解引⽤
指针的类型决定了,对指针解引⽤的时候⼀次能操作⼏个字节,⽐如: char* 的指针解引⽤就只能访问⼀个字节,⽽ int* 的指针的解引⽤就能访问四个字节:
对于上图我们就发现 int *类型的指针在解引用的时候,可以访问到4个字节的内容进行修改,而char *类型的指针在解引用的时候,只能访问到1个字节的内容进行修改。
4.2 指针+-整数
指针的类型决定了指针向前或者向后跳过几个字节的大小
int *类型:
char *类型:
4.3 void* 指针
void* 类型是指针类型中一种特殊的类型,可以理解为无具体类型的指针,这种类型的指针可以⽤来接受任意类型地址,但是void* 类型的指针不能直接进 ⾏指针的+-整数和解引⽤的运算。
因为在进行指针+-整数的时候,void*类型的指针无法确定每次加减多少个字节单位,并且在解引用的时候,不能确定访问多少个字节单位的内容。
编译器也会进行报错。
5.const修饰变量
当使用const修饰变量时,此时的变量就变成了常变量,不能被修改:
但是我们可以通过另一种方式对a进行修改,那就是指针的间接访问 :
但是既然我们既然一开始就不想变量a被改变,所以使用了const进行修饰,但是还能通过指针进行间接访问,这该怎么办呢? 别急,const不仅能修饰普通的变量,还能修饰指针变量。
const修饰指针变量
1.const放在*号的左边:修饰的是指针指向的内容(*pa),表示指针指向的内容(*pa)不能通过指针进行改变了,但是指针变量(pa)本身的值是可以改变的
2.const放在*号的右边:修饰的是指针变量(pa)本⾝,保证了指针变量(pa)本身的值不能修改,但是指针指向的内容(*pa)可以通过指针改变
3.*号两边都放上const: 表示指针变量本身(pa)的值不能被修改,指针指向的内容(*pa)也不能通过指针进行改变了
6. 指针运算
6.1 指针+-整数
在上面我们讲了指针+-运算的用法,现在我们搭配数组一起使用看看:
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
int* pa = arr;
int sz = sizeof(arr) / sizeof(arr[0]);//求数组的元素个数
for (int i = 0; i < sz; i++)
{
printf("%d ", *(pa + i));
}
return 0;
}
我们将arr数组首元素的地址存放在pa中,因为数组中元素的地址是连续存放的,所以此时pa+1就是下标为1的元素的地址,*(pa+1)就是下标为1的元素,带入循环,每次打印的就是arr数组中下标为 i 的元素。
6.2 指针-指针
指针-指针就是地址-地址,它们得到的结果就是它们之间所存放的元素个数:
那么我们接下来自己来写一个计算字符串长度的函数:
size_t my_strlen(char* str)
{
char* s = str;
while (*str != '\0')
{
str++;
}
return str - s;
}
int main()
{
char ch[] = "abcdef";
size_t len = my_strlen(ch);
printf("%zd", len);
return 0;
}
首先我们创建了一个数组存放字符串,实际上字符数组ch中存放的是 a b c d e f \0 ,将ch首元素的地址传给my_strlen,在my_strlen中,我们创建一个char*类型的指针变量str来接收ch首元素的地址,然后将str的值赋给s,我们通过while循环,直到*str=\0时,那么就停止++
最后返回str-s(指针-指针)的值,得到的就是\0和a之间的元素个数,也就是这个字符串中字符的个数。
6.3 指针的关系运算
指针与指针之间也可以进行大小的比较
例如:
我们直到数组元素的地址是通过下标的增长而递增的,所以我们可以通过地址的比较作为循环的 执行条件,打印出数组的元素个数。
以上就是初识指针1的全部内容,希望大家看完本章内容,能够对指针有一个初步的认识,后续会继续更新指针的更多内容,如有错误欢迎指出,谢谢大家!!!