【C语言入门】笔记九 (数组下+指针上)

程序设计题6

统计大写辅音字母。输入一个以回车结束的字符串(少于80个字符),统计并输出其中大写辅音字母的个数。大写辅音字母是指除"A" "E" "I" "O" "U"除外的大写字母。

#include <stdio.h>
int main(void){
	int i,n,num=0,result=0;
	char ch;
	while((ch=getchar())!='\n'){ 
		if((ch!='A'&&ch!='E'&&ch!='I'&&ch!='O'&&ch!='U')&&(ch>='A'&&ch<='Z')){
			num++;
			result=1;
		}
	}
	if(result==0){
		printf("NO");
	}else{
		printf("%d",num);
	}
	return 0;
}

(emmm...没用到数组...)

程序设计题7

字符串替换。输入一个以回车为结束的字符串(少于80个字符),将其中的大写字母用下面列出的对应大写字母替换,其余字符不变,输出替换后的字符串。

A->Z B->Y C->X...X->C Y->B Z->A

#include <stdio.h>
int main(void){
	char a[80];
	int i=0,j=0;
	while((a[i]=getchar())!='\n'){
		switch(a[i]){
			case 'A': a[i]='Z';break;
			case 'B': a[i]='Y';break;
			case 'C': a[i]='X';break;
			case 'D': a[i]='W';break;
			case 'E': a[i]='V';break;
			case 'F': a[i]='U';break;
			case 'G': a[i]='T';break;
			case 'H': a[i]='S';break;
			case 'I': a[i]='R';break;
			case 'J': a[i]='Q';break;
			case 'K': a[i]='P';break;
			case 'L': a[i]='O';break;
			case 'M': a[i]='N';break;
			case 'N': a[i]='M';break;
			case 'O': a[i]='L';break;
			case 'P': a[i]='K';break;
			case 'Q': a[i]='J';break;
			case 'R': a[i]='I';break;
			case 'S': a[i]='H';break;
			case 'T': a[i]='G';break;
			case 'U': a[i]='F';break;
			case 'V': a[i]='E';break;
			case 'W': a[i]='D';break;
			case 'X': a[i]='C';break;
			case 'Y': a[i]='B';break;
			case 'Z': a[i]='A';break;
		}
		i++;
	}
	while(j<=i){
		printf("%c",a[j]);
		j++; 
	}
	return 0;
}

(有没有更好的方法嘞?  

程序设计题8

字符串转换为十进制整数。输入一个以字符 "#" 结束的字符串,滤去所有非十六进制字符(不区分大小写),组成一个新的表示十六进制数字的字符串,然后将其转换为十进制后输出。如果过滤后字符串的首字符为 "-" ,则表示该数是负数。

#include <stdio.h>
#include <math.h>
int main(void){
	char a[1000],ch;
	int b[1000]={0};
	int i=0,j,n=0,num=0;
	while((ch=getchar())!='#'){
		if(i==0){
			if(ch=='-'){ //判断负数,负数就在结果前加上符号 
				n=1;
			}
		}
		if((ch>='0'&&ch<='9')||(ch>='A'&&ch<='F')||(ch>='a'&&ch<='f')){ //判断十六进制字符 
			a[i]=ch;
			i++;
		}
	}
	for(j=0;j<i;j++){ //将相应的十六进制字符转换为十进制整数的每一位 
		switch(a[j]){
			case '0': b[j]=0;break;
			case '1': b[j]=1;break;
			case '2': b[j]=2;break;
			case '3': b[j]=3;break;
			case '4': b[j]=4;break;
			case '5': b[j]=5;break;
			case '6': b[j]=6;break;
			case '7': b[j]=7;break;
			case '8': b[j]=8;break;
			case '9': b[j]=9;break;
			case 'A': b[j]=10;break;
			case 'B': b[j]=11;break;
			case 'C': b[j]=12;break;
			case 'D': b[j]=13;break;
			case 'E': b[j]=14;break;
			case 'F': b[j]=15;break;
			case 'a': b[j]=10;break;
			case 'b': b[j]=11;break;
			case 'c': b[j]=12;break;
			case 'd': b[j]=13;break;
			case 'e': b[j]=14;break;
			case 'f': b[j]=15;break;
		}
	}
    for(j=0;j<i;j++){ //计算十进制数并输出 
	    num+=b[j]*pow(16,(i-j-1));
	}
	if(n==1&&num!=0){
		printf("-");
	}
	printf("%d",num);
	return 0;
}


- - - 华丽的分界线 - - - 


第8章 指针

8.1.2 地址和指针

1. 地址

地址和指针是两个重要的概念,在程序运行中,变量或者程序代码会被存储在以字节为单位组织的存储器中。在C语言中,如果定义了一个变量,在编译时就会根据该变量的类型给它分配相应大小的内存单元。

例如int类型占2个字节,需要分配2个字节的内存单元,char型变量需要分配1个字节的内存单元float型变量和double型变量则需要分配4个字节和8个字节的内存单元

计算机对内存单元的数据操作一般是按“地址”存取的,也就是对内存单元进行编号。

因为int型变量的存储长度为2个字节,所以C语言编译器将它们分配到的地址为1000~1001、1002~1003和1004~1005的内存单元中

而程序执行时是将变量翻译为它所在的内存地址进行操作的

int x=1,y=2,z=3;
//
printf("%d",x);

如调用函数printf("%d",x):将x所在的内存地址1000~1001单元的内容按照整数格式输出。这种使用变量的方法叫做“直接访问”。一般以变量所在的内存单元的第1个字节地址作为它的地址,如上述代码中变量x的内存地址为1000,y的内存地址为1002,z的内存地址为1004。而它们的内容分别为1,2,3。

2. 指针

在C语言中还有一种使用变量的方法,即通过变量的地址进行操作:用指针访问内存和操纵地址。

假设再定义一个变量p,它位于2000单元,该单元中存放了变量x的地址1000,如图所示,此时,取出变量p的值1000,就可以访问访问内存为1000的单元,实现对变量x的操作,也就是说通过变量p,就可以间接访问变量x。

与直接使用变量x相比较,使用变量p访问变量x的过程实现了对变量x的间接操作。在C语言中把这种专门用来存放变量地址的变量称为“指针变量”,简称为指针。

C语言使用指针对变量的地址进行操作。指针是用来存放内存地址的变量,如果一个指针变量的值是另外一个变量的地址,那么就称指针变量指向那个变量。前面提及的p就是指针变量,它存放了变量x的指针地址,即指针变量p指向变量x。

如前面的scanf("%d",&n),就是将输入的值存储到变量n所在的内存单元里,&n即表示变量n的内存地址或存储位置。&称为地址运算符,&是一元运算符,与其他的一元运算符具有相同的优先级和从右往左的结合性。

8.1.3 指针变量的定义

如果在程序中声明一个变量并使用地址作为该变量的值,那么这个变量就是指针变量,一般形式为:

类型名 *指针变量型;
//如
int i, *p;

这里变量 p 是指向int型变量的指针。指针值可以是特殊的地址0,也可以是一个代表机器地址的正整数。(指针声明符 * 在定义指针变量时被使用,说明被定义的那个变量为指针)

指针变量用于存放变量的地址,由于不同类型的变量在内存中占用的存储单元不同,所以只知道内存地址还不能确定该地址上的对象,因此在定义指针变量时,还应该说明指针变量所指向的内存空间上所存放的数据的类型。

int * p; /*定义一个指针变量p,指向整型变量*/
char * p; /*定义一个指针变量p,指向字符变量*/
float * p; /*定义一个指针变量p,指向浮点型变量*/
double * p, * m; /*定义一个指针变量p和m,指向双精度实型变量*/
//定义多个指针变量时,每个指针变量前面都必须加上 * 

注:指针变量的类型并不是指针变量本身的类型而是指它所指向的变量的数据类型。无论何种类型的指针变量,它们都是用来存放地址的,因此指针变量自身所占的内存大小和它所指向的变量数据类型无关,尽管不同类型的变量所占的内存空间不同,但不同类型指针变量所占的内存空间大小都是相同的

指针变量被定义后,必须将指针变量和一个特定的变量进行关联后才可以使用它,也就是说指针变量也要先赋值再使用,当然指针变量被赋的值应该也是地址,如:

int i, *p; //定义指针变量p

/* 用以下方法给指针变量p赋值 */
p=&i; //将指针p指向变量i的地址(常用)
p=0; //等同于NULL,NULL再stdio.h中被定义的值为0
p=NULL; //空指针,空指针不指向任何单元
p=(int*)1732; //使用强制类型转换(int*)来避免编译错误,表示p指向地址为1732的int型变量

在定义指针变量时,要注意:

  1. 指针变量名是一个标识符,要按照C标识符的命名规则对指针变量进行命名。
  2. 指针变量的数据类型是它所指向的变量的类型,一般情况下一旦指针变量的类型被确定后,它只能指向同种类型的变量
  3. 在定义指针变量时需要使用指针声明符*,但指针声明符并不是指针的组成部分。例如定义int *p;时,说明p是指针变量,而不是*p

8.1.4 指针的基本运算

如果指针的值是某个变量的地址,通过指针就能间接访问那个变量,这些操作由取地址运算符&和间接访问运算符 * 完成。此外,相同类型的指针还能进项赋值、比较和算术运算。

1. 取地址运算和间接访问运算

单目运算符 & 用于给出变量的地址。例如:

int *p,a=0;
p=&a;

将整型变量a的地址赋给整型指针p,使指针p指向变量a。用运算符 & 取变量a的地址,并将这个地址值作为指针p的值,使指针p指向变量a。

在程序中,“ * ”除了用于定义指针变量外,还被用于访问指针所指向的变量,它也称为间接访问运算符。例如,当p指向a时,* pa访问同一个存储单元,* p的值就是a的值。* p就相当于a

2. 赋值运算

一旦指针被定义并赋值后,就可以如同其他类型变量一样进行赋值运算,例如:

int a=3,*p1,*p2;
p1=&a;
p2=p1;

将变量a的地址赋给指针p1,再将p1的值赋给p2,因此指针p1和指针p2都指向变量a。此时,*p1*p2a访问同一个储存单元,它们的值都一样。

给指针赋值是使指针和所指向变量之间建立关联的必要过程。指针之间的相互赋值只能在相同类型的指针之间进行,可以在定义时对指针进行赋值,也可以再程序运行过程中根据需要对指针重新赋值,但要特别注意:指针只有在被赋值以后才能被正确使用

注:只能将一个指针的值赋给另一个相同类型的指针。

8.1.5 指针变量的初始化

指针变量在定义后也要先赋值再引用,在定义指针变量时,可以同时对它赋初值。

如:

int a;
int *p1=&a; //在定义指针p1的同时将变量a的地址传递给指针变量p1
int *p2=p1;

以上对指针p1和p2的赋值都是在定义时进行的,使得指针p1和p2都指向变量a。

在进行指针初始化的时候注意:

  • 在指针定义或者初始化时变量名前面的 " * " 只表示该变量是个指针变量,它既不是乘法运算符也不是间接访问符。
  • 把一个变量的地址作为初始化值赋给指针变量时,该变量必须在此之前已经定义。因为变量只有在定义之后才被分配存储单元,它的地址才能赋给指针变量。
  • 可以用初始化了的指针变量给另一个指针变量作初始化。
  • 不能用数值(0可以)作为指针变量的初值,但可以将一个指针变量初始化为一个空指针(int *p=1000是不对的,int *p=0是将指针变量初始化为空指针,这里的0是ASCII编码字符的NULL的值)
  • 指针变量定义时的数据类型和它所指向的目标变量的数据类型必须一致,因为不同的数据类型所占用的存储单元的字节数不同。

注:指针变量定义后必须先赋值再引用,否则它将指向一个不确定的单元,可能会导致系统错误

练习8-1

如果有定义"int m, n, *p=&m;",与m=n等价的语句是(下列有A,B,C,D)

答:B. * p= * &n (星号代表指针变量,&n代表变量n的地址,*&n代表变量n的值)

8.2.2 指针作为函数的参数

例 8-3 有两个角色分别用变量a和b表示。为了实现角色交换,现制定了三套方案,通过函数调用来交换变量a和b的值,即swap1()、swap2()和swap3()。分析swap1()、swap2()和swap3()这三个函数中,哪个函数可以实现这样的功能。

#include <stdio.h>
void swap1(int x,int y), swap2(int *px,int *py), swap3(int *px,int *py);
int main(void){
	int a=1,b=2;
	int *pa=&a, *pb=&b;
	
	swap1(a,b);
	printf("After calling swap1: a=%d b=%d\n",a,b);
	
	a=1;
	b=2;
	swap2(pa,pb);
	printf("After calling swap2: a=%d b=%d\n",a,b);
	
	a=1;
	b=2;
	swap3(pa,pb);
	printf("After calling swap3: a=%d b=%d\n",a,b);
	return 0;
}
void swap1(int x,int y){
	int t;
	t=x;
	x=y;
	y=t;
}
void swap2(int *px,int *py){
	int t;
	t=*px;
	*px=*py;
	*py=t;
}
void swap3(int *px,int *py){
	int *pt;
	pt=px;
	px=py;
	py=pt;
}

运行结果:

第五章中的函数的参数包括实参和形参,两者类型需一致。如果将某个变量的地址作为函数的实参,相应的形参就是指针。

在C语言中实参和形参之间的数据传递是单向的“值传递”的方式,调用函数不能改变实参变量的值,当指针变量作为函数参数时也遵守这一个规则,调用函数不能改变实参指针变量的值,但可以改变实参指针变量所指向的变量的值。(有点绕)

这样的机制称为引用调用(Call by Reference)。采用引用调用机制需要在函数定义时将指针作为函数的形参,在函数调用时把变量的地址作为实参。

(理解理解)

swap2()中实参是指针变量pa和pb,其值是变量a和b的地址。在函数swap2()被调用时,将实参pa和pb的值传递给形参px和py。这样,px和py中分别存放了a和b的地址,px指向a,py指向b(如图),所以只要改变*px的值,就改变了该存储单元的内容,因此就达到了目的。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值