指针的深度理解(1)

指针初概念

首先我们要先理解指针的概念,我们都知道CPU处理数据时,需要的数据是从内存中读取的,内存有8GB  16GB  32GB等,那么我们要知道GB是一个大的单位,但内存也分为一个个内存单元,每个内存单元取一个字(byte),一个字节又等于8个比特位(bit),一个比特位可以储存2进制的0或1,计算机中内存单元都有一个编号,C语言中把这个地址也叫做指针!我们也可以这么理解:

内存单元的编号==地址==指针

下面我们来讲解

指针变量和取地址操作符(&)解引用操作符(*)

指针变量其实就是我们平常说的指针,那指针变量用来干嘛呢,答案是用来储存地址的,这时我们要想将一个地址存到指针变量中,我能便需要用到取地址操作符“&”,大家可以看下面代码:

#include
int main()
{
	int i = 10;
	int* pa = &i;
	printf("%p", pa);

	return 0;

这样一看就知道i的地址已经储存在指针变量pa上了。


需要注意的是指针变量也是一种变量,它的大小在32位机器中指针变量占4个字节,64位机器中占8个字节!由于地址线的不一样指针变量的大小就会有所不一样,我们可以看下面代码:

#include
int main()
{
	int i = 10;
	int* pa = &i;
	printf("%d", sizeof(pa));
	return 0;
}


现在来讲讲解引用操作符“*”的作用,计算机方面知识比较抽象,我们可以通过类比现实例子:好比在现实生活中我们可以使用一个地址去到一个房间里拿存放的东西,指针也一样,我们也可以通过指针找到里面的东西那么,“*” 就可以理解为动词“找”。下面用代码来给大家看一下:

#include
int main()
{
	int i = 10;
	int* pa = &i;
	printf("%d", *pa);
	return 0;
}

如上面可以看出*pa打印出来是10也就是原本给i赋的值!若果想改变i的值也可以通过指针变量来改变

#include
int main()
{
	int i = 10;
	int* pa = &i;
	*pa = 20;
	printf("%d", *pa);
	return 0;
}


下面我们在来讲讲“指针的类型“

指针的类型

指针类型无非就是相当我们之前学过的类型后加个“*”号,例如:

char*    int*     float*     long*等等

那么我们可以很容易想到int类型的地址就放到int*类型的指针变量里去,当然如果你非要把int类型的地址放到char*那里去,只要进行类型强制转换后,也是可以的,但是,当你对指针进行操作时那么就会出现偏差了!下面看一下例子:

这是指针变量存放对应的变量地址时改变内容时i的内存变化:

#include
int main()
{
	int i = 0x00112233;
	int* pa = &i;
	*pa = 1;
	printf("%d", *pa);
	return 0;
}

这是将int i的地址放到char* pa指针变量上的情况

#include
int main()
{
	int i = 0x00112233;
	char* pa = &i;
	*pa = 1;
	printf("%d", *pa);
	return 0;
}

通过这个代码我们可以理解,指针类型就是代表步数的跳过不一样,int*类型的指针变量进行+1,便是跳过4个字节去访问下一个地址。char*类型的指针变量如果进行+1,便是跳过个字节去访问下一个地址。这说明int*指针解引用只能访问一个字节,int*指针解引用就能访问4个字节,竟然这么讲那么float和int类型变量都是占4个字节,那么他们的指针是不是就没有区别呢,答案肯定是否定的,既然指针变量的类型有区别,那么他们的作用肯定是不一样的,那么它们两有啥不一样呢——其实就是他们两在内存单元中的储存方式是不一样的,操作起来时某些地方肯定是会出现偏差的。


const修饰指针:

我们都知道变量是可以被修改的,如果把一个变量的地址交给一个指针变量,通过指针也可以修改这个变量,但如果我们希望通过指针变量不能被修改呢,这时const的作用就体现出来了,下面写几个代码,让大家更好理解:指针的深度理解(1)_第1张图片

指针的深度理解(1)_第2张图片

这里注意编译器下方有红波浪线的地方便得出下面结论:

const在*的左右两边效果是不一样的

  • const如果放在*的左边,修饰的是指针指向的内容,保证了指针指向的内容不能够通过指针来改变,但是指针变量本身的内容可变(即它可以存放另一个变量的地址)

const如果放在*的右边,修饰的是指针变量本身,保证了指针变量内容不能被修改,但是指针变量指向的内容,可以通过指针改变。


野指针:

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

野指针生成的原因有:

  • 指针未初始化
#include 
int main()
{ 
 int *p;//局部变量指针未初始化,默认为随机值
 *p = 20;
 return 0;
}
  • 指针越界访问
#include
int main()
{
int arr[5] = {0};
 int *p = &arr[0];
 int i = 0;
 for(i=0; i<=10; i++)
 {
 //当指针指向的范围超出数组arr的范围时,p就是野指针
 *p++ = i;
 }
 return 0;
}
  • 指针指向空间释放
#include 
int* test()
{
 int n = 100;
 return &n;
}
int main()
{
 int*p = test();
 printf("%d\n", *p);
 return 0;
}

野指针在一定程度上会使我们无法正常通过指针变量进行修改所指向对象所以我们要规避野指针,规避的方法有:

  • 指针初始化
  • 避免指针越界
  • 指针变量不再使用时,及时置NULL,使用之前检查有效性

指针的运算:

  • 指针加减整数
#include
int main()
{
 int arr[10] = {1,2,3,4,5,6,7,8,9,10};
 int *p = &arr[0];
 int i = 0;
 int n = sizeof(arr)/sizeof(arr[0]);
 for(i=0; i

指针加减整数即在一连串的地址中往后或往前指向另一个地址,就如上数组中每个下标对应的数组元素会有各自的地址且连在一起 :

  • 指针减指针

指针减指针就可以理解为为同一块区域内的的两个指针的距离:

#include
int main()
{
	int arr[10] = { 0 };
	int* i = &arr[0];
	int* j = &arr[9];
	printf("%d", j - i);
	return 0;
}

这样就可以证明上述所说。通过这个知识我们便可自己写一个stren函数如下: 

#include 
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
}

指针的关系运算

指针的关系运算可以用一个数组理解为,后面元素的地址大于前面的地址,如下地址4是比前面3个地址都要打的:

对于这个知识点我们可以看下面的代码理解与之前大家创建另一个变量进行 i

#include 
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]);
 while(p


好了各位今天指针(1)先讲到这了,下期会有指针更多的·实际使用哦!喜欢的话可以关注期待哦

指针的深度理解(1)_第3张图片

你可能感兴趣的:(c#,c语言)