C语言 指针


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语言指针的内容,如有错误,欢迎指正,喜欢的话,点个免费的赞,蟹蟹。

  • 59
    点赞
  • 57
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值