C/C++指针详解

  1. 基础概念
  2. 套娃
  3. 数组,指针,符号含义
  4. 内存概念以及管理

指针

基础概念

    1. 1个字节就会有一个内存首地址,1个字节就是一个内存块.取地址专指取内存块的首地址.内存的最小单位就是1个字节.内存块:存储的就是值,例如20,”1111”等可以让我们直接使用的值;
    1. 变量定义时即分配内存,按照类型分配内存大小.
         char ch;//这个写法就在内存里面分配了1字节的大小,是在运行时已经分配了,但是没有用到而已,分配到哪里也不需要用户关心.
         int a;//分配4字节
    1. 内存首地址:存储的就是类似于一个数组的下标,只不过这个下标被编译器定义了,编译器定义它,不告诉你,但是你要知道它最大(指针的大小)就是32位或者64位,32位机器使用4字节存储指针,64位机器使用8字节存储指针.
    1. 内存首地址不是存储在内存块里面的,是CPU总线计算出来的,按照十进制表示:一般是 0-2的多少次方大小;可以使用十进制,二进制,八进制,十六进制表示.每次取地址,就计算出来这个内存首地址;内存块里面也可以存储内存首地址(也就是指针),因为内存首地址可以用十进制表示,也就是说指针是个十进制的数字而已,没有特别神奇的存储格式,仅仅是指针的含义与规则比较特殊.
    1. 可以根据内存首地址找到对应的内存块,叫做寻址;*p(寻址)操作的是内存首地址(指针)所指向的内存块
    1. 要把 char /int /float 等等 和 char* /int* /float* 等等类型看作是数据类型即可,int* 这个类型的优先级大于 int 的优先级
    1. ‘ * ‘号的意义

      1,定义变量时,’ * ‘ 代表的是类型(例如: int* p = 0x2498;p 就是指针类型 int* ,int是类型,int* 也是类型)
      2,在使用变量时,代表操作指针所指向的内存.意思就是 *p 指向的就是p指针变量存储的内存首地址的内存块的值.
      3,’ * ‘号在等号左边(int
      p = 0xxxx;)表示在定义一块内存,’ * ‘号操作必须操作指针变量,类型+’‘表示一个整体
      4,’ * ‘号在等号右边,表示在操作内存块里面的值,哪个内存块,取决于指针变量里面存储的指针的值.
      +指针变量表示一个整体

    1. & 符号表示什么,如果&在指针变量之前表示什么,如果&在变量之前表示什么
    1. 变量:变量只要定义,就会分配这个变量所对应的内存首地址以及内存块,如果没有赋值,则内存块里面没有值而已,但是内存首地址一定是被分配了而且存在的.
    1. 指针:指针变量的值,就是内存首地址
    1. 指针变量:存储指针的一个变量,和普通变量一样
    1. 野指针:这个指针变量保存了一个没有意义(非法)的内存首地址,对野指针变量本身进行赋值,修改等没有问题,但是一旦对指针变量的值进行取地址操作,就会出现问题,因为是非法的.
    1. 空指针:给指针变量赋值位NULL,NULL就是个0.
    1. 万能指针使用的时候,需要将其转换为本身类型才能使用,例如 void* 转为 int* 才能使用
    1. 指针运算是和其类型相关的,加减乘除的时候都要附加类型大小才可以
    1. 数组的变量本身就是个内存首地址,int a[10]; a 本身就是个内存首地址 ; 所以 int* p = a; 是没有问题的
    1. 只要是指针 * 与 [] 对于取值是一个意思. *(p + i) 与 p[i] 是相等的,也就是 *(p+i) = p[i]

套娃

  • 只要记住,内存首地址是 &变量 ,并且只能获取值 ;内存块是 *变量 可以获取值,也可以赋予值;内存首地址本质是纯数字;内存块本质也是纯数字,但是有其他表现形式;

  • 一级套娃

    int a;
    int* p = &a; 
  • 二级套娃

    int a;
    int* p = &a; 
    int** q = &p; 
    
* 三级套娃

int a;
int* p = &a;
int** q = &p;
int*** w = &q;

* 多级套娃

int a;
int* p = &a;
int** q = &p;
int* w = &q;
int**
e = &w;


# 函数传参
* 1. 函数传参都是将变量内存块里面的值拷贝一份传输过去,指针(内存首地址)拷贝一份,就能连接到函数内与函数外的数据,就会方便很多.
下面是错误例子:
    //void printf_Array(int *a) //2种写法等价,对编译器而言,没有任何区别,编译器都是当作 int * 类型处理
    void printf_Array(int a[])
    {
            for (size_t i = 0; i < sizeof(a) / sizeof(a[0]); i++) {
                    printf("%d,", a[i]);
            }
            printf("\n");
    }
    int array[] = {  7, 79, 465,  65, -345, -346, 798, 1, 0, 45 };
    printf_Array(array);
    //这个地方传输的是a这个变量内存块里面的值,也就是数组第一个元素的内存首地址,而不是整个数组
    //形参中的数组根本就不是数组,就是一个指针变量(内存首地址)
正确的例子是:
    void printf_Array(int *array,int length)
    {
            for (int i = 0; i < length; i++) {
                    printf("%d,", array[i]);
            }
            printf("\n");
    }
    int array[] = {  7, 79, 465,  65, -345, -346, 798, 1, 0, 45 };
    printf_Array(array,(sizeof(array) / sizeof(array[0])));
>结论:数组在作为函数的形参传递过程中,需要传递首地址,还要传递数组长度,函数才可以正确将数组解析出来.
> 1. 形参中的数组不是数组,是普通的指针变量
> 2. 形参数组: int a[10000],int a[],int * a,对编译器没有区别,编译器都是当作 int * 类型来处理
> 3. 形参中的数组和非形参中的数组的区别:形参中的数组是指针变量,非形参数组就是数组

* 2. 二维数组不是二级指针,指针数组才是二级指针

# 指针数组和数组指针

* 1. 指针数组,是数组,里面每个元素是指针.写法:

char* a; char a[];//这个叫做指针数组,不是叫做二维数组

* 2. 数组指针,是指针,指向数组的指针.
* 3. 指针函数,是函数;错误案例,代码会直接报错,因为pointer_Function执行完毕会释放里面的变量,指针指向的值也被回收了,然后指针就指向了一个空的内存首地址,指针指向了 NULL,变成了空指针:

int * pointer_Function()
{
int a = 200;
return &a;
}
void paFunction3()
{
int* pf = pointer_Function();
printf(“当前指针的内存首地址%p 当前指针内存块的值:%p 当前指针内存块所指向的内存的值:%d\n”,&pf,pf,*pf);
}


* 4. 函数指针,是指针

* 5. 字符指针,这个是比较特殊的

char str[] = “hello”;
printf(“%s\n”,str);//里面是重写了输出方法
//是下面的输出方式
int i = 0;
while(str[i]!= ‘\0’)
{
printf(“c”,str[i]);
i++;
}
//str本身还是首元素的内存首地址,只是输出比较特殊而已.本质还是个指针
char buf[100];
char* p = buf;

strcpy(p,”wqrywegw”);//不是给p本身拷贝内容,而是给p指向的内存块拷贝内容.



# 字符串结束符

0 数字0 与 '\0' 在字符串中是一样的,都是结束符
'\0' accsi 的结束符,与数字0在字符串中是一样的
'0' 字符0 ,在accsi中的数字表示是 48

char a[] = {'a','b'};
printf("%s",a);//乱码,没有结束符

char a[10] = {'a','b'};
printf("%s",a);//正常,自动补0

char a[] = {'a','b',0};
char a[] = {'a','b','\0'};
printf("%s",a);//正常

char a[] = {'a','b''0'};
printf("%s",a);//乱码,没有结束符

char buf[] = "hello";
printf("%s",buf);//正常,以字符串初始化,自动隐藏结束符'\0'

# 字符常量和字符指针数组
    void fun()
    {
             printf("%p\n","aaa");
    }
    printf("%p\n","aaa");
    printf("%p\n","aaa");
    fun();
    printf("%s\n","aaa"+1);//这种写法是正常的,因为这是将"aaa"当成内存首地址来使用的,类型是 char
    printf("%c\n",*("aaa"));//取出首元素
    //上面打印的地址都是一样的,所有的"aaa"就是字符常量,放在内存中的data区域,字符常量区

    char buf[] = "aaa";//这个字符数组所指向的字符串,并没有放在data区域,而是在栈里面
    char *p1 = "hello";//这个是字符常量,值是不可以被修改的
    char buf[] = "hello";//这个是字符指针数组,值是可以被修改的
    char p1[100]= "hello";//正确
    p1 = "hello";//错误
    char p2[100];p2="hello";//错误,因为数组名是常量.
    char p3[100];strcpy(p3,"hello");等价于 char p1[100]= "hello";

```

数组,指针,符号含义

    1. 使用 *p , *(p+0), p[0] 都是代表了取出内存块里面的值, *(p+1)表示: *(指针运算),这都是表达的我要直接操作内存块,而不是操作指针(内存首地址)
    1. 使用 p+0 等运算,都是对指针 p ,内存首地址进行的运算,
    1. 一维数组的三种操作方式

                 //数组有3种操作方式
                 struct Student s[3] ={};
                 //直接操作内存块
                 s[0].age = 15;
                 strcpy(s[0].name, "mike");
                 s[0].score = 15;
                 //直接操作内存块
                 (*(s+1)).age = 15;
                 strcpy((*(s+1)).name, "mike");
                 (*(s+1)).score = 15;
      
                 //操作内存首地址
                 (s+2)->age = 15;
                 strcpy((s+2)->name, "mike");
                 (s+2)->score = 15;
      
                 //指针的写法
                 struct Student * p = &s[0];// = s; 2种写法一个意思
                 //直接操作内存块
                 p[0].age = 15;
                 strcpy(p[0].name, "mike");
                 p[0].score = 15;
                 //直接操作内存块
                 (*(p+1)).age = 15;
                 strcpy((*(p+1)).name, "mike");
                 (*(p+1)).score = 15;
      
                 //操作内存首地址
                 (p+2)->age = 15;
                 strcpy((p+2)->name, "mike");
                 (p+2)->score = 15;

内存概念以及管理

    1. 简单的 int a; 这句代码已经被分配了内存首地址与内存块,而不是单纯的什么都没有.
    1. 简单的 int* p; 这句代码种 int* 合起来是一种类型,也已经分配了内存首地址与内存块,只不过内存首地址是指针变量p的内存首地址,内存块是保存指针地址(内存首地址),无法保存其他类型(int float struct … 的值).

转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 1487842110@qq.com

Love

Title:C/C++指针详解

文章字数:2.7k

Author:诸子百家-谁的天下?

Created At:2020-05-08, 11:41:32

Updated At:2021-03-28, 02:59:27

Url:http://yoursite.com/2020/05/08/Pointer/%E6%8C%87%E9%92%88/

Copyright: "署名-非商用-相同方式共享 4.0" 转载请保留原文链接及作者。

目录
×

爱你,爱世人