文章目录
目录
1.内存与地址
我们都知道在生活中,一个大房子的每个房间都有房间号,这样可以更加快速的找到所要房间,同样的,电脑CPU在处理数据的时候,需要的数据是在内存中读取的,处理后的数据也会放回内存中,把内存划分为⼀个个的内存单元,就可以高效的管理内存空间,每个内存单元的⼤⼩取1个字节。每个内存单元也都有⼀个编号(这个编号就相当于房间的房间号),有了这个内存单元的编号,CPU就可以快速找到⼀个内存空间,在计算机中我们把内存单元的编号称为地址。C语⾔中给地址起了新的名字叫:指针,所以我们可以理解为:内存单元的编号==地址==指针。
2.指针变量和地址
2.1取地址操作符(&)
在C语⾔中创建变量其实就是向内存申请空间,⽐如:
#include <stdio.h>
int main()
{
int a = 10;
return 0;
}
上述的代码就是创建了整型变量a,内存中申请4个字节,⽤于存放整数10,其中每个字节都有地址。
要得到a的地址就需要操作符(&)-取地址操作符
#include <stdio.h>
int main()
{
int a = 10;
&a;//取出a的地址
printf("%p\n", &a);
return 0;
}
&a取出的是a所占4个字节中地址较小的字节的地址。
2.2 指针变量和解引用操作符(*)
通过取地址操作符(&)拿到的地址是⼀个数值,这个数值有时候也是需要存储起来,方便后期再使用的,这个数值就是存放在指针变量中,指针变量也是⼀种变量,这种变量就是用来存放地址的,存放在指针变量中的值都会理解为地址。
将地址存储在指针变量中再需要取出来用时,就要用到解引用操作符(*)
#include <stdio.h>
int main()
{
int a = 100;
int* pa = &a;
*pa = 0;
return 0;
}
上面代码中第6行就使用了解引用操作符, *pa 的意思就是通过pa中存放的地址,找到指向的空间, *pa其实就是a变量了;所以*pa=0,这个操作符是把a改成了0。
这里还要提一下指针变量的大小,32位平台下地址是32个bit位,指针变量大小是4个字节, 64位平台下地址是64个bit位,指针变量大小是8个字节,指针变量的大小和类型是⽆关的,只要指针类型的变量,在相同的平台下,大小都是相同的。
3.const修饰指针
变量是可以修改的,如果把变量的地址交给⼀个指针变量,通过指针变量的也可以修改这个变量,但加上const就可以使变量不能被修改。
const如果放在*的左边,修饰的是指针指向的内容,保证指针指向的内容不能通过指针来改变, 但是指针变量本身的内容可变。const如果放在*的右边,修饰的是指针变量本身,保证了指针变量的内容不能修改,但是指针指向的内容,可以通过指针改变。
4.指针运算
4.1 指针+-整数
#include <stdio.h>
int main()
{
int arr[10] = {1,2,3,4,5,6,7,8,9,10};
int *p = &arr[0];
int i = 0;
int sz = sizeof(arr)/sizeof(arr[0]);
for(i=0; i<sz; i++)
{
printf("%d ", *(p+i));//p+i 这⾥就是指针+整数
}
return 0;
}
4.2指针-指针
#include <stdio.h>
int my_strlen(char *s)
{
char *p = s;
while(*p != '\0' )
p++;
return p-s;
}
int main()
{
printf("%d\n", my_strlen("abc"));
return 0;
}
5.野指针
野指针就是指针指向的位置是不可知的,产生的原因有一下几种。
1.指针未初始化
#include <stdio.h>
int main()
{
int *p;//局部变量指针未初始化,默认为随机值
*p = 20;
return 0;
}
2.指针越界访问
#include <stdio.h>
int main()
{
int arr[10] = {0};
int *p = &arr[0];
int i = 0;
for(i=0; i<=11; i++)
{
//当指针指向的范围超出数组arr的范围时,p就是野指针
*(p++) = i;
}
return 0;
}
3.指针指向的空间释放
#include <stdio.h>
int* test()
{
int n = 100;
return &n;
}
int main()
{
int*p = test();
printf("%d\n", *p);
return 0;
}
6.传值调用和传址调用
这里给一串代码
#include <stdio.h>
void Swap1(int x, int y)
{
int tmp = x;
x = y;
y = tmp;
}
int main()
{
int a = 0;
int b = 0;
scanf("%d %d", &a, &b);
printf("交换前:a=%d b=%d\n", a, b);
Swap1(a, b);
printf("交换后:a=%d b=%d\n", a, b);
return 0;
}
运行代码后会发现a,b并没有发生交换 ,因为这里用的是传值调用,实参传递给形参的时候,形参会单独创建⼀份临时空间来接收实参,对形参的修改不影响实参。
这个时候就可以用到传址调用
#include <stdio.h>
void Swap2(int*px, int*py)
{
int tmp = 0;
tmp = *px;
*px = *py;
*py = tmp;
}
int main()
{
int a = 0;
int b = 0;
scanf("%d %d", &a, &b);
printf("交换前:a=%d b=%d\n", a, b);
Swap1(&a, &b);
printf("交换后:a=%d b=%d\n", a, b);
return 0;
}
传址调用,可以让函数和主调函数之间建立真正的联系,在函数内部可以修改主调函数中的变量;所以在函数中只是需要主调函数中的变量值来实现计算,就可以采用传值调用。如果函数内部要修改主调函数中的变量的值,就需要传址调用。
7.二级指针
指针变量也是变量,是变量就有地址,指针变量的地址就存放在二级指针中。
*ppa 通过对ppa中的地址进行解引用,这样找到的是pa,*ppa 其实访问的就是 pa。
**ppa 先通过 *ppa 找到 pa ,然后对 pa 进行解引用操作: *pa ,那找到的是 a。
8.数组指针和指针数组
指针数组的每个元素都是⽤来存放地址(指针)的,指针数组的每个元素是地址,⼜可以指向⼀块区域,所以其本质就是数组。
指针数组是⼀种数组,数组中存放的是地址
int (*p)[10];
p先和*结合,说明p是⼀个指针变量变量,然后指着指向的是⼀个大小为10个整型的数组,所以 p是⼀个指针,指向⼀个数组,叫数组指针。
总结
以上就是关于C语言指针的内容,如有错误,欢迎指正,喜欢的话,点个免费的赞,蟹蟹。