从这一节开始,我们就要开启学习指针之旅,我将此次指针的学习分为5次,今天是第一次学习,在学习指针的时候我们必定会遇到许多困难与挑战,我们会遇到一些比较抽象的概念,也会遇到一些复杂的代码,不管如何,我们能做的只有坚持,坚持只有这样,我们才可以真正搞懂所谓的指针,明白指针的确实含义,来开启我们今天的指针学习吧,亲爱的同学们!

C语言指针篇第一

首先呢,我将为大家介绍有关地址的知识点,接下来我们会学习到指针的运算,以及使用。

1. 内存和地址

1.内存与地址的介绍

1.在宾馆当中,我们若果需要寻找需要的人时,在不知道对方的房间号时,我们能够做的是,一个房间一个房间挨着寻找,虽然这样可以找到我们需要的人,但是需要注意的是。这样寻找,注定了它的效率是不高的,是低效率的,因此呢,若果我们知道对方的房间号时,那么找到对方是一瞬间的事情。 2.在计算机中,信息也是按照宾馆,按照宿舍存储的,在计算机中信息是以字节为单位,这个字节就有点像宿舍,一个宿舍存储8个人,而一个字节有八个比特位,这样只要我们知道信息的房间号,在计算机中我们常说的是地址—-指针—内存单元的编号,我们就可以迅速的找到这个信息。 3.若果在32为环境下,地址是按照32位地址线发出电信号,进行编码的,此时地址拥有32个比特位,也就是说地址有4个字节 4.但是,若果在64位的环境下,那么就是地址按照64个地址线编码的,此时地址拥有64个比特位,也就是说地址现在拥有,8个字节。

2.地址的一些性质

1.首先,在相同环境之下,地址的大小都是一样,要么是4个字节,要么是8个字节,这个同地址(指针)的类型是无关的。 2. 指针是有类型的,有字符型,整型,数组类型。 3. 在计算机存储当中时,是按照字节进行存储的,整型的话是4个字节,字符型是一个字节。

2. 指针变量和地址

以下我们即将学到,操作符&,以及解引用操作符*,以及我们会学习到,指针的大小如何比较,下面就开启我们的学习之旅吧!

1.取地址操作符(&)

首先呢,我们举一个例子:

int a=12;
int * pr=&a;

在上例中,我们可以看到,按位与操作符加在变量之前就变成了,取地址操作符,通过以上代码,我们可以发现,我们使用了指针变量加以接收,a的地址,现在把a的地址就存储到pr当中了,通过上例的举出,大家对于取地址操作符,有新的了解与认识吗?似乎,没有非常的困难的样子,下面我就为大家开启以下的重头戏,上面只是本个知识点的开胃菜,下面才是真正的硬菜。

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

在下面我即将会学习到,解引用操作符以及指针变量,这个我希望大家可以认真,听我的讲解,来开启这个知识点的学习吧!

1.指针变量

1.指针变量的含义

1.当大家首次听到这个名字的时候,会发生疑惑,指针变量不是接收地址,而地址在内存当中不是一样的吗?其实对于这样的想法,我想说,你说的并没有问题,只是由于,不同类型的地址,他们的指针宽度是不同的,因此不能胡子眉毛一把抓,我们在此处定义了指针变量有字符型,整型,数组类型,函数类型,等等。

2.指针变量的意义

1.由于我们拥有了指针变量,那么的话,它就可以存储我们的地址,这样地址就存储在指针变量当中,这大概就是指针变量的含义。

2.解引⽤操作符(*)

1.解引用操作符的含义

解引用操作符是当地址存储在指针变量当中之时,我们需要操纵这个地址上面的东西,这个时候我们就用到了解引用操作符,给大家举例子如下:

int a=12;
int * pr=&a;
*pr=3;
2.理解指针变量

给大家举出例子如下:

int w=18;
int * a=&w;

在这里呢,*a代表的是,该变量是指针变量而其前面的int 则表示的是,指针的类型是整型,如此我相信大家,可以对指针变量有着深厚的理解。

3.解引用操作符的意义

通过以上例子,我们可以发现通过解引用,我们就非常的容易对a的地址进行修改,这样解引用就不仅可以得到与原来的变脸一样的变量,同时由于其是对地址的解引用那么的话,同时可以对原变量进行远程修改,这一点是极其重要的。

3.指针变量的⼤⼩

指针变量的大小,在我的上面陈述当中时,我们发现在相同环境下,那么指针变量的大小就是一样的,假设在32位的环境之下,那么指针变量的大小都是4个字节;若是在64位的环境之下的话,那么的话,指针变量的大小就是8个字节,给大家举出例子如下:

#include <stdio.h>
//指针变量的⼤⼩取决于地址的⼤⼩
//32位平台下地址是32个bit位(即4个字节)
//64位平台下地址是64个bit位(即8个字节)
int main()
{
 printf("%zd\n", sizeof(char *));
 printf("%zd\n", sizeof(short *));
 printf("%zd\n", sizeof(int *));
 printf("%zd\n", sizeof(double *));
 return 0; }

如下是在32位环境下运行的结果: 在这里插入图片描述 由此呢,我相信大家一定会明白指针的大小是相同的,只要是在相同的环境之下,下面我们就开启关于变量的类型的意义的学习。

3. 指针变量类型的意义

1.指针变量类型的含义

我们需要知道一个东西,是指针的步长,也就是指针的宽度,是指针向后移动一个则实际在内存上移动多少个字节。

2.指针变量类型的举例

指针变量的类型有字符型,整型,他们的步长分别是1,4。

3. 指针变量类型的意义

首先我们举出例子如下:

#include <stdio.h>
int main()
{
 int n = 0x11223344;
 int *pi = &n;
 *pi = 0;
 return 0;
 }

1.在这里,由于指针变量的类型与变量的类型都是整型那么的话,所得出的答案,就是整型a的4个字节全部都是0.

#include <stdio.h>
int main()
{
int n = 0x11223344;
char *pc = (char *)&n;
*pc = 0;
return 0;
 }

2.在这里,由于指针变量的类型是字符型与变量的类型是整型那么的话,所得出的答案,就是整型a的4个字节中的一个字节是0. 3.通过上述例子我们看出,指针的类型对于解引用的权限是相关的,需要注意的是void * 可以接收任何的地址类型,但是不能对void 类型的指针进行解引用,因为它的步长我们无法得知。

4. const修饰指针

1.const修饰变量(1)

若果我们不想要变量被修改的话,那么我们需要在变量的前面加上const,这样变量就不能通过直接的方式修改了,我给大家举出的例子如下:

const int a=90;
a=98;

那么由于我们在变量的前面加上了const那么变量是无法修改的,在程序运行的时候必然会报错。

2.const修饰变量(2)

1.我们在上述的例子中发现加上一句const这句话,这样便无法被修改了,但是我们可以采用间接的方法进行修改,举出的例子如下:

const int a=90;
int * b=&a;
*b=98;

2.由于const修饰的是,变量a那么它的地址就没有被修饰,如此我们就可以采用地址的方式修改原来的地址,我们加上const这句话的目的是不要修改原来的变量,但是它被修改了,这不是我们需要的代码,是不正确的,因此我们通过以下的方式,对地址加上const那么就可以,规避这些问题了。

3.const修饰指针

const修饰指针,可以通过加在指针的前面或者后面加以取得不同的结果,取得不同的修饰的后果。

1.const加在*的前面

1.这样修饰的是指针指向的内容,保证指针指向的内容不能通过指针来改变。 但是指针变量本⾝的内容可变。 给大家举出的例子如下:

void test2()
{
 //代码2
 int n = 10;
 int m = 20;
 const int* p = &n;
 *p = 20;//ok?
 p = &m; //ok?
}

2.在这里由于指针指向的内容不能通过指针来改变,那么*p=20是错误的,在系统运行的时候会报错,但是由于指针变量本⾝的内容可变,那么的话,p = &m是没有问题的。

2.const加在*的后面

1.这样修饰的是是指针变量本⾝,保证了指针变量的内容不能修改,但是指针指 向的内容,可以通过指针改变。 给大家举出的例子如下:

void test3()
{
 int n = 10;
 int m = 20;
 int *const p = &n;
 *p = 20; //ok?
 p = &m; //ok?
}

2.在这里由于指针变量的内容不能修改,那么 p = &m; 是错误的,在系统运行的时候会报错,但是指针指 向的内容,可以通过指针改变,那么的话,*p = 20是没有问题的。

5. 指针运算

1.指针-指针

指针-指针是指针之间的元素的个数,给大家举出例子如下:

#include <stdio.h>
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;
 }

上述例子当中,由于把首地址存到另一个指针当中,那么两者相减那么就是,字符串的个数

2.指针+(-)整数

是指针移动多少个步长,举出一些例子如下:

#include <stdio.h>
//指针+- 整数
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]);
 for(i=0; i<sz; i++)
 {
 printf("%d ", *(p+i));//p+i 这⾥就是指针+整数
 }
 return 0;
 }

在上面的例子当中,*(p+i)就是每次移动i * 步长个单位,而int类型的指针的步长则是4,那么每次的移动次数就是步长乘以i,以此类推。

6. 野指针

1.野指针是如何造成的

以下是野指针形成的三个成因。

1. 指针未初始化

例子如下:

#include <stdio.h>
int main()
{
 int *p;//局部变量指针未初始化,默认为随机值
 *p = 20;
 return 0;
 }

2. 指针越界访问

例子如下:

#include <stdio.h>
int main()
{
 int arr[10] = {0};
 int *p = &arr[0];
 int i = 0;
 for(i=0; i<=11; i++)
 {
 //当指针指向的范围超出数组arr的范围时,p就是野指针
 *(p++) = i;
 }
 return 0;
 }

3. 指针指向的空间释放

例子如下:

#include <stdio.h>
int* test()
{
 int n = 100;
 return &n;
}
int main()
{
 int*p = test();
 printf("%d\n", *p);
 return 0;
 }

2.如何规避野指针

1.指针初始化 2.⼩⼼指针越界 3.指针变量不再使⽤时,及时置NULL,指针使⽤之前检查有效性 完(结束)