指针

  • 指针

指针是C语言中一个重要的概念也是一个重要的特色。

正确而灵活的运用它,可以有效的表示复杂的数据结构,能动态的分配内存;能方便的使用字符串;有效而方便的使用数组。

掌握指针的应用,可以使程序简洁、紧凑、高效。可以说,不掌握指针就是没有掌握C语言的精华。

7、1地址与指针的概念

为了说清楚什么是指针,必须弄清楚数据在内存中是如何存储的,又是如何读取的。

地址

内存

0

...

 

2000

5

2001

6

2002

7

2003

 

...

...

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

在C语言中,对变量的访问有两种方式,直接访问和间接访问。

直接访问: 如 a=5

  系统在编译的时候,已经对变量分配了地址,例如,若变量分配的地址是2000,则该语句的作用就是把常数5保存在地址为2000的单元中。

间接访问 :scanf(“%d”,&a);

 调用函数的时候,把变量a的地址传递给函数Scanf函数首先把该地址保存到一个单元中,然后把从键盘接收的数据通过所存储的地址保存到a变量中。

7、1、1初识指针

在C语言中,指针是一种特殊的变量,它是存放地址的。假设我们定义了一个指针变量

 int* i_pointer用来存放整型变量i的地址。可以通过语句i_pointer = &i;

7、1、2初识两个操作符

*:叫做取值操作符   

   注意:如果这样写 int *p;则*代表的是指针的定义操作

        如果这样写 int i= 2000;  int *p=&i;  printf(“%d\n”,*p); //此处的*代表的是取值操作。

&:叫做取地址操作符

7、1、3指针与指针变量

知道了一个变量的地址,就可以通过这个地址来访问变量,因此,又把变量的地址称之为该变量的“指针”。

C语言中可以定义一类特殊的变量,这些变量专门用来存放变量的地址,称之为指针变量

注意:指针变量的值(即指针变量中存放的值)是地址(即指针)。请区分“指针”和“指针变量”

7、1、4定义一个指针变量

下面都是合法的定义

float* pointer_3;  //pointer_3是指向float型变量的指针变量

char *pointer_4; //pointer_4是指向字符型变量的指针变量

可以用赋值语句使一个指针变量得到另一个变量的地址,从而使它指向一个该变量。

在定义指针变量的时候要注意两点:

  • 指针变量前面的“*”,表示该变量的类型为指针型变量。其一般形式为:

   类型说明符 *变量名;

  其中,*表示一个指针变量,变量名即为定义的指针变量名,类型说明符表示本指针变量所指向的变量的数据类型。

  例如:float* pointer_1;

   指针变量名是pointer_1,而不是*pointer_1;

  • 在定义指针变量时要注意两点

  需要特别注意的是,只有整型变量的地址才能放到指向整型变量的指针变量中。下面的赋值是错误的。

float a;

int *pointer_1;

Pointer_1=&a;

/*

将float型变量的地址放到指向整型变量的指针变量中,错误*/

7、2对&与“*”运算符再做一些说明

1)如果已经执行了 pointer_1=&a;    int *p=&a;  == int *p;p=&a;

那么&*pointer_1的含义是什么?

&a  a的地址

如果有pointer_2 = &*pointer_1;

它的作用是将&a(a的地址)赋给了pointer_2,如果pointer_2原来指向b,经过重新赋值后它已经不再指向b了,而是指向a.

2)*&a的含义是什么?

a的值

先进行&a运算,得到a的地址,在进行*运算。即&a所指向的变量,也就是变量a。

3)(*pointer_1)++相当于a++

注意括号是必要的,如果没有的话就是按照自右向左的运算规则,从附录可知:++和*为同一优先级。

7、3数组与指针

一个变量有地址,一个数组包含若干个元素,每个数组包含若干元素,每个数组元素都在内存中占用存储单元,它们都有相应的地址。

指针变量既然可以指向变量,当然也可以指向数组元素(把某一个元素的地址放到一个指针变量中)。

7、3、1指向数组元素的指针

 定义一个指向数组元素的指针的变量的方法,与以前介绍的指向变量的指针变量相同。

例如:

int a[10];(定义a为包含10个整型数据的数组)

int *p;(定义p为指向整型变量的指针变量)

应当注意,如果数组为int型,则指针变量的基类型也应该是int型

P=&a[0];

把a[0]元素的地址赋值给指针变量p。

也就是说使p指向a数组的第0号元素。

引用一个数组元素,可以使用

  1. 下标法,例如a[i]形式
  2. 指针法,如*(a+i)或者*(p+i)

其中的a是数组名,P是指向数组元素的指针变量,其初值为p =a;

注意:数组名即“翻译成数组的第一个元素的地址!”

7、3、2用函数名作函数参数

f(int arr[],int n) 但是在编译的时候是将arr按照指针变量处理的,相当于将函数f的首部写成f(int *arr,int n)以上两种写法是等价的。

 

需要说明的是:C语言调用函数的时候虚实结合的方法都是采用“值传递”方式,当用变量名作为函数参数的时候传递的是变量的值,当用数组名作为函数参数的时候,由于数组名代表的是数组首元素地址,因此传递的值是地址,所以要求形参为指针变量。

7、3、3指针做参数

归纳总结:

   如果有一个实参数组,想在函数中改变此数组中的元素的值,实参与形参的对应关系有以下4种情况:(注意:这里要注意形参与实参数组与变量的区别)

  1. 形参和实参都用数组名
  2. 实参采用数组,形参使用指针变量
  3. 实参与形参都是指针变量
  4. 实参为指针变量,形参为数组名

7、4多维数组与指针

用指针变量可以指向一维数组中的元素,也可以指向多维数组中的元素。在概念和使用上,多维数组要复杂一些。

7、4、1多维数组元素的地址

五种方法来确定元素的地址:

int a[][]={};

a,*a,a[0],&a[0],&a[0][0]  这五个表示第一行第一个元素的地址

(说明:*a 的值为数组,因此数组名为第一个元素的地址)

(a+1),*(a+1),a[1],&a[1],&a[1][0] 这五个表示第二行第一个元素的地址

7、4、2指向多维数组元素的指针变量

把二维数组a分解为一维数组a[0],a[1],a[2]之后,设P为指向二维数组的指针变量。

可定义为:int (*p)[4];

它表示p是一个指针变量,它指向包含4个元素的一维数组。若指向第一个一维数组a[0],其值等于a,a[0],或者&a[0][0]等。

 

从前面的分析可以得出*(p+i)+j是二维数组i行j列的元素的地址,而*(*(p+i)+j)则是i行j列元素的值。

 

二维数组指针变量说明的形式为:

类型说明符(*指针变量名)[长度]

其中“类型说明符”为所指的数组的数据类型。“*”表示其后的变量是指针类型。“长度”表示二维数组分解为多个一维数组时,一维数组的长度,也就是二维数组的列数。

7、5字符串与指针

  1. 用字符数组存放一个字符串,然后输出该字符串。

 例题1:定义一个字符数组,对它初始化,然后输出该字符串

  1. 用字符指针指向一个字符串

7、5、1字符串中字符的存取方法

对字符串中字符的存取,可以使用下标的方法,也可以使用指针的方法。

7、5、2用字符指针作函数的参数

【存储的说明】在C/C++中,内存分成5个区,他们分别是堆、栈、自由存储区,全局、静态存储区和常量存储区。

:就是那些由编译器在需要的时候分配,再不需要的时候自动清除的变量的存储区。里面的变量通常是局部变量、函数参数等。

:就是那些由new分配的内存块,他们的释放编译器不去管,由我们的应用程序去控制,一般一个new就要对应一个delete。如果程序员没有释放掉,那么程序结束后,操作系统就会自动回收。

自由存储区:就是那些由malloc等分配的内存块,它和堆是十分相似的,不过它是用free来结束自己生命的。

全局/静态存储区:全局变量和静态变量被分配到同一个内存中,在以前的C语言中,全局变量又分为初始化与未初始化的,在C++里面没有这个区分了,他们共同占用同一块内存区。

常量存储区:这是一块比较特殊的存储区,他们里面存放的是常量,不允许修改(当然,你要是通过非正常手段也可以修改,而且方法很多)

关于a[] 与 *a的一些区别:

  虽然用字符数组和字符指针变量都能实现字符串的存储和运算,但是他们二者之间是有区别的,不要混为一谈。

主要概括起来有以下几点:

  1. 字符数组由若干个元素组成,每个元素中放一个字符,而字符指针变量中存放的是地址(字符串第一个字符的地址),决不是将字符串放到字符指针变量中。
  2. 赋值方法的不同。对于字符数组只能是对各个元素赋值

  char str[20] ; str = “I Love Fishc.com!”;是错误的

   char str[20]= “I Love Fishc.com!”;是正确的

   char *str; str = “I Love Fishc.com!”; 是正确的

char *str=“I Love Fishc.com!”;是正确的

而字符变量可以,但是注意存放的是字符串的首字符的地址

  1. 如果定义了一个字符数组,在编译时为他分配内存单元,它有确定的地址。而定义一个字符指针变量,给指针变量分配内存单元,在其中可以放一个字符变量的地址也就是说,该指针变量可以指向一个字符型数据,但是如果未对它赋予一个地址,则它并未具体指向一个确定的字符数据。
  2. 指针变量的值是可以改变的。
  3. 使用指针定义的数组可以通过下标的方式遍历字符串

7、6用函数指针变量调用函数

一个函数在编译的时候被分配给一个入口地址。这个函数的入口地址就称为函数的指针。

1)函数指针变量常用的用途之一是把指针作为参数传递到其他的函数。

2)函数的参数可以是变量、指向变量的指针变量、数组名、指向数组的指针变量等。

3)现在介绍指向函数的指针也可以作为参数,以实现函数地址的传递,这样就能够在被调用的函数中使用实参函数。

 

7、7返回指针值的函数

这种带回指针值的函数,一般定义形式为:

例如:

int *a(int x,int y);

指针函数与函数指针的区别:

指针函数是指带指针的函数。

函数指针是指向函数的变量。

指针数组和指向指针的指针

指针数组的概念:

    一个数组,若其元素均为指针类型的数据,称为指针数组。

怎样定义一个指向指针的指针?

  字符类型  **p;

P的前面有两个*号。*号运算符的结合性是从右到左,因此**p相当于*(*p),显然*p是指针变量的定义形式。如果没有最前面的*,那就是定义了一个指向字符数据的指针变量。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值