指针知识点笔记(1)

***内存和地址
1.你可以把它想作每一栋楼里都有一个专属的房间号,按照房间号就可以找到对应的一个人

2.同样,内存的使用和管理:把内存划分为⼀个个的内存单元,每个内存单元的⼤⼩取1个字节

3.计算机中的单位:

*⼀个⽐特位可以存储⼀个2进制的位1或者0

1Byte(字节) = 8bit(比特)

1KB = 1024Byte

1MB = 1024KB

1GB = 1024MB

1TB = 1024GB

1PB = 1024TB

常用的就是上面的,还有其他感兴趣可以去查查

4.计算机中:内存单元的编号----也称为地址----也叫做指针

5.数据是通过数据总线接互的,地址是通过地址总线接互的

6.CPU和内存之间也是有⼤量的数据交互的,所以,两者必须也⽤线连起来,其中一组线叫地址总线
7地址信息被下达给内存,在内存上,就可以找到该地址对应的数据,将数据在通过数据总线传⼊CPU内寄存器。

***指针变量和地址

1.&取地址操作符

如果有一个值a,取地址后,a所占的就是字节在地址最小的字节地址,知道了第一个地址,剩下的有顺其自然知道了。

eg:打印出的值就是四个字节中最小的地址

#include<stdio.h>
int main()
{
  int a=10;
  &a;
  printf("%d",&a);

}

2.指针变量和解引⽤操作符(*)

1)指针变量:取地址值后存在的地方

#include<stdio.h>
int main()
{
  int a=10;
  int* pa=&a;


  return 0;
}

pa是一个变量,是用来存放地址(指针)的

*表示的是说明pa是指针变量

int表示pa指向的变量a的类型的int

同样char类型:

eg:char ch='w';
-->char * pc=&ch  ---注意一定要记得&这个符号(初学容易忘记)

为什么要加?指针放的是地址,所以初始化时有&符号

3.解引用操作符*

作用:将地址保存起来,未来是要使⽤的

区别:
a&b是按位与
&a是取地址
a*b乘法
*a      //a是指针变量,*就是解引用操作符

#include<stdio.h>
int main()
{

  int a=10;
  int* pa=&a;
  *pa=20;

  return 0;
}

这样就可以将a从原来的10变成了20

4.指针变量的大小

32位平台下地址是32个bit位,指针变量⼤⼩是4个字节 (vs中x86)

• 64位平台下地址是64个bit位,指针变量⼤⼩是8个字节(vs中x64)

注意指针变量的⼤⼩和类型是⽆关的,只要指针类型的变量,在相同的平台下,⼤⼩都是相同的

5.指针的解引用

#include<stdio.h>
{
  int a=0x11223344;
  int* pa=&a;
  *pa=5;

  return 0;
}

一个16进制位占4个二进制位
两个16就是8个二进制位,8个一个字节
这样就填满了

结论:指针的类型决定了,对指针解引⽤的时候有多⼤的权限(⼀次能操作⼏个字节)。

⽐如: char* 的指针解引⽤就只能访问⼀个字节,⽽ int* 的指针的解引⽤就能访问四个字节

6.指针+-整数

解引用决定了我们通过地址访问这个元素的时候怎么访问
而加一减一是通过向后偏移,这样我们只要找到这一个位置
空间的起始位置来顺藤摸瓜来找到那个元素

结论:指针的类型决定了指针向前或者向后⾛⼀步有多⼤(距离)。
int* +1----跳动4个字节

char* +1---跳动1个字节

eg:

int* pa:  pa+1----> +1*sizeof(int)
          pa+n-----> +n*sizeof(int)  

char* pa:pa+1----> +1*sizeof(char)
        pa+n-----> +n*sizeof(char)

7.void* 指针

⽆具体类型的指针(也称泛型指针)

注意::void*不可以进行指针+-整数

#include <stdio.h>
int main()
{
 int a=10;
 void* pa=&a;
 *pa=20   //这样是错误的
  

 return 0;
}

8.const 修饰指针

变量的地址交给⼀个指针变量,加上后就不可以被修改

9.const修饰指针变量
这分为3种情况:*放左边,右边,两边?

int const * p; 左边

int * const p; 右边

int const * const p 两边


在此之前,我们先搞清:关于指针p有3个相关的值
1.p,p里边放着一个地址
2.*p,p指向的那个对象
3.&p,表示的是p变量的地址

放左边:

#include <stdio.h>
//代码2 - 测试const放在*的左边情况
void test1()
{
 int n = 10;
 int m = 20;
 int const *p = &n;
 *p = 20;//不可以
 p = &m; //ok,可以执行
}

放右边:

#include <stdio.h>
//代码2 - 测试const放在*的右边情况
void test1()
{
 int n = 10;
 int m = 20;
 int *const p  = &n;
 *p = 20;//可以
 p = &m; //不可以执行
}

两边

#include <stdio.h>
//代码2 - 测试const放在*的两边情况
void test1()
{
 int n = 10;
 int m = 20;
 int const *const p = &n;
 *p = 20;//不可以
 p = &m; //不可以执行
}

总结:(这里好绕啊啊啊啊啊,比较难分清,谁能更加清晰的理解啊啊)

.const如果放在*的左边,修饰的是指针指向的内容(*p),保证指针指向的内容(p=&m)不能通过指针来改变。

但是指针变量本⾝的内容可变(p=&m)。

• const如果放在*的右边,修饰的是指针变量本⾝,保证了指针变量的内容(p=&m)不能修改,但是指针指向的内容(*p),可以通过指针改变。

两边都不可以

10.指针的+-整数

1)因为数组在内存中是连续存放的,只要知道第⼀个元素的地址,顺藤摸⽠就能找到后⾯的所有元素
2)指针类型决定了指针+1的步长决定了指针解引用的权限
3)数组在内存中是连续的~

#include<stdio.h>
int main()
{
 int arr[10]={1,2,3,4,5,6,7,8,9,10};
 int *p=&arr[0];
 int sz=sizeof(arr)/sizeof(arr[0]);
 int i=0; 
 for(i=0;i<sz;i++)
   { 
     printf("%d",*(p+i));


   }

 return 0;
}

11.指针-指针

指针-指针的绝对值是指针和指针之间元素的个数

指针-指针,计算的前提条件是两个指针指向的是同一个空间

eg:*p=arr1[];

     *b=arr2[];

      *p-*b      这种是不可以的

strlen其实统计的是字符串中\0之前的字符个数

数组名其实是数组首个元素的地址 arr=&arr[0]

12.野指针

1)野指针就是指针指向的位置是不可知的(随机的、不正确的、没有明确限制的)

2)成因:p是局部变量,但是没有初始化,其值是随机值的,如果
将p在存放的值当作地址,解引用操作符就会形成非法访问

3)如何避免:如果明确知道指针指向哪⾥就直接赋值地址,如果不知道指针应该指向哪⾥,可以给指针赋值NULL

4)针变量不再使⽤时,及时置NULL,指针使⽤之前检查有效性

俗成规定:只要是NULL指针就不去访问,同时使⽤指针之前可以判断指针是否为NULL。

13.assert 断⾔

1)使用时要assert.h 头⽂件

⽤于在运⾏时确保程序符合指定条件,如果不符合,就报错终⽌运⾏。这个宏常常被称为“断⾔”。

2)还有⼀种⽆需更改代码就能开启或关闭 assert() 的机制。如果已经确认程序没有问

题,不需要再做断⾔,就在 #include <assert.h> 语句的前⾯,定义⼀个宏 NDEBUG 。

#define NDEBUG
#include <assert.h>

14.传值调⽤和传址调⽤

结论:实参传递给形参的时候,形参会单独创建⼀份临时空间来接收实参,对形参的修改不影响实参
传址调⽤,可以让函数和主调函数之间建⽴真正的联系,在函数内部可以修改主调函数中的变量;只是需要主调函数中的变量值来实现计算,就可以采⽤传值调⽤。

如果函数内部要修改主调函数中的变量的值,就需要传址调⽤。
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值