C语言学习(六)函数、数组和指针

参考书:《C Primer Plus》第六版


函数

直接做练习。函数这部分内容基本不用介绍。

  1. 设计应给函数min(x,y)返回两个double类型值的较小值并测试。

    #include<stdio.h>
    
    double min(double x,double y){
    	return x<y?x:y;
    }
    
    int main(void){
    	double d1=10.,d2=11.;
    	printf("min:%lf",min(d1,d2));
    	
    	return 0;
    }
    
  2. 设计函数chline(ch,i,j)打印指定的字符j行i列。

    #include<stdio.h>
    
    void chline(char ch,int i,int j){
    	for (int x=0;x<i;++x){
    		for(int y=0;y<j;++y)
    			putchar(ch);
    		putchar('\n');
    	}
    		
    }
    int main(void){
    	chline('x',3,3);
    	
    	return 0;
    }
    
  3. 编写一个函数,接受3个参数,一个字符和两个整数

    #include<stdio.h>
    
    void chline(char ch,int i,int j){
    	for (int x=0;x<i;++x)
    		putchar('\n');
    	for(int y=0;y<j;++y)
    		putchar(ch);
    }
    int main(void){
    	chline('x',3,3);
    	
    	return 0;
    }
    
  4. 计算两个数的调和平均数

    #include<stdio.h>
    
    double mean(double x,double y){
    	return 2./(1./x+1./y);
    }
    int main(void){
    	printf("两个数%.3lf,%.3lf 的调和平均数为%.3lf",2.,3.,mean(2.,3.));
    	
    	return 0;
    }
    
  5. 将两个值中的较大值赋值给这两个值

    #include<stdio.h>
    
    void largerOf(double* x,double* y){
    	*x=*x<*y?*y:*x;
    	*y=*x;
    }
    int main(void){
    	double d1=3.1,d2=4.2;
    	largerOf(&d1,&d2);
    	printf("%.3lf.,%.3lf",d1,d2);
    	
    	return 0;
    }
    
  6. 编写一个函数,将3个变量中最小值放入第一个参数,中间值放入第二个参数,最大值放入第三个参数

    #include<stdio.h>
    
    void sorts(double* x,double* y,double *z){
    	int v1=*x,v2=*y,v3=*z;
    	if(v1<v2){
    		if(v2<v3){
    			return;
    		}else if(v2>v3){
    			if(v1<v3){
    				*z=v2;
    				*y=v3;
    				return;
    			}else{
    				*y=v1;
    				*x=v3;
    				*z=v2;
    				return;
    			}
    		}
    	}else{
    		if(v2>v3){
    			*x=v3;
    			*z=v1;
    			return;
    		}else{
    			if(v1>v3){
    				*x=v2;
    				*y=v3;
    				*z=v1;
    			return;
    			}else{
    				*x=v2;
    				*y=v1;
    				*z=v3;
    				return;
    			}
    		}
    	}
    }
    int main(void){
    	double d1=3.1,d2=4.2,d3=1.1;
    	sorts(&d1,&d2,&d3);
    	printf("%.3lf.,%.3lf,%.3lf",d1,d2,d3);
    	
    	return 0;
    }
    
  7. 编写函数读取字符。

    #include<stdio.h>
    #include<ctype.h>
    
    int getloc(char ch){
    	return ch-'a'+1;
    }
    
    void getchs(){
    	char ch;
    	while((ch=getchar())!=EOF){
    		if(isalpha(ch)){
    			printf("%d",getloc(tolower(ch)));
    		}else
    			printf("-1");
    		if(getchar()=='\n')
    			continue;
    	}
    }
    int main(void){
    	getchs();
    	
    	return 0;
    }
    
    1. 计算幂,用递归和不用递归
    #include<stdio.h>
    #include<ctype.h>
    
    double power(double d,int a){
    	if(d==0.&&a==0){
    	printf("未定义。");
    	return 0.;
    	}
    	if(d==0.)
    		return 0.;
    	if(a==0)
    		return 1.;
    	if(a<0){
    		d=1./d;
    		a=-a;
    	}
    	double k=d;
    	for(int i=0;i<a-1;i++){
    		k*=d;
    	}
    	return k;
    }
    //递归版本
    double powerR(double d,int a){
    	if(d==0.&&a==0){
    	printf("未定义。");
    	return 0.;
    	}
    	if(d==0)
    		return 0.;
    	if(a==0)
    		return 1.;
    	if(a<0){
    		d=1./d;
    		a=-a;
    		return powerR(d,a);
    	}
    	if(a==1)
    		return d;
    	else
    		return d*powerR(d,a-1);
    }
    int main(void){
    	double d;
    	int i;
    	printf("Enter a double value: ");
    	while(scanf_s("%lf",&d)==1){
    		printf("Enter an integer:");
    		scanf_s("%d",&i);
    		printf("power(%lf,%d)=%lf\n",d,i,power(d,i));
    		printf("power(%lf,%d)=%lf\n",d,i,powerR(d,i));
    		printf("Enter a double value: ");
    	}
    	printf("Bye.");
    	return 0;
    }
    

    输出

    Enter a double value: 2.1
    Enter an integer:5
    power(2.100000,5)=40.841010
    power(2.100000,5)=40.841010
    Enter a double value: 3.2
    Enter an integer:5
    power(3.200000,5)=335.544320
    power(3.200000,5)=335.544320
    Enter a double value: 0
    Enter an integer:1
    power(0.000000,1)=0.000000
    power(0.000000,1)=0.000000
    Enter a double value: 0
    Enter an integer:0
    未定义。power(0.000000,0)=0.000000
    未定义。power(0.000000,0)=0.000000
    Enter a double value: 1
    Enter an integer:0
    power(1.000000,0)=1.000000
    power(1.000000,0)=1.000000
    Enter a double value: ^Z
    ^Z
    2
    Bye.
    C:\Users\xhh\Source\Repos\cPrimerPlus_study\Debug\cPrimerPlus_study.exe (进程 34860)已退出,代码为 0。
    按任意键关闭此窗口. . .
    
  8. 以指定进制打印指定的数

    #include<stdio.h>
    #include<ctype.h>
    
    void to_base_n(int x,int a){
    	if(a>10||a<2)
    		return;
    	int k=x%a;
    	if(x>=a)
    		to_base_n(x/a,a);
    	putchar(k+'1'-1);
    }
    int main(void){
    	to_base_n(129,8);
    	return 0;
    }
    
  9. 编写Fibonacci()函数

    #include<stdio.h>
    #include<ctype.h>
    
    int Fibonacci(int k){
    	if(k<3)
    		return 1;
    	int n1=1,n2=1,n3;
    	for(int i=0;i<k-2;++i){
    		n3=n2;
    		n2+=n1;
    		n1=n3;
    	}
    	return n2;
    }
    //递归版本,对比可以明显看出递归版本处理这类问题时的优势
    int FibonacciD(int k){
    	if(k>2)
    		return FibonacciD(k-2)+FibonacciD(k-1);
    	else
    		return 1;
    }
    int main(void){
    	for(int i=1;i<11;++i){
    		printf("第%d个斐波那契数为:%d\n",i,Fibonacci(i));
    		printf("第%d个斐波那契数为:%d\n",i,FibonacciD(i));
    	}
    	return 0;
    }
    
    1个斐波那契数为:11个斐波那契数为:12个斐波那契数为:12个斐波那契数为:13个斐波那契数为:23个斐波那契数为:24个斐波那契数为:34个斐波那契数为:35个斐波那契数为:55个斐波那契数为:56个斐波那契数为:86个斐波那契数为:87个斐波那契数为:137个斐波那契数为:138个斐波那契数为:218个斐波那契数为:219个斐波那契数为:349个斐波那契数为:3410个斐波那契数为:5510个斐波那契数为:55
    
    C:\Users\xhh\Source\Repos\cPrimerPlus_study\Debug\cPrimerPlus_study.exe (进程 31440)已退出,代码为 0。
    按任意键关闭此窗口. . .
    

数组和指针

1. 数组

要说起来,个人认为,不管是C还是C++,数组都是很不好用的,C++中基本需要用数组的地方用Vector也没问题的,而且用Vector要方便很多,所以C++里面都很少用到这种数组。但C里面还是非常需要掌握这个概念的。

  1. 初始化
int days[12]={1,2,3,4};//数组中前四个元素为指定值,后面的数全部初始化为0
int arr1[]={1,2,3,4};//编译器自动确定数组 大小
int data[4];//只声明,未初始化
  1. 指定初始化器

可以初始化指定数组元素。如

int arr[6]={[5]=212};
int stuff[]={1,[6]=23,8,10};//数组大小为9,部分元素初始化为指定值,其余初始化为0

这个特性是C++没有的。

  1. 给数组元素赋值

C不允许将数组作为变量赋值给另一个数组。

  1. 数组边界

要自己注意数组下标,编译器不会检查数组下标的。C语言不检查下标是因为信任程序员。同时少了检查下标是否越界这一步骤也可以使程序更快运行。

  1. 指定数组大小

声明数组时方括号中只可以使用整型常量表达式,sizeof表达式被视为整型常量,但const不是(与C++不同)。

int a[5];
int a1[sizeof(int)+1)];

2. 多维数组

多维数组就是数组的数组。

计算机内部二维数组是按顺序存储的。

3. 指针和数组

要想学好C语言,用好指针是必不可少的。指针提供一种以符号形式使用地址的方式。而计算机的硬件指令非常依赖地址,指针在某种程度上把程序员想要传达的指令以更接近机器的方式表达。所以,使用指针的程序更有效率,尤其是在处理数值时。数组表示法其实是在变相的使用指针。

有一点需要记住:数组名时数组首元素的地址。如filzny是一个数组,那么下面的语句为真:

filzy==&filzy[0];

知道数组名是数组首地址这一点有什么用呢,既然是地址,我们就可以把它赋值给指针变量,然后也可以通过绑定的指针来修改变量的值。

如下,程序清单1

#include<stdio.h>
#include<ctype.h>

int main(void){
	short datas[4];
	short *pti;
	short index;
	double bills[4];
	double *ptf;
	pti=datas;
	ptf=bills;
	printf("%23s %10s\n","short","double");
	for(index=0;index<4;index++)
		printf("pointers +%d: %10p %10p\n",index,pti+index,ptf+index);
	return 0;
}

输出

                  short     double
pointers +0:   00B8FA68   00B8FA28
pointers +1:   00B8FA6A   00B8FA30
pointers +2:   00B8FA6C   00B8FA38
pointers +3:   00B8FA6E   00B8FA40

C:\Users\xhh\Source\Repos\cPrimerPlus_study\Debug\cPrimerPlus_study.exe (进程 9816)已退出,代码为 0。
按任意键关闭此窗口. . .

系统中,地址按字节编码,short类型占2字节,double类型占8字节。在C中,指针加1意味着增加一个存储单元。对于数组而言,加1后的地址为下一个元素的地址。这也是我们声明指针时必须声明指针指向对象的类型的原因之一。

注意:

  • 指针的值为它所指向的对象的地址。地址的表示方式取决于计算机内部的硬件。许多计算机都是按字节编码,即内存中的每个字节都按顺序编码。较大对象的地址如double通常是该对象第一个字节的地址。
  • 在指针之前使用*可以得到该指针所指向的对象的值。
  • 指针加1,指针的值递增它所指向类型的大小。

如果能理解这些机制,那么下面的等式也不能理解:

dates+2==&dates[2];//地址相同,但仔细想想不能完全等同的,左边完全是地址,而右边则是取数组中的元素的地址
*(dates+2)==dates[2];//元素值相等

这里还要注意第二个等式,因为*的优先级高于加号,所以必须要有括号。*可以称为解引用符号。

4. 函数、数组和指针

先看下面的示例,程序清单2

#include<stdio.h>
#include<ctype.h>

int sum(int *a,int n){
	int s=0;
	for(int i=0;i<n;++i)
		s+=*(a+i);
	printf("%zd\n",sizeof a);
	return s;
}

int main(void){
	int marbles[10]={1,1,2,3,4,5,6,7};
	int s=sum(marbles,10);
	printf("%zd\n",sizeof marbles);
	printf("sum=%d",s);
}
4
40
sum=29
C:\Users\xhh\Source\Repos\cPrimerPlus_study\Debug\cPrimerPlus_study.exe (进程 23792)已退出,代码为 0。
按任意键关闭此窗口. . .

程序清单3

#include<stdio.h>
#include<ctype.h>

int sum(int *a,int *b){
	int s=0;
	while(a<b){
		s+=*a;
		a++;
	}
	printf("%zd\n",sizeof a);
	return s;
}

int main(void){
	int marbles[10]={1,1,2,3,4,5,6,7};
	int s=sum(marbles,marbles+10);
	printf("%zd\n",sizeof marbles);
	printf("sum=%d",s);
}

输出结果同程序清单2。

需要探讨的几个点:

  • 程序清单2中,sum函数的第一个参数为数组,我们写成指针的形式和数组的形式是等效的:int* aint a[],然而用sizeof得到的结果只是一个int变量的大小4,而在main函数中,用sizeof求出数组的大小为40字节,由此可知,我们向函数传递数组时实际传递的其实是数组的首元素的地址,这里还是要区分整型数组和整型指针,所以我们要用函数计算数组元素和时除了传递数组还要传递数组的大小,不告诉函数数组的大小的话函数无法知道数组的实际大小,只知道数组首元素的指针。
  • 程序清单3中,我们用另一种方式来计算数组的元素和,即向函数传递数组的首尾元素指针,注意marbles+10得到的不是数组的尾元素的地址,实际得到的是尾元素后一个元素的地址。但我们这样做是没问题的,即使这个地址是数组之外的地址了,只要我们不对它解引用。这里也就存在一个可能的误区:如果我们这样*(marbles+10)*或者marbles[10]这时就可能出现不可预知的风险,因为这个地址不是我们定义的,那么这样访问这个地址上的值就是非法的,可能会造成内存泄漏,出现一些计算机安全问题。
  • 程序清单3中的函数的循环体还可以压缩为一个语句:s+=*a++*和++的优先级相同,从右往左,但后缀形式的++导致了先运算之后再加1,等同于s+=*(a++),注意区分++的前缀形式和后缀形式。一般来说还是最好不要这样简写,可读性差而且容易出错。

不管是指针表示法还是数组表示法都只取决于我们的个人喜好,对于C语言,指针表示法有时再编译时能生成效率更高的代码。但如果觉得用数组表示法看起来更舒服那用数组表示法也没什么问题。

5. 指针操作

主要有以下一些操作:

  • 赋值
  • 解引用
  • 取址
  • 指针和整数相加减
  • 递增指针和递减指针
  • 指针求差
  • 指针比较

这些操作前面都已经有所接触了,就不用介绍了。

6. 保护数组中的数据

通常我们向一个函数传递一个变量,如果不用改变这个变量的值的话,我们都是传递这个变量的副本,这样可以避免函数修改原始数据,如果需要通过函数修改变量数值时就需要传递变量的指针。然而对于数组来说我们只能传递指针,这样效率更高,而且有时我们正好需要修改数组的元素。但有时我们不希望函数修改数组元素,传递指针的方式就显得有些问题了。这时我们可以在函数声明形参时加一个关键字const,有了const,如果函数试图修改数组元素编译时会报错。

const很灵活,我们可以创建const数组、const指针和指向const的指针。其中的意义需要去体会。

7. 指针和多维数组

既然多维数组是数组的数组,那么多维数组对应的指针也就是指针的指针。这里需要一些举一反三的能力。

直接看以下下面的程序,程序清单4

#include<stdio.h>
#include<ctype.h>

int main(void){
	int zippo[4][2]={{2,4},{6,8},{1,3},{5,7}};
	printf("zippo = %p, zippo+1 = %p\n",zippo,zippo+1);
	printf("zippo[0] = %p,zippo[0]+1 = %p\n",zippo[0],zippo[0]+1);
	printf("*zippo = %p,*zippo+1= %p \n",*zippo,*zippo+1);
	printf("zippo[0][0] = %d\n",zippo[0][0]);
	printf("*zippo[0] = %d\n",*zippo[0]);
	printf("**zippo = %d\n",**zippo);
	printf("zippo[2][1] = %d\n",zippo[2][1]);
	printf("*(*(zippo+2)+1) = %d\n",*(*(zippo+2)+1));
	return 0;
}
zippo = 0137F974, zippo+1 = 0137F97C
zippo[0] = 0137F974,zippo[0]+1 = 0137F978
*zippo = 0137F974,*zippo+1= 0137F978
zippo[0][0] = 2
*zippo[0] = 2
**zippo = 2
zippo[2][1] = 3
*(*(zippo+2)+1) = 3

C:\Users\xhh\Source\Repos\cPrimerPlus_study\Debug\cPrimerPlus_study.exe (进程 29428)已退出,代码为 0。
按任意键关闭此窗口. . .

首先是zippozippo[0]*zippo*以及&zippo[0][0]都相等,地址都是相等的。但又是有差别的。

然后要理解*(*(zippo+2)+1)等同于zippo[2][1],这样基本就可以了。

指向多维数组的指针

如下

int (*pz)[2];//pz指向一个包含两个int类型值的数组
int *paz[2];//pax指向一个包含两个指针元素的数组,每个元素都指向int的指针。[]的优先级高于*
int zippo[4][2]={{2,4},{6,8},{1,3},{5,7}};
pz=zippo;

函数和多维数组

程序清单5

#include<stdio.h>
#include<ctype.h>
#define ROWS 3
#define COLS 4
void sumRows(int ar[][COLS],int rows);
void sumCols(int [][COLS],int);
int sum2d(int (*ar)[COLS],int rows);
int main(void){
	int junk[ROWS][COLS]={
		{2,3,4,8},
		{3,5,7,9},
		{12,10,8,6}
	};
	sumRows(junk,ROWS);
	sumCols(junk,ROWS);
	printf("Sum of all elements=%d\n",sum2d(junk,ROWS));
	return 0;
}

void sumRows(int ar[][COLS], int rows)
{
	int r;
	int c;
	int tot;
	for(r=0;r<rows;r++){
		tot=0;
		for(c=0;c<COLS;c++)
			tot+=ar[r][c];
		printf("row %d:sum=%d\n",r,tot);
	}
}

void sumCols(int ar[][COLS], int rows)
{
	int r;
	int c;
	int tot;
	for (c=0;c<COLS;c++){
		tot=0;
		for(r=0;r<rows;r++)
			tot+=ar[r][c];
		printf("col: %d:sum=%d\n",c,tot);
	}
}

int sum2d(int(*ar)[COLS], int rows)
{
	int c,r,tot=0;
	for(c=0;c<COLS;c++)
		for(r=0;r<rows;r++)
			tot+=ar[r][c];
	return tot;
}
row 0:sum=17
row 1:sum=24
row 2:sum=36
col: 0:sum=17
col: 1:sum=18
col: 2:sum=19
col: 3:sum=23
Sum of all elements=77

C:\Users\xhh\Source\Repos\cPrimerPlus_study\Debug\cPrimerPlus_study.exe (进程 30240)已退出,代码为 0。
按任意键关闭此窗口. . .

8. 变长数组(VLA)

略。(VS上C语言貌似不能用变长数组,编辑时会提示错误。)

9. 复合字面值

如:(int []) {1,2,3,4,5}就是一个复合字面值。它是匿名数组,一般是直接用。

程序清单6

#include<stdio.h>
int sum(int *a,int l);
int main(void){
	printf("%d",sum((int []){1,2,3,4,5},5));
	return 0;
}
int sum(int *a,int l){
	int i,sum=0;
	for(i=0;i<l;++i)
		sum+=*(a+i);
	return sum;
}
15
C:\Users\xhh\Source\Repos\cPrimerPlus_study\Debug\cPrimerPlus_study.exe (进程 27732)已退出,代码为 0。
按任意键关闭此窗口. . .

10. 练习

#include<stdio.h>
#define MONTHS 12
#define YEARS 5
int main(void){
	const float rain[YEARS][MONTHS]={
		{4.3,4.3,4.3,3.0,2.0,1.2,0.2,0.2,0.4,2.4,3.5,6.6},
		{8.5,8.3,1.2,1.5,2.3,0.0,5.3,0.9,0.3,0.8,0.4,0.3},
		{9.2,8.3,1.2,1.5,6.7,4.3,4.3,2.3,3.4,5.3,5.3,3.3},
		{7.4,9.9,8.4,3.3,1.2,0.8,0.9,0.4,0.0,0.6,1.7,4.5},
		{7.6,5.6,4.4,3.2,3.4,6.7,4.3,1.1,2.1,1.3,4.4,2.2}
	};
	int y,m;
	float subtot,tot;
	printf(" YEAR    RAINALL  (inches)\n");
	for(y=0,tot=0;y<YEARS;++y){
		for(m=0,subtot=0;m<MONTHS;++m)
			subtot+=*(*(rain+y)+m);
		printf("%5d      %1.5f\n",2010+y,subtot);
		tot+=subtot;
	}
	printf("\nThe yearly average is %.1f inches.\n\n",tot/YEARS);
	printf("MONTHLY AVERAGE: \n\n");
	printf("Jan Feb Mar Arp May Jun Jul Aug Sep Oct Nov Dec\n");
	for(m=0;m<MONTHS;++m){
		for(y=0,subtot=0;y<YEARS;++y)
			subtot+=*(*(rain+y)+m);
		printf("%.1f ",subtot/YEARS);
	}
	printf("\n");
	return 0;
}
 YEAR    RAINALL  (inches)
 2010      32.40000
 2011      29.80000
 2012      55.10000
 2013      39.10000
 2014      46.30000

The yearly average is 40.5 inches.

MONTHLY AVERAGE:

Jan Feb Mar Arp May Jun Jul Aug Sep Oct Nov Dec
7.4 7.3 3.9 2.5 3.1 2.6 3.0 1.0 1.2 2.1 3.1 3.4

C:\Users\xhh\Source\Repos\cPrimerPlus_study\Debug\cPrimerPlus_study.exe (进程 25232)已退出,代码为 0。
按任意键关闭此窗口. . .
  1. 用3种方式拷贝数组

    #include<stdio.h>
    void copy_arr(double *,double *,int);
    void copy_ptr(double *,double *,int);
    void copy_ptrs(double *,double *,double*);
    int main(void){
    	double sources[5]={1.1,2.2,3.3,4.4,5.5};
    	double target1[5],target2[5],target3[5];
    	copy_arr(target1,sources,5);
    	copy_ptr(target2,sources,5);
    	copy_ptrs(target3,sources,sources+5);
    	int i;
    	for(i=0;i<5;i++)
    		printf("%.1lf %.1lf %.1lf %.1lf\n",*(sources+i),target1[i],*(target2+i),*(target3+i));
    	return 0;
    }
    void copy_arr(double *t,double *s,int len){
    	int i;
    	for(i=0;i<len;i++)
    		t[i]=s[i];
    }
    void copy_ptr(double*t,double*s,int len){
    	int i;
    	for(i=0;i<len;i++)
    		*(t+i)=*(s+i);
    }
    void copy_ptrs(double *t,double *b,double *e){
    	while(b!=e){
    		*t=*b;
    		t++;
    		b++;
    	}
    }
    
    1.1 1.1 1.1 1.1
    2.2 2.2 2.2 2.2
    3.3 3.3 3.3 3.3
    4.4 4.4 4.4 4.4
    5.5 5.5 5.5 5.5
    
    C:\Users\xhh\Source\Repos\cPrimerPlus_study\Debug\cPrimerPlus_study.exe (进程 10060)已退出,代码为 0。
    按任意键关闭此窗口. . .
    
  2. 编写一个求int数组最大值的函数。

    #include<stdio.h>
    int max(int *,int);
    int main(void){
        int ar[5]={2,33,23,43,5};
        printf("max:%d",max(ar,5));
    }
    int max(int *arr,int len){
        int i,sol;
        for(i=1,sol=*arr;i<len;i++)
            sol=sol<*(arr+i)?*(arr+i):sol;
        return sol;
    }
    
    max:43
    C:\Users\xhh\Source\Repos\cPrimerPlus_study\Debug\cPrimerPlus_study.exe (进程 30488)已退出,代码为 0。
    按任意键关闭此窗口. . .
    
  3. 编写一个返回double数组最大值下标的函数

    #include<stdio.h>
    int maxIndex(double *,int);
    int main(void){
        double ar[6]={1.2,3.3,2.3,5.5,6.3,2.2};
        printf("%d",maxIndex(ar,6));
    }
    int maxIndex(double *ar,int len){
        double max=*ar;
        int i,ind=1;
        for(int i=1;i<len;i++){
            if(max<*(ar+i)){
                max=*(ar+i);
                ind=i;
            }
        }
        return ind;
    }
    
    4
    C:\Users\xhh\Source\Repos\cPrimerPlus_study\Debug\cPrimerPlus_study.exe (进程 22560)已退出,代码为 0。
    按任意键关闭此窗口. . .
    
  4. 编写一个返回double数组的最大值和最小值的差值的函数

    #include<stdio.h>
    double dis(double *,int);
    int main(void){
        double ar[6]={1.2,3.3,2.3,5.5,6.3,2.2};
        printf("%.1lf",dis(ar,6));
    }
    double dis(double *arr,int len){
        double max=*arr,min=*arr;
        int i;
        for(i=1;i<len;i++){
            max=max<*(arr+i)?*(arr+i):max;
            min=min<*(arr+i)?min:*(arr+i);
        }
        return max-min;
    }
    
    5.1
    C:\Users\xhh\Source\Repos\cPrimerPlus_study\Debug\cPrimerPlus_study.exe (进程 30036)已退出,代码为 0。
    按任意键关闭此窗口. . .
    
  5. 编写一个将double 数组中的数据倒序排列的函数

    #include<stdio.h>
    void reverse(double *,int);
    int main(void){
        double ar[6]={1.2,3.3,2.3,5.5,6.3,2.2};
        int i=0;
        for(i=0;i<6;i++)
            printf("%.1f ",*(ar+i));
        reverse(ar,6);
        printf("\n");
        for(i=0;i<6;i++)
            printf("%.1f ",*(ar+i));
    }
    void reverse(double *ar,int len){
        double temp;
        int i;
        for(i=0;i<len/2;i++){
            temp=*(ar+i);
            *(ar+i)=*(ar+len-1-i);
            *(ar+len-1-i)=temp;
        }
    }
    
    1.2 3.3 2.3 5.5 6.3 2.2
    2.2 6.3 5.5 2.3 3.3 1.2
    C:\Users\xhh\Source\Repos\cPrimerPlus_study\Debug\cPrimerPlus_study.exe (进程 6464)已退出,代码为 0。
    按任意键关闭此窗口. . .
    
  6. 用练习2中的一个拷贝函数拷贝一个二维数组。

    #include<stdio.h>
    #define MONTHS 12
    #define YEARS 5
    void copy_arr(double *,double *,int);
    void copy_ptr(double *,double *,int);
    void copy_ptrs(double *,double *,double*);
    int main(void){
    	const double rain[YEARS][MONTHS]={
    		{4.3,4.3,4.3,3.0,2.0,1.2,0.2,0.2,0.4,2.4,3.5,6.6},
    		{8.5,8.3,1.2,1.5,2.3,0.0,5.3,0.9,0.3,0.8,0.4,0.3},
    		{9.2,8.3,1.2,1.5,6.7,4.3,4.3,2.3,3.4,5.3,5.3,3.3},
    		{7.4,9.9,8.4,3.3,1.2,0.8,0.9,0.4,0.0,0.6,1.7,4.5},
    		{7.6,5.6,4.4,3.2,3.4,6.7,4.3,1.1,2.1,1.3,4.4,2.2}
    	};
    	double target1[YEARS][MONTHS];
    	int m,y;
    	for(y=0;y<YEARS;y++)
    		copy_ptr(*(target1+y),*(rain+y),MONTHS);
    	for(y=0;y<YEARS;++y){
    		for(m=0;m<MONTHS;++m)
    			printf("%.1f ",*(*(target1+y)+m));
    		printf("\n");
    	}
    }
    void copy_arr(double *t,double *s,int len){
    	int i;
    	for(i=0;i<len;i++)
    		t[i]=s[i];
    }
    void copy_ptr(double*t,double*s,int len){
    	int i;
    	for(i=0;i<len;i++)
    		*(t+i)=*(s+i);
    }
    void copy_ptrs(double *t,double *b,double *e){
    	while(b!=e){
    		*t=*b;
    		t++;
    		b++;
    	}
    }
    
    4.3 4.3 4.3 3.0 2.0 1.2 0.2 0.2 0.4 2.4 3.5 6.6
    8.5 8.3 1.2 1.5 2.3 0.0 5.3 0.9 0.3 0.8 0.4 0.3
    9.2 8.3 1.2 1.5 6.7 4.3 4.3 2.3 3.4 5.3 5.3 3.3
    7.4 9.9 8.4 3.3 1.2 0.8 0.9 0.4 0.0 0.6 1.7 4.5
    7.6 5.6 4.4 3.2 3.4 6.7 4.3 1.1 2.1 1.3 4.4 2.2
    
    C:\Users\xhh\Source\Repos\cPrimerPlus_study\Debug\cPrimerPlus_study.exe (进程 21380)已退出,代码为 0。
    按任意键关闭此窗口. . .
    
  7. 将一个7元素的数组中的第3-5元素拷贝到另一个数组。

    #include<stdio.h>
    
    void copy_arr(double *,double *,int);
    void copy_ptr(double *,double *,int);
    void copy_ptrs(double *,double *,double*);
    int main(void){
    	double ar[]={1.1,2.2,3.3,4.4,5.5,6.6,7.7};
    	double target[3];
    	copy_ptr(target,ar+2,3);
    	for(int i=0;i<3;++i)
    		printf("%.1lf ",*(target+i));
    	return 0;
    }
    void copy_arr(double *t,double *s,int len){
    	int i;
    	for(i=0;i<len;i++)
    		t[i]=s[i];
    }
    void copy_ptr(double*t,double*s,int len){
    	int i;
    	for(i=0;i<len;i++)
    		*(t+i)=*(s+i);
    }
    void copy_ptrs(double *t,double *b,double *e){
    	while(b!=e){
    		*t=*b;
    		t++;
    		b++;
    	}
    }
    
    3.3 4.4 5.5
    C:\Users\xhh\Source\Repos\cPrimerPlus_study\Debug\cPrimerPlus_study.exe (进程 29220)已退出,代码为 0。
    按任意键关闭此窗口. . .
    
  8. 编写一个函数将两个数组中对应的元素相加,结果保存在第三个数组中。

    #include<stdio.h>
    
    void add(int*,int*,int*,int);
    int main(void){
    	int ar1[]={1,4,5,8};
    	int ar2[]={1,0,4,6};
    	int ar3[4];
    	add(ar1,ar2,ar3,4);
    	for(int i=0;i<4;++i)
    		printf("%d ",*(ar3+i));
    	return 0;
    }
    void add(int *ar1,int*ar2,int*ar3,int len){
    	int i;
    	for(i=0;i<len;i++)
    		*(ar3+i)=*(ar1+i)+*(ar2+i);
    }
    
    2 4 9 14
    C:\Users\xhh\Source\Repos\cPrimerPlus_study\Debug\cPrimerPlus_study.exe (进程 1240)已退出,代码为 0。
    按任意键关闭此窗口. . .
    
  9. 编写一个函数显示数组的内容,再编写一个函数将数组各元素数组翻倍

    #include<stdio.h>
    #define C 5
    #define R 3
    void printArr(int ar[][C],int  );
    void plusTwo(int ar[][C],int );
    int main(void){
    	int arr[R][C]={
    		{2,3,4,5,6},
    		{3,4,5,3,2},
    		{3,4,5,6,2}
    	};
    	printArr(arr,3);
    	plusTwo(arr,3);
    	printf("\n");
    	printArr(arr,3);
    }
    void printArr(int ar[][C],int r){
    	int i,j;
    	for(i=0;i<r;i++){
    		for(j=0;j<C;j++)
    			printf("%d ",*(*(ar+i)+j));
    		printf("\n");
    	}
    }
    void plusTwo(int ar[][C],int r){
    	int i,j;
    	for(i=0;i<r;i++){
    		for(j=0;j<C;j++)
    			*(*(ar+i)+j)*=2;
    	}
    }
    
    2 3 4 5 6
    3 4 5 3 2
    3 4 5 6 2
    
    4 6 8 10 12
    6 8 10 6 4
    6 8 10 12 4
    
    C:\Users\xhh\Source\Repos\cPrimerPlus_study\Debug\cPrimerPlus_study.exe (进程 24076)已退出,代码为 0。
    按任意键关闭此窗口. . .
    
  10. 重写练习1中的程序

    #include<stdio.h>
    #define MONTHS 12
    #define YEARS 5
    void showInfo(float rain[][MONTHS]);
    int main(void){
    	const float rain[YEARS][MONTHS]={
    		{4.3,4.3,4.3,3.0,2.0,1.2,0.2,0.2,0.4,2.4,3.5,6.6},
    		{8.5,8.3,1.2,1.5,2.3,0.0,5.3,0.9,0.3,0.8,0.4,0.3},
    		{9.2,8.3,1.2,1.5,6.7,4.3,4.3,2.3,3.4,5.3,5.3,3.3},
    		{7.4,9.9,8.4,3.3,1.2,0.8,0.9,0.4,0.0,0.6,1.7,4.5},
    		{7.6,5.6,4.4,3.2,3.4,6.7,4.3,1.1,2.1,1.3,4.4,2.2}
    	};
    	showInfo(rain);
    	return 0;
    }
    void showInfo(float rain[][MONTHS]){
    	int y,m;
    	float subtot,tot;
    	printf(" YEAR    RAINALL  (inches)\n");
    	for(y=0,tot=0;y<YEARS;++y){
    		for(m=0,subtot=0;m<MONTHS;++m)
    			subtot+=*(*(rain+y)+m);
    		printf("%5d      %1.5f\n",2010+y,subtot);
    		tot+=subtot;
    	}
    	printf("\nThe yearly average is %.1f inches.\n\n",tot/YEARS);
    	printf("MONTHLY AVERAGE: \n\n");
    	printf("Jan Feb Mar Arp May Jun Jul Aug Sep Oct Nov Dec\n");
    	for(m=0;m<MONTHS;++m){
    		for(y=0,subtot=0;y<YEARS;++y)
    			subtot+=*(*(rain+y)+m);
    		printf("%.1f ",subtot/YEARS);
    	}
    	printf("\n");
    }
    
  11. 编写程序,提醒用户输入3组数,每组包含5个double类型的数,然后程序完成一些任务。

    #include<stdio.h>
    #define R 3
    #define C 5
    void store(double [][C]);
    double mean(double *);
    double meanAll(double [][C]);
    double max(double [][C]);
    void printArr(double [][C]);
    int main(void){
    	double arr[R][C];
    	store(arr);
    	for(int i=0;i<R;i++)
    		printf("Row %d,mean=%.2lf\n",i,mean(*(arr+i)));
    	printf("MEAN: %.2lf\n",meanAll(arr));
    	printf("Max: %.2lf\n",max(arr));
    	printArr(arr);
    }
    void store(double arr[][C]){
    	 int times=0,i;
    	 
    	 for (i=0;i<R;i++){
    		 double * temp=*(arr+i);
    		 printf("请输入5个double数:\n");
    		 times=0;
    		while(times!=5){
    			times=scanf_s("%lf %lf %lf %lf %lf",temp,temp+1,temp+2,temp+3,temp+4);
    			if(times!=5)
    				printf("不符合要求,重新输入\n");
    		}
    	 }
    	printf("OK\n");
    }
    
    double mean(double*a)
    {
    	double sum=0.;
    	for(int i=0;i<C;++i)
    		sum+=*(a+i);
    	return sum/C;
    }
    
    double meanAll(double ar[][C])
    {
    	double sum=0;
    	for(int i=0;i<R;++i)
    		for(int j=0;j<C;++j)
    			sum+=*(*(ar+i)+j);
    	return sum/(double)(C*R);
    }
    
    double max(double ar[][C])
    {
    	double m=**ar;
    	for(int i=0;i<R;++i)
    		for(int j=0;j<C;++j)
    			m=m<*(*(ar+i)+j)?*(*(ar+i)+j):m;
    	return m;
    }
    
    void printArr(double ar[][C])
    {
    	for(int i=0;i<R;++i){
    		for(int j=0;j<C;++j)
    			printf("%.2lf ",*(*(ar+i)+j));
    		printf("\n");
    	}
    }
    
    请输入5double数:
    1.2 2.3 3.4 4.5 6.6
    请输入5double数:
    2.2 3.3 4.4 5.6 7.8
    请输入5double数:
    3.4 5.6 7.8 9.9 3.4
    OK
    Row 0,mean=3.60
    Row 1,mean=4.66
    Row 2,mean=6.02
    MEAN: 4.76
    Max: 9.90
    1.20 2.30 3.40 4.50 6.60
    2.20 3.30 4.40 5.60 7.80
    3.40 5.60 7.80 9.90 3.40
    
    C:\Users\xhh\Source\Repos\cPrimerPlus_study\Debug\cPrimerPlus_study.exe (进程 14520)已退出,代码为 0。
    按任意键关闭此窗口. . .
    
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值