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

指针初阶

点击此处可以查看一些简单的题目[指针和数组的烧脑题目]
(https://blog.****.net/wang_yiduo/article/details/88530349)

-指针定义

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

- 指针变量

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

代码演示:

#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, &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的地址

-二级指针
既然指针变量是一个地址,用来存放变量的值,那么指针变量也是一个变量,那指针变量的地址就被称作二级指针
图示:
浅谈指针---指针的含义,用法,机器的字节序,指针和数组的关系