You are on page 1of 19

C 语言程序设计

第十章: C 语言的指针

授课 师习之

湘潭大学物理与光电工程学院
本章内容

1 、指针的定义、引用;
2 、指针与数组、动态数组;
3 、指针作为函数参数;
4 、指针数组与主函数参数;
什么是指针
计算机内存相当于一个巨大的一维数组,以字节为单位。
每个字节的序号,称为内存地址。

运算器
控制器

int b; | | | | | | | | | | | | | | | | | | | | | |
double c; 存储器
float d[2][3];
内 … …

变 … a b d[0][0] d[0][1] d[0][2] d[1][0] d[1][1] d[2][2] …


地 …
这里
址 int 1000 1004 double 1012
类型占 4 个字节, 1016float 占
占 8 字节, 1020 1024
4 字节。 1028 1032 …

指针:保存内存地址的变量。
C 语言中指针
1 、指针变量的定义: 类型 * 指针名 ;
指针的类型:用于区分地址处所存放的是什么类型的数据。

2 、指针变量的引用: 指针名
对其中保存的地址进行操作:

3 、指针指向的内容的引用:
* 指针 对指针所指向位置的数据进行操作;

指针名 [ 偏移 对距离所指向位置一定偏移处的数据进行操作。
量]
4 、指针的运算: +, -, ++, --, +=, -=
指针的加、减法运算,用于改变所指向的位置,进行前后移动。
C 语言中指针
获取可用地址的常用方式:
1 、使用取地址运算符 & 取得已定义的变量的地址:
int a; // 定义变量 a // 也可以简写为:
int *p; // 定义指针变量 p int a, *p=&a;
p=&a; // 令 p 指向变量 a

2 、数组名,不加方括号索引时表示数组的起始地址:
int a[10], *p; // 定义数组 a, 以及指针 p
p=a; // 令指针 p 指向 a 的数组 a 的起始位置。
//p=a; 等价于语句: p=&a[0];

3 、利用标准库函数、系统 API 等所提供的返回指针的函数:

int *p=(int *)malloc(n*sizeof(int)); // 获得一个长度为 n 的数组


C 语言中指针
【 10.1 】演示指针的基本用法。
#inlcude <stdio.h>

int main()
{
float a=1.23; // 定义变量 a 并赋初始值
float * p; // 定义指针 p

p=&a; // 取得变量 a 的地址,并赋值给 p ,即令指针 p 指向 a


printf("p= %d \n", p); // 显示 p 的值,即 a 的地址,是一个整数
scanf("%f", p); // 等价于: scanf("%f", &a);

printf("p: %f \n", *p); // 显示 p 所指向值,即 a 的值,是一个浮点数


*p=4.56; // 向 p 所指向的位置写入 4.56 ,等价于: a=4.56;
*p=2*(*p); // 将 p 指向的值乘 2 。等价于: a=2*a;

return 0;
}
指针与数组
【 10.2 】演示通过指针访问数组。
#include <stdio.h>

int main()
{
int i, a[5]={1,2,3,4,5}, *p=a; // 指针 p 初始指向 a 的起始位置
*p=123; // 或者: p[0]=123; 等价于 : a[0]=123;
*(p+2)=456; // 或者: p[2]=456; 等价于 : a[2]=456;
p=p+2; // 将 p 的位置向后移动 2 ,即指向 a[2]; 等价于: p=&a[2];
printf("%d\n", *p); // 显示 a[5] 的值 456
for(p=a; p-a<5; p++) // 通过指针 p 遍历数组 a
printf("%d ", *p);
printf("\n");
// 上面的 for 循环又等价于:
for(i=0; i<5; i++)
printf("%d ", a[i]);
return 0;
}
指针与数组
【 10.3 】通过指针操作数组:将字符串中井号 # 及之后的内容删掉。
#include <stdio.h> #include <stdio.h>
#include <string.h>
int main()
{ int main()
char s[10], *p; {
scanf("%s", s); char s[10], *p;
for(p=s; *p != '\0'; p++) scanf("%s", s);
if(*p=='#') if( (p=strchr(s,'#')) !=
break; 0 )
*p='\0'; *p='\0';
printf("%s", s); printf("%s", s);
return 0; return 0;
} }
注意: strchr 用于在字符串中查
注意:字符串通过结束符 '\0' 来标 找一个字符首次出现的位置,返回
记结束的位置。 指向它的指针。如果没找到,则返
回空指针:地址 0 。
动态数组
【 10.4 】使用动态数组:根据输入的大小创建数组,并向其中填入随机数。
#include <stdio.h>
#include <stdlib.h> 注意:
#include <time.h> 1 、 malloc 的参数为要分配的内存
int main() 区域大小,以字节为单位;
{ 2 、 malloc 的返回值为空类型指针
int i, n, *a; void * ,必须用强制类型转换来转
scanf("%d", &n); 换为需要的类型;
a=(int *)malloc(n*sizeof(int)); 3 、用 malloc 获取的内存在不使用
srand(time(0)); 时要用 free 函数释放。
for(i=0;i<n;i++) 4 、对 malloc 的调用有可能会失败
a[i]=rand(); // 对数组 a 赋值 (比如当内存不足),此时返回值等
for(i=0;i<n;i++) 于 0 ,表示空指针;
printf("%d ", a[i]); 5 、还有其他分配内存的函数。比如
free(a); realloc 用于改变已分配的内存区域
return 0; 的大小。
}
指针作为函数参数
函数的参数也可以是指针类型:
函数名 ( 类型 * 参数名 , 等
等 );
通过指针参数,函数可以访问定义在外面的变量。
【 10.5 】设计函数 swap ,交换两个 int 变量中的值。
#include <stdio.h>

void swapi(int *a, int *b) int main()


{ {
int tmp=*a; int x=123, y=456;
*a=*b; printf("x=%d y=%d\n", x, y);
*b=tmp; swapi(&x, &y);
} printf("x=%d y=%d\n", x, y);
return 0;
}
指针作为函数参数
【 10.6 】设计函数: 1 、为数组填入随机数; 2 、打印数组所有元素。
#include <stdio.h>
#include <stdlib.h> void randn(int *p, int n)
#include <time.h> {
int i;
void randn(int *p, int n); srand(time(0));
void printn(int *p, int n); for(i=0; i<n; i++)
p[i]=rand();
int main() }
{
int a[10]; void printn(int *p, int n)
randn(a, 10); {
printn(a, 10); int i;
return 0; for(i=0; i<n; i++)
} printf("%d ",p[i]);
printf("\n");
}
指针型数组
数组也可以是指针型——其中每个元素都是一个指针!
#include <stdio.h>
int main()
{
char str1[]="abc", str2[]="12345", str3[]="Hello, world!";
char *strs[]={str1, str2, str3};
printf("%s; %s; %s\n", strs[0], strs[1], strs[2]);
return 0; 字符指针数组:每个字符串所在的字符数组
} 的长度可以不同;

#include <stdio.h> 二维字符数组:每个字符串占据的一维数组


int main() 的长度一样(较短的字符串末尾有空位)。
{
char strs[][14]={"abc", "12345", "Hello, world!"};
printf("%s; %s; %s\n", strs[0], strs[1], strs[2]);
return 0;
}
主程序参数——程序的命令行参数
程序参数:在程序启动时,可以输入不定个数的字符串作为主函数的
参数,这是输入信息的另一种方式,也称为命令行参数。
输入程序参数的方法:
1 、从命令行运行时,在程序名后以空格隔开每个参数。如果参数中包含
空格,可以用双引号 "" 括起来避免被空格划分开。

运行命令 :copy ,提供了两个参


数: "a.txt" 和 "b.txt" 。
这里命令 copy 的作用是把文件
a.txt 拷贝为新文件 b.txt 。

运行程序 :ping ,提供了一个参


数: "www.baidu.com" 。
这里程序 ping 用于测试到某个网站的
网络连接是否可连通以及响应速度。
主程序参数——程序的命令行参数
程序参数:在程序启动时,可以输入不定个数的字符串作为主函数的
参数,这是输入信息的另一种方式,也称为命令行参数。
输入程序参数的方法:

2 、在 windows 系统中,可以通过程序快捷
方式的属性对话框指定其运行时参数。

3 、在 windows 系统中,将文件用鼠标拖
到程序文件上松开,则表示以该文件的文
件名(包含路径)为第一个参数来运行该
程序。多数应用程序默认会将第一个参数
作为需要处理的文件进行打开。
主程序参数——程序的命令行参数
C 语言中通过主函数的参数引用程序参数:
int main() // 忽略了参数的主函数

int main(int n, char *a[]) // 完整的主函数格式!

主函数 main 的两个参数,其类型是固定的,但参数名不是固定的,可以任意修改:


第 1 个:为 int 类型,表示主函数参数的个数;
第 2 个:为 char 型指针数组,保存了指向每个参数的指针——所有参数均为字符串!
int main(int argc, char *argv[]) // 参数类型固定,但参数名可自定义
int main(int an, char *ap[])
参数数组中,第 0 号元素为命令本身, 1 号元素为第一个参数,依次类推。
例如:假定 copy 程序的主程序定义为: int main(int argc, char *argv[]);
如果运行 copy 的命令行为: copy a.txt b.txt
第 0 号参数 argv[0] 的值为 "copy";
第 1 个参数 argv[1] 的值为 "a.txt";
第 2 个参数 argv[2] 的值为 "b.txt" 。
主程序参数——程序的命令行参数
【例 10.7 】显示程序参数的个数及每一个参数。
#include <stdio.h>
int main(int argc, char *argv[])
{
for(i=0; i<argc; i++)
printf(" 参数 %d: %s\n", argv[i]);
return 0;
}
主程序参数——程序的命令行参数
【例 10.8 】编写一个小程序,通过参数读取一个正整数,计算其阶乘。
#include <stdio.h>
int main(int an, char *ap[])
{
int n, s; // 分别保存读取的数字和其阶乘
sscanf(ap[1], "%d", i, &n); // 将第一个参数 ap[1] 转换为数字
for(s=1; n>1; n--) // 计算其阶乘
s*=n;
printf("%d\n", s); // 输出结果
return 0; // 返回 0 表示程序成功结束
}

注意:
1 、由于系统规则,所有程序参数均为字符串,所以这里用 sscanf 将其转换为数
字。 2 、 sscanf 与 scanf 功能类似,但不是从键盘、而是从字符串读取数据;
3 、也可以用 C 语言库函数 atof 来将字符串转换为数字,如将 "1.23" 变为
1.23 。
4 、用户运行程序时输入的参数个数或类型可能与代码设计时的可能不一致,会导
致程序出错。所以,一个完善的程序应该在处理参数前对参数格式进行检查!
主程序参数——程序的命令行参数
【例 10.8 】编写一个小程序,通过参数读取一个正整数,计算其阶乘。
#include <stdio.h>
int main(int an, char *ap[])
{
int n, s;
if(an!=2) // 检查参数个数。
{
printf(" 需要一个参数! \n");
return -1; // 程序设计中一般约定:主程序返回非 0 值表示运行时出错
}
if(1 != sscanf(ap[1], "%d", &n) || n<0) // 转换为数字,并检查格式
{ // 如果参数不是一个数字, sscanf 会失败: sscanf 的返回值表示成功读取的个
数。
printf(" 需要一个正整数! \n");
return -2;
}
for(s=1; n>1; n--) // 计算其阶乘
s*=n;
printf("%d\n", s); // 输出结果
return 0; // 返回 0 表示程序成功结束
}
练习题
1 、通过指针来查找数组中的最大值。

3 、编写函数 revarr 将数组内元素的次序颠倒存放。


可参考定义: void revarr(int *p, int n);

2 、编写函数 strrepeat ,将字符串 src 重复 n 次后保存到新的字符数


组,新数组用动态数组获取,并作为返回值返回。
可参考定义: char * strrepeat(char *src, int n);

4 、编写程序 sum ,从命令行参数读取不定个数的数字,对其求和后输出。

You might also like