您的位置:首页 > 其它

浅谈指针---指针的含义,用法,机器的字节序,指针和数组的关系

2019-03-12 22:34 260 查看

指针初阶

点击此处可以查看一些简单的题目[指针和数组的烧脑题目]
(https://www.geek-share.com/detail/2763454294.html)

-指针定义

指针是编程语言中的一个对象,利用地址,它的值直接指向存在电脑存储器中另一个地方的值,存这个这个值的地方被称作这个值的地址,这个值的地址就是指针,意思是可以通过指针来找到这个值所在的内存单元,然后进而找到这个值具体是多少

- 指针变量

指针是一个变量,用来存放内存单元的地址(编号)

代码演示:

#include <stdio.h>
int main()
{
int a = 1;//在内存中开辟一块空间
int *p = &a;//这里我们对变量a,取出它的地址,可以使用&操作符。
//将a的地址存放在p变量中,p就是一个之指针变量。
printf("*p=%d\np=%p\n&a=%p",*p,p,&a);
return 0;
}

结果为:

注意:int*指的是整形指针变量,*p指的是指针变量解引用,二者中的 *是不同的,第一个代表它是指针变量,第二个代表解引用,指的是求存在指针p这个地址的值
结论:可以明显看出指针变量p和变量a的地址是相同的,所以指针变量就是存放变量的地址(存放在指针中的值都被当作地址来处理)

-指针变量的大小

首先一个字节占8个位,所以在32位的系统上,一个指针变量的大小就是4个字节(32/8=4),在64位系统上,一个指针变量的大小就是8个字节(64/8=8)

- 指针编址的空间

  • 在32位的系统上,指针最多能存储232个地址,也就是4G的空间
    (232=232/1024KB=232/1024/1024MB=232/1024/1024/1024GB=4GB)
  • 在64位的系统上,指针最多能存储264个地址,这个空间就非常大了,目前是用不完的

-指针类型
指针是一个地址,地址里面可以存各种各样的数据,所以相对的地址存的数据是什么类型,那么指针就是什么类型的指针变量

char* p1=NULL;
int* p2=NULL;
short* p3=NUL;
long* p4=NULL;

结论:

  • 指针的定义方式是: type + *
  • char* 类型的指针是为了存放 char 类型变量的地 址。 short* 类型的指针是为了存放 short 类型变量的地址。 int* 类型的指针是为了存放 int 类型变量的 地址。

-指针的解引用

-指针运算

已知存放数据的地址要求求出此地址所存放的数据

代码演示:

#include <stdio.h>
int main()
{
int a = 1;
int *p1 = &a;
char* p2=&a;
printf("*p1=%d\n,*p2=%d",*p1,*p2);
return 0;
}

结果为:*p1=1,*p2=1

总结: 指针的类型决定了,对指针解引用的时候有多大的权限(能操作几个字节)。 比如: char* 的指针解引用 就只能访问一个字节,而 int* 的指针的解引用就能访问四个字节。

这时就会出现一个问题,为什么p2解引用结果是1?按理来说一个整形数字占4个字节解引用也最多解4个字节,所以p1解引用后用16进制表示为00000001,此时将一个整型变量按照字符型变量来解引用,一个字符占1个字节,所以解引用也最多只能解1个字节,那么p2解引用解的存储的数据用16进制表示方式应该是00,可是实际结果却是01,这是为什么?这是因为数据在地址中存储的时候是按小端序(机器的字节序)来存储的

-机器的字节序
假设现在有一个指针变量指向一个16进制的数字a,那么这个数字a在地址中按照字节序的存储会有两种情况

将它赋给一个字符指针变量,如果解引用的结果为a(10进制输出为10),说明它是按照小端序来排列的(0a000000),如果解引用为0,说明他是按照大端序来排列的(0000000a)

结论:

  1. 大端序:低位在高地址上
  2. 小端序:低位在低地址上

-指针±整数
指针加几就是指指针向后跳几个指针类型的长度
指针减几就是指指针向前挑几个指针类型的长度

代码演示:

//指针+整数
#include <stdio.h>
int main()
{
int*p1 = NULL;
p1=p1+1;
int* p2=NULL;
p2=p2+2;
printf("p1=%d\n,p2=%d\n",p1,p2);
return 0;
}

结果为:p1=4,p2=8

//指针-整数
#include <stdio.h>
int main()
{
double*p1 = 20;
p1=p1-1;
double* p2=20;
p2=p2-2;
printf("p1=%d\n,p2=%d\n",p1,p2);
return 0;
}

结果为:p1=12,p2=4
原因:p1-1就是前跳1个double类型的长度,所以为12(20-8=12),p1-2就是向前跳2个double类型的长度(20-16=4)
结论::指针的类型决定了指针向前或者向后走一步有多大(距离)

-指针-指针
实质:两个指针之间隔了多少个元素
代码演示:

#include<stdio.h>
int Strlen(char* str)
{
char* p=str;
while(*p!='\0')
++p;
return p-str;
}
int main()
{
char str[]="hello,world";
printf("字符串的实际长度为%d\n",Strlen(str));
return 0;
}

结果为:字符串的实际长度为:11
原因:利用p得出当p指向\0的时候的地址,再减去str的首地址,结果为11,正好是两个指针之间隔得元素个数

-指针和数组

  1. 指针和数组名
    我们知道数组名在做函数的参数的时候会隐式转换为指针,而这种转换不止会体现在数组名作参数的时候,当数组名加减一个整数的时候数组名也会隐式转换为指针
    代码演示:

    #include <stdio.h>
    int main()
    {
    int arr[] = {1,2,3,4,5};
    printf("%p\n", arr);
    printf("%p\n", arr+1);
    return 0;
    }

结果为:

可以看出此时arr和arr+1都被因式转换为了指针,arr指向数组元素1,arr+1指向数组元素2

当数组名做指针的时候会隐式转换成为指针,那么arr,&arr[0]以及&arr有什么区别呢?
代码演示:

#include <stdio.h>
int main()
{
int arr[] = {1,2,3,4,5};
printf("arr=%p\n&arr[0]=%p\n&arr=%p\n", arr,&arr[0],&arr);
return 0;
}

结果为:

可以看出arr,&arr[0],&arr它们在数值上没有任何区别,但是实际上他们真的没有区别吗?看下面的代码
代码演示:

#include <stdio.h>
int main()
{
int arr[] = {1,2,3,4,5};
printf("arr=%p\n&arr[0]=%p\n&arr=%p\n", arr,&arr[0],&arr);
printf("\n");
printf("arr+1=    %p\n&arr[0]+1=%p\n&arr+1=   %p\n", arr+1, &arr[0]+1, &
27d98
;arr+1);
return 0;
}

结果为:

此时可以看出arr+1和&arr[0]+1的地址还是相同的,但是&arr+1的地址却不在和他俩相同,比他俩要大16个字节,也就说相差了4个元素
原因:arr在隐式转换成为指针之后会指向数组的首元素,是数组首元素的地址,而&arr[0]也是数组首元素的地址所以它们俩是完全相同的,但是&arr,是数组指针,指的是整个数组的地址,指向的是整个数组的数据,只不过恰好数组的地址用数组的首元素来表示,所以&arr的数值也和它们俩相等,但仅仅是数值,实际的意义是不同的,所以在都加1之后arr+1和&arr[0]+1,都指向了数组的第二个元素2,而&arr+1由于指针+1要跳过它1个指针类型的数据,所以它要跳过整个数组,所以此时&arr+1可以说是指向了5后面的一个数据和数组元素2正好差了4个元素

  1. 指针和数组
    数组名既然可以当做地址存在指针里面,那我们也就可以通过对指针(数组名)的解引用来访问数组的元素
    代码演示:

    int main()
    {
    int arr[] = { 1, 2, 3, 4, 5};
    int *p = arr; //指针存放数组首元素的地址
    int sz = sizeof(arr) / sizeof(arr[0]);
    int i = 0;
    //值的比较
    for (i = 0; i<sz; i++)
    {
    printf("*(p+%d)=%d<===>arr[%d]=%d\n", i,*(p + i),i,arr[i]);
    }
    //地址的比较
    for (i = 0; i<sz; i++)
    {
    printf("p+%d=%p<===>&arr[%d]=%p\n", i,p+i,i,&arr[i]);
    }
    return 0;
    }

    结果为:

    可以看出p+i解引用的值就是arr下标为i解引用的值;p+i的地址就是arr下标为i的地址

-二级指针
既然指针变量是一个地址,用来存放变量的值,那么指针变量也是一个变量,那指针变量的地址就被称作二级指针
图示:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: