【高级语言程序设计(一)】第 7 章:指针

目录

一、指针和指针变量

(1)指针 

(2)指针变量

(3)指针变量的定义

(4)指针变量的初始化

(5)指针变量的一般使用

① 给指针变量赋值

② 直接使用指针变量

③ 通过指针变量引用所指向的变量

(6)指针的基本运算 

① 取地址运算符 &

② 指针运算符 *

③ 取地址运算符和指针运算符的说明

④ 取地址运算符和指针运算符的优先级和结合性

(7)指针变量的引用

(8)指针变量作为函数参数

① 值传递 

② 地址传递 

二、指针和数组 

(1)指针和一维数组

(2)指针变量指向方法

① 指针变量指向一维数组

② 指针变量指向一维数组元素

③ 指针变量指向一维数组(利用指针变量引用一维数组元素)

④ 指针变量指向下标为 i 的一维数组元素(利用指针变量引用数组元素)

⑤ 指针变量指向一维数组(引用下标为 i 的一维数组元素)

⑥ 「示例」指向数组元素的指针

⑦ 「示例」通过指针引用数组元素

(3)一级指针变量与一维数组的关系

(4)表示数组元素的两种方法

① 下标法

② 指针法

(5)用三种方法输出数组中全部元素的值

① 下标法

② 指针法

③ 指针法和指针下标

(6)算术运算 

(7)关系运算

三、指针和字符串

(1)字符串的表示形式

① 用字符数组实现

② 用字符指针实现

③  用下标法存取字符串中的字符实现

(2)指向字符串的指针变量

① 将指针变量指向字符串的方法

②  利用指针变量处理字符串的处理方式

(3)指向字符数组的指针变量

① 字符指针和字符数组的区别

② 对使用字符指针变量和字符数组的讨论

四、指针和函数

(1)指针变量作为函数参数

(2)数组名作为函数参数 

① 实参与形参均用数组名 

② 实参用数组名,形参用指针变量

③ 实参与形参均用指针变量

④ 实参用指针变量,形参用数组名

(3)指针型函数的定义

(4)指针型函数的调用

五、指针数组

(1)指针数组的定义 

(2)指针数组的初始化 

(3)指针数组元素的赋值 

① 将数组名赋予指针数组各元素 

② 将字符串直接赋予指针数组元素 

(4)指针元素的使用

六、指针的程序设计举例

(1)示例一

(2)示例二



一、指针和指针变量

(1)指针 

  • C 语言中指针是一种数据类型。
  • 指针是存放数据的内存单元地址。
  • 计算机系统的内存拥有大量的存储单元(每个存储单元的大小为1字节),为了便于管理,必须为每个存储单元编号,该编号就是存储单元的 “地址” 。
  • 每个存储单元拥有一个唯一的地址。

(2)指针变量

  • 指针变量除了可以存放变量的地址外,还可以存放其他数据的地址。
  • 例如可以存放数组和函数的地址。

(3)指针变量的定义

指针变量定义的一般形式:
【格式】 数据类型符 * 指针变量名 [=初始地址值] , … ;
【功能】定义指向 “数据类型符” 的变量或数组的指针变量,同时为其赋初值。
【说明】
  1. “*” 表示定义的是一个指针变量。指针变量的前面必须有 “*” 号。
  2. 在定义指针变量的同时也可以定义普通变量或数组等。
  3. “数据类型符” 是指针变量所指向变量的数据类型,可以是任何基本数据类型,也可以是其他数据类型。
  4. “初始地址值” 通常是 “&变量名” “&数组元素” 或 “一维数组名” ,这里的变量或数组必须是已定义的。
  5. 在定义指针变量时,可以只给部分指针变量赋初值。
  6. 指针变量的初始化,除了可以是已定义变量的地址,也可以是已初始化的同类型的指针变量,也可以是 NULL(空指针)。
  7. 指针变量初始化时,指针变量的 “数据类型符” 必须与其 “初始地址值” 中保存的数据的类型相同。

(4)指针变量的初始化

【格式】[存储类型] 数据类型 * 指针名 = 初始地址值 ;

/* 错误代码示例:变量必须已说明过类型应一致 */
int *p=&i;
int i;
/* 错误示例:不能用auto变量的地址,去初始化static型指针 */
main( )
{ int i;
static int *p=&i;
.............. }
/* 正确示例:赋给指针变量,不是赋给目标变量 */
int i;
int *p=&i;
/* 正确示例:用已初始化指针变量作初值 */
int i;
int *p=&i;
int *q=p;
/* 指针变量赋值 */
int i, j;
int *p1,
*p2;
p1=&i; p2=&j ;
i=3; *p1=5;
j=6; *p2=8;


(5)指针变量的一般使用

① 给指针变量赋值

【格式】 指针变量 = 地址型表达式
  • 其中, “地址型表达式” 即运算结果是地址型的表达式。
  • C 语言规定,变量地址只能通过取地址运算符获得,即 “&” ,其运算对象是变量或数组元素名,运算结果是对应变量或数组元素的地址。
  • 需要注意的是,虽然地址是一个整数,但是 C 语言中不允许把整数看成 “地址常量” ,所以此处的 “地址型表达式” 不能是整数。

② 直接使用指针变量

【格式】 指针变量名
  • 需要使用地址时,可以直接引用指针变量名。

③ 通过指针变量引用所指向的变量

【格式】* 指针变量名

  • C 程序中, “* 指针变量名” 代表其指向的变量或数组元素,其中的 “*” 称为指针运算符。
  • 需要注意的是,这种引用方式要求指针变量必须已经定义且有值。

(6)指针的基本运算 

① 取地址运算符 &

  • 取地址运算符 “&” 的功能是取变量的地址,它是单目运算符。
  • 取地址运算符的运算对象必须是已经定义的变量或数组元素,但不能是数组名。
  • 运算结果是运算对象的地址。

② 指针运算符 *

  • 指针运算符 “*” 的功能是取指针变量所指向地址中的内容,与取地址运算符 “&” 的运算是互逆的,它是单目运算符。
  • 指针运算符的运算对象必须是地址,可以是已赋值的指针变量,也可以是变量或数组元素的地址,但不能是整数,也不能是非地址型的变量。
  • 运算结果就是地址对应的变量。

③ 取地址运算符和指针运算符的说明

④ 取地址运算符和指针运算符的优先级和结合性

  1. 取地址运算符、指针运算符和自增、自减等单目运算符的优先级相同。
  2. 所有单目运算符的结合性为从右至左。

(7)指针变量的引用

/* 示例:通过指针变量访问整型变量 */
#include <stdio.h>
void main( )
{
int a, b, *p1, *p2 ;
a=100; b=10;
p1=&a; p2=&b;
printf(“a=%d, b=%d\n”, a, b);
printf(“*p1=%d, *p2=%d\n”, *p1, *p2);
printf(“&a=%x,& b=%x\n”, &a, &b);
printf(“p1=%x, p2=%x\n”, p1, p2);
printf(“&p1=%x, &p2=%x\n”, &p1, &p2);
}

 


(8)指针变量作为函数参数

特点:共享内存, 双向” 传递 

① 值传递 

/* 「值传递」示例:将数从大到小输出 
    函数调用结束后,分配给 x,y,temp 单元释放 */

#include <stdio.h>
void swap(int x,int y)
{
  int temp;
  temp=x;
  x=y;
  y=temp;
}

void main()
{ 
  int a,b;
  scanf("%d,%d", &a, &b);
  if(a<b) swap(a,b);
  printf("\n%d,%d\n", a, b);
}

 

② 地址传递 

/* 示例:将数从大到小输出(使用指针变量作函数参数) */
#include <stdio.h>
void main()
{
  void swap(int *p1, int *p2);
  int a,b;
  int *pointer_1,
  *pointer_2;
  scanf("%d,%d", &a, &b);
  pointer_1=&a; pointer_2=&b;
  if(a<b) swap(pointer_1,pointer_2);
  printf("\n%d,%d\n", a, b);
}

void swap(int *p1, int *p2)
{ 
  int temp;
  temp=*p1;
  *p1=*p2;
  *p2=temp;
}

 



二、指针和数组 

(1)指针和一维数组

数组的指针是指向数组在内存的起始地址,数组元素的指针是指向数组元素在内存的起始地址。

(2)指针变量指向方法

指针变量指向一维数组

若将指针变量指向一维数组,可以采用以下 2 种方法:
  1. 在数据定义语句中用赋初值的方式,即:*指针变量=数组名
  2. 在程序中用赋值的方式,即:指针变量=数组名;

② 指针变量指向一维数组元素

若将指针变量指向一维数组元素,可以采用以下 2 种方法:
  1. 在数据定义语句中用赋初值的方式,即:*指针变量=&数组名[下标]
  2. 在程序中用赋值的方式,即:指针变量=&数组名[下标];

③ 指针变量指向一维数组(利用指针变量引用一维数组元素)

当指针变量指向一维数组,利用指针变量引用一维数组元素的方法如下:
  1. 引用下标为 0 的数组元素 *(指针变量+0)*指针变量指针变量[0]
  2. 引用下标为 i 的数组元素 *(指针变量+i)  或 指针变量[i]

④ 指针变量指向下标为 i 的一维数组元素(利用指针变量引用数组元素)

当指针变量指向下标为 i 的一维数组元素时,利用指针变量引用数组元素的方法如下:
  1. 引用下标为 i 的数组元素 *(指针变量+0) *指针变量
  2. 引用下标为 i-k 的数组元素 *(指针变量-k)
  3. 引用下标为 i+k 的数组元素 *(指针变量+k)

⑤ 指针变量指向一维数组(引用下标为 i 的一维数组元素)

当指针变量指向一维数组时,引用下标为 i 的一维数组元素可以采用 4 种方法:

  1. *(指针变量+i)
  2. *(数组名+i)
  3. 指针变量[i]
  4. 数组名[i]

⑥ 「示例」指向数组元素的指针

 

/* 示例:指向数组元素的指针 */
int a[10];
int *p;
p=&a[0];    /* 或 p=a;  定义后赋值,两者等价 */

/* 示例:定义指针变量时赋初值 */
int *p=&a[0];
int *p=a;

⑦ 「示例」通过指针引用数组元素

如果:
int a[10];
int *p;
p=&a[1];     /* p指向数组元素a[1] */
则:
*p=1 /* 表示对 p 当前指向的数组元素 a[1] 赋予值 1 */

而:

  • p+1 指向同一数组的下一个元素 a[2]
  • 的值(地址)加了 个字节,p+1=p+1×d(整型,d=2实型,d=4;字符型d=1)指针变量所指数组元素的地址的计算,与数组数据类型有关。
设:
​​​​​​​p=&a[0]
则:
  • p+i 和 a+i 就是 a[i] 的地址 a+i×d
  • *(p+i) 或 *(a+i) 是 p+i 或 a+i 指向的数组元素 a[i]
  • 指向数组的指针变量可带下标,p[i] 与 *(p+i) 等价

(3)一级指针变量与一维数组的关系

int *p int q[10]
  • 数组名是指针(地址)常量
  • p=q; p+i 是 q[i] 的地址
  • 数组元素的表示方法下标法指针法

  • 形参数组实质上是指针变量

  • 在定义指针变量(不是形参)时,不能把 int *p 写成 int p[];
  • 系统只给 分配能保存一个指针值的内存区(一般 字节);而给 q 分配 2*10 字节的内存区

(4)表示数组元素的两种方法

① 下标法

② 指针法


(5)用三种方法输出数组中全部元素的值

下面 3 种示例代码中,使用指针变量时要注意的问题:

  1. p++:合法,因为 p 是指针变量,++ 只能用于变量。
  2. a++:不合法,因为 a 是数组名,其值是数组元素的首地址,是常量,程序运行期间值固定不变。
  3. 指针变量使用时要注意当前值。

① 下标法

#include <stdio.h>
void main()
{
  int a[10];
  int i;
  for(i=0; i<10; i++)
  scanf("%d", &a[i]);
  printf("\n");
  for(i=0; i<10; i++)
  printf("%d", a[i]);
}

② 指针法

#include <stdio.h>
void main()
{
  int a[10];
  int *p,i;
  for(i=0; i<10; i++)
  scanf("%d", &a[i]);
  printf("\n");
  for(p=a,i=0; i<10; i++)
  printf("%d", *(p+i));
}

③ 针法和指针下标

#include <stdio.h>
void main()
{
  int a[10];
  int *p,i;
  for(i=0; i<10; i++)
  scanf("%d", &a[i]);
  printf("\n");
  for(p=a; p<(a+10); p++)
  printf("%d", *p);
}

 


(6)算术运算 

指针变量可以进行的算术运算包括:

  • 指针变量 ± 整数
  • 指针变量 ++/++ 指针变量
  • 指针变量 --/-- 指针变量
  • 指针变量1 - 指针变量2
由于指针运算符 * 与自增运算符 ++、自减运算符 -- 的优先级相同,结合方向都是 从右至左 ,因此需要注意以下各种形式的含义不同。

*++px;      /* 先使指针变量 px 加 1,再取新的指针变量 px 所指向地址的内容 */

*(++px);    /* 等价于 *++px; */


*px++;      /* 先取指针变量 px 所指向地址的内容,再使指针变量 px 加 1 */

*(px++);    /* 等价于 *px++; */


++(*px);    /* 将指针变量 px 所指向地址的内容加 1 */

++*px;      /* 等价于 ++(*px); */


*(--px);      /* 先使指针变量 px 减 1,再取新的 px 所指向地址的内容 */

*--px;        /* 等价于 *(--px); */


*(px--);      /* 先取指针变量 px 所指向地址的内容,再使指针变量 px 减 1 */

*px--;        /* 等价于 *(px--); */


--(px);       /* 将指针变量 px 所指向地址的内容减 1 */

--*px;        /* 等价于 --(px); */


px-py;      /* 是指两个相同类型的指针可以进行减法运算,运算结果是两个指针之间的数据个数,而不是两个指针的地址之差 */


(7)关系运算

  • 两个类型相同的指针变量可以运用关系运算符比较大小,表示两个指针变量所指向地址位置的前后关系,即前者为小,后者为大。
  • 需要注意的是,如果两个指针变量不是指向同一个数组,则比较大小没有实际意义。


三、指针和字符串

(1)字符串的表示形式

① 用字符数组实现

字符串 : 用双引号括起的一串字符。
  • 可赋给字符型的数组或指针变量
  • 可通过字符型数组名或字符型指针变量输出

​​/* 示例:定义字符数组 */
#include <stdio.h>
void main()
{ 
  char string[]="I love China!";
  printf("%s\n", string);
  printf("%s\n", string+7);
}

​​/* 运行结果 */
I love Chine!
Chine!

② 用字符指针实现

  • 字符串的指针就是字符串的首地址,即第一个字符的地址,可以使用字符指针变量来保存这个地址
  • 使用字符指针可以处理字符串
  • 字符指针的定义及使用
定义和初始化:
/* 示例:定义和初始化 */
char *string="I love China!";
在程序中可以直接把字符串常量赋给 一个指针变量:
/* 示例:在程序中可以直接把字符串常量赋给一个指针变量 */
char *string;
string="I love China!";

定义字符指针:

/* 示例:定义字符指针 */
#include <stdio.h>
void main( )
{ 
  char *string="I love China!";
  printf("%s\n", string);
}

/* 运行结果 */
I love Chine!

/* 示例:定义字符指针(改动后的) */
#include <stdio.h>
void main( )
{ 
  char *string="I love China!";
  printf("%s\n", string);
  string+=7;
      while(*string)  /* *string!='\0' */
      { 
         putchar(string[0]);
         string++;
       }
}

/* 运行结果 */
I love Chine!
Chine!

③  用下标法存取字符串中的字符实现

/* 示例:将字符串a复制为字符串b */
#include <stdio.h>
void main()
{ 
  char a[]="I am boy.", b[20];
  int i;
  for(i=0; *(a+i)!='\0'; i++)
     *(b+i)=*(a+i);
     *(b+i)='\0';
  printf("string a is: %s\n", a);
  printf("string b is: ");
  for(i=0; b[i]!='\0'; i++)
     printf("%c", b[i]);
  printf("\n");
}

/* 运行结果 */
string a is: I am boy. 
string b is: I am boy.

(2)指向字符串的指针变量

① 将指针变量指向字符串的方法

  1. 在数据定义语句中用赋初值的方式:*指针变量=字符串;
  2. 在程序中用赋值的方式:指针变量=字符串;
需要注意的是,这两种方法并不是将字符串赋予指针变量,而是将存放字符串的连续内存单元的首地址赋予指针变量。

②  利用指针变量处理字符串的处理方式

当指针变量指向字符串时,则可以利用指针变量处理字符串,处理方式主要有:
1. 处理整个字符串
  • 输出整个字符串:printf("%s" ,指针变量);
  • 输入整个字符串:scanf("%s" ,指针变量);
/* 示例:处理整个字符串 */
#include <stdio.h>
int main(void)
{
  char*string="I love China.";
  printf("%s\n",string);
  return 0;
}

/* 运行结果 */
I love China.

2. 处理字符串中的单个字符

/* 示例:使用指向字符串的指针变量处理字符串中单个字符 */
#include <stdio.h>
int main(void)
{
  char *string="I love China.";
  for(;*string!='\0'; string++) printt("%c", *string); /* 利用for循环和指向字符串的指针变量string 逐一输出字符串各字符 */
  printf("\n");
  return 0;
}

/* 运行结果 */
l love China.

(3)指向字符数组的指针变量

  • C 语言中,字符串是按字符数组进行处理的,系统存储一个字符串时先分配一个起始地址,从该地址开始连续存放字符串中的字符。
  • 这一起始地址即字符串首字符的地址。
  • 所以,可以将一个字符串赋值给一个字符数组,也可以赋值给一个字符指针变量。

① 字符指针和字符数组的区别

字符指针和字符数组的区别主要体现在:
  1. 存储内容不同
  2. 赋值方式不同
  3. 字符指针变量在定义后应先赋值才能引用
  4. 指针变量的值是可以改变的,字符指针变量也不例外;而数组名代表数组的首地址,是一个常量,而常量是不能改变的。

② 对使用字符指针变量字符数组的讨论

char *cp; char str[20]; 的区别:
1、str  由若干元素组成,每个元素放一个字符;而  cp  中存放字符串首地址
2、赋值方式:
  • 字符数组只能对元素赋值
/* 示例:错误代码 */
char str[20];
str="I love China!";
  • 字符指针变量可以用
/* 示例:正确代码 */
char *cp;
cp="I love China!"; 
  • 赋初值
/* 示例:正确代码,等价 char *cp; cp=“China!”; */
char *cp="China!"; 

/* 示例:错误代码,不等价 char str[14]; str[]="China" */
char str[14]={"China"};


四、指针和函数

(1)指针变量作为函数参数

  1. 指针变量既可以作为函数的形参,也可以作为函数的实参。
  2. 指针变量作为函数参数,形参和实参之间的数据传递方式本质上是值传递,只是在调用函数时传递的内容是地址,这样使得形参变量和实参变量指向同一个变量。
  3. 若被调函数中有对形参所指变量内存的改变,实际上是改变了实参所指变量的内容。

(2)数组名作为函数参数 

1. 数组名作为函数形参时,接收实参数组的首地址;
2. 数组名作为函数实参时,将数组的首地址传递给形参数组。
3. 引入指向数组的指针变量后,数组及指向数组的指针变量作为函数参数时,可有四种等价形式:
  • 形参、实参均为数组名
  • 形参、实参均为指针变量
  • 形参为指针变量、实参为数组名
  • 形参为数组名、实参为指针变量
数组名作函数参数, 地址传递 当用数组名做函数 实参时相当于将数组的 首地址传给被调函数的 形参,此时,形参数组 和实参数组占用的是同 一段内存, 所以当在被 调函数中对形参数组元 素进行修改时,实参数 组中的数据也将被修改, 因为它们是同一个地址。
/* 示例:数组名作函数参数 */
void main( )
{
  f(int arr[], int n);
  int array[10];
       ┆
  f(array, 10);
       ┆
}

void f(int arr[], int n)
{
  ┆
}
用数组做函数参数有如下 4 种情况:
【示例】将数组 a  中  个整数按相反顺序存放。
【思路】数组元素头尾对调。
【调用方式】
  • 实参与形参均用数组名
/* 实参形参都用数组名 */
int a[10];                  inv(int x[], int n)
inv(a, 10)                  { …… }
  • 实参用数组名,形参用指针变量
/* 实参用数组名,形参用指针变量 */
int a[10];                   inv(int *x, int n)
inv(a, 10)                   { …… }
  • 实参与形参均用指针变量
/* 实参形参都用指针变量 */
int a[10];                   inv(int *x, int n)
int *p=a;                    { …… }
inv(p, 10)
  • 实参用指针变量,形参用数组名

/* 实参用指针变量,形参用数组名 */
int a[10];                   inv(int x[ ],int n)
int *p=a;                    { …… }
inv(p,10)

① 实参与形参均用数组名 

/* 示例:将数组 a 中 n 个整数按相反顺序存放 */
/* [调用方式] 实参与形参均用数组名 */
#include <stdio.h>
void main()
{
  void inv(int x[], int n);
  int i, a[10]={3,7,9,11,0,6,7,5,4,2};
  printf("The original array:\n");
  for(i=0; i<10; i++) printf("%d,", a[i]);
      printf("\n");
  inv(a,10);
  printf("The array has been inverted:\n");
  for(i=0; i<10; i++) printf("%d,", a[i]);
     printf("\n");
}

void inv(int x[], int n)
{ 
  int temp, i, j, m=(n-1)/2;
  for(i=0; i<=m; i++)
     { 
        j=n-1-i;
        temp=x[i]; x[i]=x[j]; x[j]=temp; 
     }
  return;
}

② 实参用数组名,形参用指针变量

/* 示例:将数组 a 中 n 个整数按相反顺序存放 */
/* [调用方式] 实参用数组名,形参用指针变量 */
#include <stdio.h>
void main()
{
  void inv(int *x, int n);
  int i, a[10]={3,7,9,11,0,6,7,5,4,2};
  printf("The original array:\n");
  for(i=0; i<10; i++) printf("%d,", a[i]);
      printf("\n"); inv(a,10);
  printf("The array has been inverted:\n");
  for(i=0; i<10; i++) printf("%d,", a[i]);
      printf("\n");
}

void inv(int *x, int n)
{ 
  int temp, *p, *i, *j, m=(n-1)/2;
  i=x; j=x+n-1; p=x+m;
  for(; i<=p; i++, j--)
     { 
        temp=*i; *i=*j; *j=temp; 
     }
  return;
}

③ 实参与形参均用指针变量

/* 示例:将数组 a 中 n 个整数按相反顺序存放 */
/* [调用方式] 实参与形参均用指针变量 */
#include <stdio.h>
void main()
{
  void inv(int *x, int n);
  int i, arr[10], *p=arr;
  printf("The original array:\n");
  for(i=0; i<10; i++, p++)
      scanf("%d", p);
  p=arr; inv(p, 10);
  printf("The array has been inverted:\n");
  for(p=arr; p<arr+10; p++)
      printf("%d", *p);
  printf("\n");
}

void inv(int *x, int n)
{ 
  int *p, m, temp, *i, *j;
  m=(n-1)/2;
  i=x; j=x+n-1; p=x+m;
  for(; i<=p; i++, j--)
     { 
        temp=*i; *i=*j; *j=temp; 
     }
  return;
}

④ 实参用指针变量,形参用数组名

/* 示例:将数组 a 中 n 个整数按相反顺序存放 */
/* [调用方式] 实参用指针变量,形参用数组名 */
#include <stdio.h>
void main()
{
  void inv(int x[], int n);
  int i, a[10], *p=a;
  for(i=0; i<10; i++, p++)
      scanf("%d", p);
  p=a;
  inv(p,10);
  printf("The array has been inverted:\n");
  for(p=arr; p<arr+10; p++)
      printf("%d", *p);
  printf("\n");
}

void inv(int x[ ], int n)
{ 
  int t, i, j, m=(n-1)/2;
  for(i=0; i<=m; i++)
     { 
        j=n-1-i; 
        t=x[i]; x[i]=x[j]; x[j]=t; 
     }
  return;
}

(3)指针型函数的定义

  • C 语言中,函数可以返回整型、实型、字符型数据,也可以返回指针类型数据,即返回一个地址。
  • 指针型函数是指函数的返回值是指针型,即这类函数的返回值必须是地址值,调用该类函数时,接收返回值的必须是指针变量、指针数组元素等能够存放地址值的对象。
  • 定义指针型函数的格式和有返回值的函数的定义格式基本相同,唯一的区别是在函数名前面加一个 “*” ,表示函数的返回值是指针型数据。

(4)指针型函数的调用

指针型函数的调用和一般函数的调用方法完全相同,但需要注意的是:
  • 只能使用指针变量或指针数组元素接收指针型函数的返回值
  • 不能使用数组名接收指针型函数的返回值
  • 因为函数名是地址常量,不是地址型变量,不能接收地址型变量数据


五、指针数组

(1)指针数组的定义 

【定义】指针数组是数组中的元素均为指针变量。
【格式】 数据类型符 *指针数组名[数组长度];
【功能】定义指针数组,有 “长度” 个数组元素。
【说明】
  1. 指针数组名是标识符,前面必须加 “*” 号。
  2. 定义指针数组的同时可以定义普通变量、数组和指针变量等。
  3. “数据类型符” 可以是任何基本数据类型。
  4. “数据类型符” 不是指针数组元素中存放的数据类型,而是其所指向数据的数据类型。

(2)指针数组的初始化 

/* 示例 */
char *ps[]={"China", "America", "Russia", NULL};
定义了一个用于指向字符型数据的指针数组 ps,其长度为 4 ,同时对指针数组元素赋初值,前面三个是字符型指针,最后一个是空指针。
/* 示例 */
int a[3][3]={1,2,3,4,5,6,7,8,9};
int *p[3]={a[0],a[1],a[2]};      /* 利用二维数组元素初始化指针数组p */

(3)指针数组元素的赋值 

① 将数组名赋予指针数组各元素 

/* 示例 */
char s[4][20]={"China", "America", "Russia", NULL};
char *p[4];
p[0]=s[0];    /* 给指针数组元素 p[0] 赋值 s[0] ,s[0] 是字符串 "China" 的首地址 */

② 将字符串直接赋予指针数组元素 

/* 示例 */
char *p[4];
p[0]="China";  /* 直接给指针数组元素 p[0] 赋值为字符串 "China" 的首地址 */

(4)指针元素的使用

  • 指针数组元素的表示方法和普通数组元素的表示方法完全相同。
  • 指针数元素的使用和指针变量的使用完全相同,可以对其赋予地址值,可以利用其引用所指向的变量或数组元素,也可以参与运算。

其中算术运算和关系运算一般只用于指针数组元素指向同一个指针数组。 


六、指针的程序设计举例

(1)示例一

/* 
  pointer[i]+j、array[i]+j、 &array[i][j] 等价,均指向 array[i][j]
  *(pointer[i]+j)、 *(*(pointer+i)+j)、 pointer[i][j] 与 array[i][j] 等价
*/

#include <stdio.h>
#include <string.h>
int main(void)
{
  int array[3][3]={1,2,3,4,5,6,7,8,9), i, j;       /* 定义一个整形二维数组 array */
  int *pointer[3]={array[0], array[1], array[2]};  /* 定义一个指向整形数据的指针数组 pointer 并初始化,即将二维数组 array 的每行元素的首地址赋予指针数组的各元素 */
  for(i=0; i<3; i++)
      for(j=0; j<3; j++)
          printf("%4d", pointer[i][j]);            /* 利用指向二维数组元素的指针数组输出二维数组各元素的值 */
  return 0;
}

【代码详解】

1. 在 main 函数中,定义一个 3 行 3 列、类型为整形的二维数组 array ,并且初始化它的每一个元素,代码如下:

int array[3][3]={1,2,3,4,5,6,7,8,9};

2. 定义一个指向 int 类型的指针数组 pointer ,它有 3 个元素,即数组的行数。将二维数组每一行的首元素的地址分别赋给 pointer 数组中的相应元素,代码如下:

int *pointer[3]={array[0], array[1], array[2]};

3. 使用嵌套的 for 循环遍历二维数组 array 的每个元素,并使用指向二维数组元素的指针数组 pointer 输出相应元素的值,代码如下:

for(i=0; i<3; i++)
  for(j=0; j<3; j++)
      printf("%4d", pointer[i][j]);

4. 在输出时,利用了 pointer[i][j] 等价于 *(pointer[i]+j),即先取得 pointer[i] 指针指向的地址,再加上 j 偏移量,最后用 * 取指针指向的值,这样就不必再写二重循环取数组元素。因此,*(pointer[i]+j)、*(*(pointer+i)+j)、pointer[i][j] 与 array[i][j]等价。


(2)示例二

/* 输入三个国家的名称,按字母顺序排序后输出 */
#include <stdio.h>
#include <string.h>
int main(void)
{
  char *s[]={"China", "America", "Russia"}, *p;   /* 定义指针数组s和指针变量p */
  int i, j, k=3;
  for(i=0; i<k-1; i++)
      for(j=0; j<k-1; j++)
          if(strcmp(s[j],s[j+1]>0)
            { 
               p=s[j]; s[j]=s[j+1]; s[j+1]=p; 
            }
  for(i=0; i<k; i++)
      printf("%s\n", s[i]);
  return 0;
}

【代码详解】

这是一个 C++ 代码,它实现了输入三个国家的名称,按字母顺序排序后输出的功能。下面是代码的详细解释:

  1. #include 是 C++ 中的预处理指令,它会在编译之前将 stdio.h 和 string.h 头文件插入到代码中,以便在程序中使用这些库函数。

  2. char *s[]={"China", "America", "Russia"}, *p; 是定义了一个指针数组 s 和一个指针变量 p, *s[] 是一个指向字符类型的指针数组,数组中存放的是 char 类型的指针变量,每个指针变量指向一个字符串。在本例中,数组中存放了三个国家的名称。

  3. int i, j, k=3; 是定义了三个整型变量 ij 和 k,并将 k 初始化为 3。其中,i 和 j 是循环变量,用于控制循环次数,k 存储指针数组s的元素数量,也即需要排序的国家名称数量。

  4. for(i=0; i<k-1; i++) for(j=0; j<k-1; j++) if(strcmp(s[j],s[j+1])>0) { p=s[j]; s[j]=s[j+1]; s[j+1]=p; } 是一个双重循环,用于字符串的排序。外层循环变量 i 用于控制循环次数,因为只有 k-1 次循环后才可以完成排序,内层循环变量 j 也用于控制循环次数,每次循环会比较相邻的两个字符串,如果前一个字符串比后一个字符串的字典序大,则通过指针交换的方法进行排序,最后完成整个数组的排序。

    1. strcmp(s[j],s[j+1])>0 表示字符串 s[j] 是否比字符串 s[j+1] 大,如果是,说明 s[j] 排在 s[j+1] 的后面,需要进行交换。
    2. p=s[j]; s[j]=s[j+1]; s[j+1]=p; 是通过指针变量 p 进行指针交换,将 s[j] 和 s[j+1] 的值进行交换。
  5. for(i=0; i<k; i++) printf("%s\n", s[i]); 是一个循环语句,用于输出排序后的字符串,%s 是 C++ 语言中的格式控制字符串,用于输出字符串,%s\n 表示输出字符串并换行。

  6. return 0; 表示程序执行完毕,程序结束,并将执行结果返回给操作系统。

  • 1
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

顾三殇

觉得不错的话,打赏鼓励一下吧~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值