Upload
theodora-xena
View
49
Download
0
Embed Size (px)
DESCRIPTION
程序设计导论. 指针 (1). 内容. 指针的概念 指针与数组 字符串及其处理 指针与函数 指针与结构 指针与结构数组 引用 几种参数传递方式. 什么是指针?. 指针是 C/C++ 语言中的一个重要概念。掌握指针的用法,可使程序简洁、高效、灵活,但并不难学。 为了了解什么是指针,先看一个小故事. - PowerPoint PPT Presentation
Citation preview
指针指针 (1)(1)
程序设计导论程序设计导论
内容内容 指针的概念指针的概念 指针与数组指针与数组 字符串及其处理字符串及其处理 指针与函数指针与函数 指针与结构指针与结构 指针与结构数组指针与结构数组 引用引用 几种参数传递方式几种参数传递方式
什么是指针?什么是指针? 指针是指针是 C/C++C/C++ 语言中的一个重要概念。语言中的一个重要概念。
掌握指针的用法,可使程序简洁、高效、掌握指针的用法,可使程序简洁、高效、灵活,但并不难学。灵活,但并不难学。
为了了解什么是指针,先看一个小故事为了了解什么是指针,先看一个小故事
地下工作者阿金接到上级指令,要去寻找打开密地下工作者阿金接到上级指令,要去寻找打开密电码的密钥,这是一个整数。几经周折,才探知电码的密钥,这是一个整数。几经周折,才探知如下线索,密钥藏在一栋三年前就被贴上封条的如下线索,密钥藏在一栋三年前就被贴上封条的小楼中。一个风雨交加的夜晚,阿金潜入了小楼,小楼中。一个风雨交加的夜晚,阿金潜入了小楼,房间很多,不知该进哪一间,正在一筹莫展之际,房间很多,不知该进哪一间,正在一筹莫展之际,忽然走廊上的电话铃声响起。艺高人胆大,阿金忽然走廊上的电话铃声响起。艺高人胆大,阿金毫不迟疑,抓起听筒。只听一个陌生人说:毫不迟疑,抓起听筒。只听一个陌生人说:““去去打开 打开 211 211 房间,那里有线索房间,那里有线索””。阿金疾步上楼,。阿金疾步上楼,打开 打开 211 211 房门,用电筒一照,只见桌上赫然 房门,用电筒一照,只见桌上赫然 6 6 个大字:个大字:地址地址 10001000 。阿金眼睛一亮,迅速找到 。阿金眼睛一亮,迅速找到 1000 1000 房间,取出重要数据 房间,取出重要数据 6666 ,完成了任务。,完成了任务。
我们画出下图
10001000 …… 6666 ……211 1000
P
说明:1 、数据藏在一个内存地址单元中,地址是 1000 。2 、地址 1000 又由 P 单元所指认, P 单元的地址为 211 。3 、 66 的直接地址是 1000 ; 66 的间接地址是 211 ;
211 中存的是直接地址 1000 。4 、称 P 为指针变量, 1000 是指针变量的值,实际上是
有用数据藏在地址为 1000 的存储器中。
指针的概念指针的概念 指针变量——用来存放另一变量地址的变量
指针是一种特殊的变量,特殊性表现在类型和值上。 从变量讲,指针也具有变量的三个要素:
1. 变量名,这与一般变量取名相同,由英文字符开始。2. 指针变量的类型,是指针所指向的变量的类型,而不是身的
类型。3. 指针的值是某个变量的内存地址。
变量的指针就是变量的地址。
指针的定义指针的定义 指针变量的类型定义成它所指向的变量的类型。 定义的格式: 类型标识符 * 标识符 ;
例如: int *p, *q; // 定义 p,q 为指向整数类型变量的指
针 float *point; // 定义 point 为指向 float 型变量
的指针 double *pd; // 定义 pd 为指向 double 型变量
的指针 int (*pa)[10]; // 定义 pa 为指向 int 型数组的指针 int (*pu)(); // 定义 pu 为指向 int 型函数
的指针 int **qq; // 定义 qq 为指向 int 型指针的指针
还有指向结构、联合的指针,后面再介绍
指针的初始化指针的初始化 int *p = NULL; int *p = NULL; 说明:说明:
NULL NULL 是在头文件中定义了的,是符号化的是在头文件中定义了的,是符号化的常量常量 00 ,,是唯一的一个允许赋值给指针的整数是唯一的一个允许赋值给指针的整数值值
表示指针不指向任何内存地址表示指针不指向任何内存地址 防止其指向任何未知的内存区域防止其指向任何未知的内存区域 避免产生难以预料的错误发生避免产生难以预料的错误发生
把指针初始化为 把指针初始化为 NULL NULL 是好习惯是好习惯
指针的赋值指针的赋值
将一个内存地址装入指针变量将一个内存地址装入指针变量 取址运算符取址运算符 && 例如:例如:
int a=66; int a=66; // // 定义整型变量 定义整型变量 a, a, 赋初值赋初值 6666
// // 定义定义 p,qp,q 指针变量,赋初值为指针变量,赋初值为 00
int *p=NULL,*q=NULL; int *p=NULL,*q=NULL;
p = &a;p = &a; ////将变量 将变量 a a 的地址赋给 的地址赋给 pp ,这,这时见图时见图 11
q = p;q = p; // // 将 将 p p 的值赋给 的值赋给 q q ,见图,见图 22
&a
p a
&p p 变量的地址
&a a 变量的地址
图 1
66
66
&a
p a
图 2 的说明:当着执行 q=p;之后,p 中所存的 a 变量的地址值,也就被放到 q 变量中,意味着让指针 q 也指向 a
图 2
&a
q
&p
&q
q=p;
q = p; // 将 p 的值赋给 q ,见图 2
// 指针 1.cpp
#include <stdio.h> // 预编译命令
int main() // 主函数{ // 函数体开始 int a[5]={0,1,2,3,4}; // 定义数组,赋初值 int *p1=NULL,*p2=NULL; // 定义指针变量 p1=&a[1]; // 赋值给指针变量,让 p1 指向 a[1]
p2=&a[2]; // 赋值给指针变量,让 p2 指向 a[2]
printf("%d,%d\n", *p1, *p2); // 输出 a[1] 和 a[2] 的值 return 0;
} // 函数体结束
程序说明程序说明
P1 P1 和 和 p2 p2 分别指向 分别指向 a[1], a[2]a[1], a[2] ,这里,这里 & & ———— 取地址运算符取地址运算符 * * ———— 指针运算符(间接访问运算符)指针运算符(间接访问运算符) **p1p1———— 间接访问间接访问 p1p1 所指向的内存单元,当然是输出所指向的内存单元,当然是输出 a[1]a[1] 的的
值值 **p2p2———— 间接访问间接访问 p2p2 所指向的内存单元,当然是输出所指向的内存单元,当然是输出 a[2]a[2] 的的
值值
&a[1] &a[2]
&p1 &p2
p1 p2
00 11 22 33 44&a[0&a[0
]]&a[1&a[1
]]&a[2&a[2
]]&a[3&a[3
]]&a[4&a[4
]]
间接访问运算符间接访问运算符 int a;int a; int *p;int *p; p=&a;p=&a; a=666; a=666; 等效于等效于 **p=666;p=666;
666
a
&a
&a
p
&p
*p
a
&a
&a
p
&p
#include <stdio.h> // 预编译命令
int main() // 主函数{ // 函数体开始
int akey,b; // 定义整型变量int *p,*q; // 定义指针变量akey=66; // 赋值给变量 akey
p=&akey; // 赋值给指针变量 p ,让 p 指向变量 akey
q=&b; // 赋值给指针变量 q ,让 q 指向变量 b
*q=*p; // 将 p 所指向的 akey 的值赋给 q 所指向的变量 b
printf("b=%d\n", b); // 输出 b 的值printf("*q=%d\n", *q); // 输出 b 的值return 0;
} // 函数体结束
例程:
&aKey 66
&b 66
p aKey
&aKey
q b
&b
int *p; int*q;int *p; int*q;
p=&akey;p=&akey;
q=&b;q=&b;
*q=*p;*q=*p;
akey=66;akey=66;
7.2 7.2 指针与数组指针与数组#include <stdio.h> // 预编译命令
int main() // 主函数{ // 函数体开始
int a[5]={1,3,5,7,9}; // 定义数组,赋初值int *p; // 定义指针变量int i; // 定义整型变量p=a; // 赋值给指针变量,让 p 指向 a数组 for(i=0; i<5; i++){ // 循环体开始
printf("a[%d]=%d\n", i, *p); // 输出 a 数组元素的值
p++; // 指针变量加 1 } // 循环体结束return 0;
} // 函数体结束
说明 (1) p=a; 这里数组名作为数组的起始地址,即 a[0] 的地址。
因此 p=a 等效于 p=&a[0]; (2) p=p+1; 如 p 指向 a[0], 则 p=p+1 之后, p 指向 a[1] (3) 如果 p=a 等效于 p=&a[0];
则 p=a+4 等效于 p=&a[4];
a[0]a[0]
a[1]a[1]
a[2]a[2]
a[3]a[3]
a[4]a[4]
*p*p
*(p+1)*(p+1)
*(p+2)*(p+2)
*(p+3)*(p+3)
*(p+4)*(p+4)
p
p+1
p+2
p
p+1
p+2
等效
#include <stdio.h> // 预编译命令
int main() // 主函数{ // 函数体开始 int a[5]={1,3,5,7,9}; // 定义数组,赋初值 int *p; // 定义指针变量 int i=0; // 定义整型变量 , 赋初值 for(p=a; p<a+5;p++) // 赋值给指针变量,让 p 指向 a 数
组 { // 循环体开始 printf("a[%d]=%d\n", i, *p); // 输出 a 数组元素的值 i++; // 让 i 加 1 } // 循环体结束 return 0;} // 函数体结束
做下面的实验
a a
1 3 5 7 9 1 3 5 7 9
a a+1 a+2 a+3 a+4 a a+1 a+2 a+3 a+4
p=a p p+1 p+2 p+3 p=a p p+1 p+2 p+3 p+4p+4
#include <stdio.h>
int main( ){
char *p=NULL; // 定义指向字符类型的指针变量 pchar s[] = “abcdefgh”; // 定义字符数组,并赋值p=s; // 数组名是一个常量指针,
// 它指向该数组首地址while (*p != ‘\0’) // 当 p 所指向的数组元素不为’ \0’ 时{
p++; // 让指针加 1}printf(" 字串长度为 %d\n", p-s);// 输出字串长return 0;
}
数组名是一个常量指针,指向该数组的首地址,例
00 11 22 33 44 55 66 77 88
aa bb cc dd ee ff gg hh \0\0s
s p
图中数组的首地址是 s[0] 的地址,即 &s[0] 。 s 可看作是指向 s[0] 的指针。 s 是不会动的,是常量指针。
a b c d e f g h \0 a b c d e f g h \0
ss 61 62 63 64 65 66 67 68 0061 62 63 64 65 66 67 68 00
s s p=p+1 p=p+1 p s s+1 s+2 s+3 s+4 s+5 s+6 s+7 s+8p s s+1 s+2 s+3 s+4 s+5 s+6 s+7 s+8
p = s+8 p – s = 8
编程实例编程实例妙对妙对 与 与 逆序输出逆序输出
客上天然居客上天然居 , , 居然天上客居然天上客人过大钟寺人过大钟寺 , , 寺钟大过人寺钟大过人
实例实例 11 :将字符串逆序输出:将字符串逆序输出
#include <stdio.h> // 预编译命令int main() // 主函数{ // 函数体开始
char shuzi[]="987654321"; // 定义数组,// 赋初值为数字字符串
char *p=&shuzi[8]; // 让指针 p 指向 shuzi[8] 元素,// 该处是字符‘ 1’
do // 直到型循环{ // 循环体开始
printf("%c", *p); // 输出一个字符,该字符由 p指向
p--; // 让 p 减 1} // 循环体结束while (p>=shuzi); // 当 p>=shuzi 时,继续循环printf("\n"); // 换行return 0;
}
数组名是一个常量指针,指向该数组的首地址,例
00 11 22 33 44 55 66 77 88 99
99 88 77 66 55 44 33 22 11 \0\0
shuzi p
说明:1 、字符串: 数字字符串。2 、 p 指向 shuzi[8] ,即指向串中的字符 ’ 1’ 。3 、直到型循环,用 printf 将 shuzi[8] 输出到屏幕;之后
让 p 减 1 赋给 p 。4 、在 while 中,当 p>=shuzi 则继续执行循环体。一旦
p<shuzi 则退出循环。这种做法使输出结果为123456789
5 、在本例中数组名 shuzi 是一个常量指针,永远指向 shuzi[0] 的地址上。
思考:如何通过 p 和 shuzi 求该数字字符串的长度
#include <stdio.h> // 预编译命令int main() // 主函数{ // 函数体开始
int i;char *p; // 定义指针变量,赋初值p="computer"; // 指针赋初值,指向字苻串printf("%s\n", p); // 输出字苻串for (i=0; i<8; i++){ // 循环体开始
printf("%c", p[i]); // 输出第 i 个字苻} // 循环体结束cout<<endl; // 换行while(*p){ // 循环体开始
printf("%c", *p); // 输出 p 所指向的字符 p++; // 指针变量值加 1
} // 循环体结束 cout<<endl; // 换行
return 0;} // 函数体结束 v
p p[0] p[1] p[2] p[3] p[4] p[5] p p[0] p[1] p[2] p[3] p[4] p[5] p[6] p[7] p[8]p[6] p[7] p[8]
c o m p u t c o m p u t e r /0 e r /0
pp
数组名是常量指针,数组名是常量指针, pp 可理解为这个字可理解为这个字符数组的名字。 符数组的名字。
P p[0] p[1] p[2] p[3] p[4] p[5] P p[0] p[1] p[2] p[3] p[4] p[5] p[6] p[7] p[8]p[6] p[7] p[8]
c o m p u t c o m p u t e r /0 e r /0
p p+1p p+1
*p==c, *(p+1) ==o, *(p+2) *p==c, *(p+1) ==o, *(p+2) ==m==m
1 、对字符指针变量赋值的写法( 1 ) char *p; ( 2 ) char *p=“computer”; p = “computer”;以上两种都行。可以整体赋值。
2 、对字符数组赋初值的写法( 1 ) char as[12]=“department”;// 可以。在定义时可以整体赋
值char as[] =“department”;// 可以。在定义时可以整体赋
值
( 2 ) char as[12];as = “department”; // 不可以!不可以整体赋值as[12]=“department”; // 不可以!不可以整体赋值
对对字符指针字符指针和和字符数组字符数组的赋值的赋值
字符数组字符数组 && 字符指针字符指针char str[ ]= "Computer char str[ ]= "Computer
Science";Science";char *pStr="Information char *pStr="Information
School";School";printf(printf(““%s\n%s\n””, str);, str);printf(printf(““%s\n%s\n””, pStr);, pStr);printf(printf(““%d\n%d\n””, &str);, &str);printf(printf(““%d\n%d\n””, &pStr);, &pStr);
pStr = str;pStr = str;printf(printf(““%s\n%s\n””, pStr);, pStr);
int int
aryNum[]={1,2,3,4,5,6,7,aryNum[]={1,2,3,4,5,6,7,
8};8};
int *pNum;int *pNum;
pNum = aryNum;pNum = aryNum;
printf(printf(““%d\n%d\n””, aryNum);, aryNum);
printf(printf(““%d\n%d\n””, &aryNum); , &aryNum);
printf(printf(““%d\n%d\n””, pNum);, pNum);
printf(printf(““%d\n%d\n””, &pNum);, &pNum);Computer ScienceInformation School0012FF6C0012FF68Computer Science
0012FF480012FF480012FF480012FF44
pNum = {2, 3 , 4};
有关指针的一段错误代码有关指针的一段错误代码
char str[ ]= "Computer Science";char str[ ]= "Computer Science";char *p=NULL, *q=NULL;char *p=NULL, *q=NULL;p = str;p = str;printf(printf(““%c\n%c\n””, *p);, *p);*q = *p;*q = *p;q = p;q = p;
结 束