C语言程序设计现代方法_P125_编程题

1.修改8.1节的程序repdigit.c,使其可以显示出哪些数字有重复(如果有的话)

#include<stdbool.h>
#include<stdio.h>
int main(){
    int digit_seen[10];             //这个是数组的名字
    int digit,i;
    long n;                         //一些要用到的数的定义

    for(i=0;i<=9;i++)
        digit_seen[i]=0;            //初始化数组,定义数组的状态
    printf("Enter a number:");
    scanf("%ld",&n);
    printf("Repeated digit(s):");

    while(n>0){
        digit=n%10;
        if(digit_seen[digit]==0     //此时已经找到了一次数组
            digit_seen[digit]=1;    //此时改变状态,吧把状态改变为1
        else if(digit_seen[digit]==1){  //此时状态是1,表示找到了重复的
            printf("%4d",digit);        //输出
            digit_seen[digit]=2;        //改变状态,改变为不读取,状态为2
        }
        n=n/10;
    }
    return 0;
}

结果图如下

个人感悟

这题我觉得写的不是很好,一开始的时候思路都是不对的,一开始的时候没有想到有多个重复的怎么办,题目原题是就2种状态,用的是布尔类型的数组,但是我想了想,布尔类型的数组用起来表示不了3个以上重复数,所以最后用了个整形数组(当然了,本人愚笨,如果你有更好的解法,希望你可以分享出来)

2.修改8.1节的程序repdigit.c。使其打印一份列表,显示出每数字在数中出现的次数。

#include<stdbool.h>
#include<stdio.h>
int main(){
    bool digit_seen[10]={false};       //默认 初始化,都为false
    int number_number[10],digit,i;
    long n;                            //一些要用的定义
    for(i=0;i<10;i++)
        number_number[i]=0;            //用循环初始化
    printf("Enter a number:");
    scanf("%ld",&n);
    printf("Repeated digit(s):\n");

    while(n>0){
        digit=n%10;
        number_number[digit]++;     //找到相同的并相加
        n=n/10;
    }
    for(i=0;i<10;i++)
        printf("%-4d",i);

    printf("\n");

    for(i=0;i<10;i++)
        printf("%-4d",number_number[i]);    //输出
    return 0;
}

结果如下

 3.修改8.1节的redigit.c,使得用户可以录入多个数进行重复的判断,当用户录入的数小于或等于0时,程序终止。

#include<stdbool.h>
#include<stdio.h>
int main(){
    bool digit_seen[10]={false};
    int digit,i;
    long n;
    printf("Enter a number:");
    while(scanf("%ld",&n)){           //循环的输入
        if(n<=0)        
            break;                    //循环终止的条件
        printf("Repeated digit(s):");
       while(n>0){
        digit=n%10;
        if(digit_seen[digit]==0)     //此时已经找到了一次数组
            digit_seen[digit]=1;    //此时改变状态,吧把状态改变为1
        else if(digit_seen[digit]==1){  //此时状态是1,表示找到了重复的
            printf("%4d",digit);        //输出
            digit_seen[digit]=2;        //改变状态,改变为不读取,状态为2
        }
        n=n/10;
    }
        printf("\n\n");
        printf("Enter a number:");
        for(i=0;i<10;i++)
            digit_seen[i]=0;
    }
    return 0;
}

结果如下

 4.修改8.1节的程序,reverse.c,利用表达式(int)(sizeof(a)/sizeof(a[0]))(或者具有相同值的宏)来计算数组的长度

#include<stdio.h>
#define N 10
int main(){
    int a[N],i;

    printf("Enter %d numbers: ",N);
    for(i=0;i<(int)(sizeof(a)/sizeof(a[0]));i++)            //计算数组的长度(int)(sizeof(a)/sizeof(a[0]))
        scanf("%d",&a[i]);

    printf("In reverse order:");
    for(i=(int)(sizeof(a)/sizeof(a[0]))-1;i>=0;i--)
        printf(" %d",a[i]);
    printf("\n");
    return 0;
}

结果如下

5 .修改8.1节的程序,interest.c,使得修改后的程序可以每月整合一次利息,而不是每年整合一次利息,不要改变程序的输出格式,余额仍按每年一次的时间间隔提醒

代码如下

#include<stdio.h>
#define NUM_RATEES ((int)(sizeof(value)/sizeof(value[0])))
#define INTTIAL_BALANCE 100.00

int main(){
    int i,low_rate,num_years,year;
    double value[5],month;

    printf("Enter interest rate: ");
    scanf("%d",&low_rate);
    printf("Enter number of years: ");
    scanf("%d",&num_years);

    printf("\nYears");
    for(i=0;i<NUM_RATEES;i++){
        printf("%6d%%",low_rate+i);
        value[i]=INTTIAL_BALANCE;
    }
    printf("\n");

    for(month=1;month<=num_years*12;month++){
            if((int)month%12==0)                //为了保持格式
        printf("%3d  ",(int)(month/12));        //格式一致,所以除去12

        for(i=0;i<NUM_RATEES;i++){
            value[i]+=((double)(low_rate+i)/12)/100.0*value[i];     //(double)强制类型转换,如果不转换的话
                                                                    //因为low_rate和i都是int型,所以要用double型转换
            if((int)month%12==0)
            printf("%7.2f",value[i]);
        }
        if((int)month%12==0)
        printf("\n");
    }
    return 0;
}

 

我是每月算的,所以这个结果会和原题的答案有出入

6.网络新手的原型是一个叫做BIFF 的人,他有一种独特的编写消息的方法。下面是一条常见的BIFF公告:

H3Y DUD3,C 15 RILLY C00l !!!!!!

编写一个“BIFF过滤器”,它可以用来读取用户录入的消息并把消息翻译成BIFF的表达风格:

Enter message : Hey dude ,C is rilly cOOl

In BIFF-speak :H3Y DUD3 ,C is R1LLY C00L!!!!!!

程序需要把消息转换成大写字母,用数字代替特定的字母(A--4,B--8,E--3,I--1,O--0,S--5),然后添加10个左右的感叹号。(提示:把原始消息放在一个字符数组中,然后从数组头开始逐个翻译并显示字符)

代码如下

#include <stdio.h>
#include <ctype.h>	//为·

#define N 40

int  main()
{
	int i, n;			
	char biff[N];

	printf("Enter message : ");
	n = 0;

	while ((biff[n++] = getchar()) != '\n' && n < N);	//一个常用的表达式
	{
		printf("In bill-speak : ");

		for (i = 0; i < n - 1; i++)
		{
			biff[i] = toupper(biff[i]);					//大小写转换函数touooer需要ctype.h头文件的支持
			if(biff[i]=='A')
				biff[i] = '4';
			if(biff[i]=='B')							//一系列判断语句的说明
				biff[i] = '8';
			if (biff[i] == 'E')
				biff[i] = '3';
			if (biff[i] == 'I')
				biff[i] = '1';
			if (biff[i] == 'O')
				biff[i] = '0';
			if (biff[i] == 'S')
				biff[i] = '5';
		printf("%c", biff[i]);						//转换后立刻输出
		}
		printf("!!!!!!!!!!\n");						//最后在加上一个!!!!!!!!!!
	}
	return 0;
}

其中需要注意的是toupper函数里面的参数是biff[i],是一个字符。

7.编写一个程序读取一个5*5的整数数组,然后显示每行的和于每列的和

Enter row 1:839010
Enter row 2:351711
Enter row 3:286231
Enter row 4:15732

9

Enter row 5:614260
row total:3027403628
column total:3437373221

 代码如下图

#include<stdio.h>
int main(void){
	int a[5][5], row[5] = { 0 }, column[5] = {0}, row_cycle =0,line_cycle =0,line=0;
	printf("Enter row 1:");
	for ( ; row_cycle <5; row_cycle++){
		if (row_cycle != 0)
			printf("\nEnter row %d:",row_cycle+1);
		for (line_cycle=0; line_cycle < 5; line_cycle++) {
			scanf_s("%d",&a[row_cycle][line_cycle]);
		}
	}
	for (row_cycle = 0; row_cycle < 5; row_cycle++) {
		for (line_cycle=0; line_cycle < 5; line_cycle++) {
			column[row_cycle] += a[line_cycle][row_cycle];
			row[row_cycle] += a[row_cycle][line_cycle];
		}
	}
	printf("\nRow total: ");
	for (row_cycle = 0; row_cycle < 5; row_cycle++)
		printf("%d\t", row[row_cycle]);
	printf("\nCoulumn total: ");
	for (row_cycle = 0; row_cycle < 5; row_cycle++)
		printf("%d\t", column[row_cycle]);
	
	
	return 0;
}

8.修改编程题7.使其提示每给学生5门测试的成绩,一共有5给学生,然后计算每个学生的总分和平均分,以见每门测试的平均分,高分和低分。

代码如下

#include<stdio.h>
int main() {
	int Student_garde[5][5],Garde_sum=0, number, garde_number,max,min;		//定于要用的数,我的英语不是很好,定义的也不是很好
	float Class_averge[5] = { 0.0 },Student_averge;							
	printf("Enter 1 Student garde:");
	for (number=0; number< 5; number++) {
		if (number != 0)
			printf("\nEnter %d Student garde:", number + 1);
		for ( garde_number= 0; garde_number < 5; garde_number++) {
			scanf_s("%d",&Student_garde[number][garde_number]);
		}
	}																		//和上题一样的输入
	for (number = 0; number < 5; number++) {
		max = Student_garde[number][0];
		min = max;
		for (garde_number = 0; garde_number < 5; garde_number++) {
			Class_averge[number] += Student_garde[garde_number][number];	//算课程的评价分
			Garde_sum += Student_garde[number][garde_number];				//算个人的总分
			if (Student_garde[garde_number][number] > max)					
				max = Student_garde[garde_number][number];
			if (Student_garde[garde_number][number] < min)
				min = Student_garde[garde_number][number];					//找课程里的最大和最小
		}
		Class_averge[number]/= 5;
		Student_averge = Garde_sum / 5;
		printf("'\nThe %d number Student's garde average is %.2f,and sum is %d ",number+1,Student_averge, Garde_sum);
		printf("\nThe %d class avergae is %.4f,max is %d,min is %d ", number+1,Class_averge[number],max,min);
		Garde_sum = 0;														//总分重置语句,这还是比较重要的
	}
	return 0;

9.编写程序,生成一种贯穿10*10的字符数组(初始时全为字符  '.' )的“随机步法”。程序必需随机地从一个元素“走到”另一个元素,每次都向上,下,左,右移动一个元素位置,以访问过的元素按访问顺序用字母A到Z标记,下面是一个输出示例

A.........
BCD      .
 FE.......
HG .......
I.........
J.......Z.
K..RSTUVY.
LMPQ   WX.
.NO.......
..........

 提示:利用srand函数和rand函数(见程序deal.c)产生随机数,然后查看次数除以4的余数,余数一共有4种可能的值(0.1.2和3),指示下一次移动的4种可能方向。在执行移动前,需要检查2项内容:一是不能走到数组外面,二是不能走到已有字母表记的地方。只要有一个条件不满足就得换给方向移动。如果4给方向都堵住了,程序就必需终止了,下面是一个示例

ABGHI.....
.CF.JK....
.DE.ML....
....NO....
..WXYPQ...
..VUTSR...
..........
..........
..........
..........

 最后的一个z没有地方放置了,z,程序就此终止。

#include<stdio.h>
#include<time.h>
#include<stdlib.h>
#include<stdbool.h>
#define Row 10						//定义个宏常量
#define Coulmn 10
int main() {
	bool Stop_map = { true };		//用来判断是否需要停止	
	char map_array[Row][Coulmn];	//这个是地图数组,我觉得比较像地图
	int map_direction, row = 0, coulmn = 0, Direction = 0, A = 65;		//定义需要用的变量
	srand((unsigned)time(NULL));										//随机数的种子,具体定义请翻到P488页
	for (int i = 0; i < Row; i++)
		for (int j = 0; j < Coulmn; j++) {
			map_array[i][j] = '.';
		}																//给地图数组赋值
	map_array[0][0] = 'A';
	while (Stop_map) {
		map_direction = rand() % 12;
		if (map_direction == 0) {
			if (row - 1 < 0 || map_array[row - 1][coulmn] != '.') {		//判断是不是出界的语句
				Direction++;											//出界的累加语句,如果出界就加一下,然后累加到4次
				map_direction = 1;										//改变方向的语句
			}															//如果累加到4次那么就代表4个方向都不行,程序就在次终止
			else {
				A += 1;													//程序可行时的移动语句,这里用了c语言char和int可以自动
				map_array[row - 1][coulmn] = A;							//转换的知识
				row -= 1;
			}
		}																//这个是向上移动的判断加移动语句
		if (map_direction == 1) {										//0是向上,1是向右,2是向下,3是向左

			if (coulmn + 1 >= 9 || map_array[row][coulmn + 1] != '.') {
				Direction++;
				map_direction = 2;
			}
			else {
				A += 1;
				map_array[row][coulmn + 1] = A;
				coulmn += 1;
			}
		}
		if (map_direction == 2) {

			if (row + 1 >= 9 || map_array[row + 1][coulmn] != '.') {
				Direction++;
				map_direction = 3;
			}
			else {
				A += 1;
				map_array[row + 1][coulmn] = A;
				row += 1;
			}
		}
		if (map_direction == 3) {

			if (coulmn - 1 < 0 || map_array[row][coulmn - 1] != '.') {
				Direction++;

			}
			else {
				A += 1;
				map_array[row][coulmn - 1] = A;
				coulmn -= 1;
			}
		}
		if (Direction == 4 || A == 90)
			Stop_map = false;
		else
			Direction = 0;

	}
	for (int i = 0; i < Row; i++) {
		for (int j = 0; j < Coulmn; j++) {
			printf("%c\t", map_array[i][j]);
		}																	//简单的输出语句
		printf("\n");
	}


}

 10.修改第5章的编程题8,用一个数组存储时间,另一个数组存储抵达时间(时间用整数表示,表示从午夜开始的分钟数)程序用一个循环搜索起飞的时间数组,以找到与用户输入时间最接近的起飞时间。

代码如下

#include<stdio.h>
#define Number 8
int main() {
	int Take_off_time[Number] = {8*60,9*60+43,11*60+19,12*60+47,14*60,15*60+45,19*60,21*60+45};			//转换,我懒就这样算了
	int Array_time[Number] = {10*60+16,11*60+52,13*60+31,15*60,16*60+8,17*60+55,21*60+20,23*60+58};		
	int hour,minute,time,take_number,difference_1, difference_2;
	printf("Enter a 24_hour time:");
	scanf_s("%d:%d", &hour,&minute);
	time = hour * 60 + minute;
	for (int i = 1; i < Number; i++) {
		if (time < Take_off_time[0]) {
			take_number = 0;
			break;
		}																								
		if (time > Take_off_time[7]) {
			take_number = 7;
			break;
		}																								//最大和最小的两个极端
		if (time >= Take_off_time[i - 1] && time <= Take_off_time[i]) {
			difference_1 = time - Take_off_time[i - 1];
			difference_2 = Take_off_time[i] - time;
			if (difference_1 >= difference_2) {
				take_number = i - 1;
				break;
			}																							//在中间值的时候的判断
			else {
				take_number = i;
				break;
			}
		}
		
	}
	printf("Closest despart time is %d ,arry despart is %d", Take_off_time[take_number], Array_time[take_number]);
}

结果图

 11.修改第7章的编程题4,给输出加上标签

#include<stdio.h>
int main() {
	char letter_phone[15],phone_array[15];
	int number = 0;
	printf("Enter phone number:");
	while ((letter_phone[number]=getchar())!='\n') {	//从键盘上一个一个的输入字符
		number++;
	}
	letter_phone[number] = '\0';						//结尾加一个\0,表示结束
	for (int i = 0; i < letter_phone[i]!='\0'; i++) {
		if (letter_phone[i] == 'A' || letter_phone[i] == 'B' || letter_phone[i] == 'C')
			phone_array[i] = '2';
		else	if (letter_phone[i] == 'D' || letter_phone[i] == 'E' || letter_phone[i] == 'F')
			phone_array[i] = '3';
		else	if (letter_phone[i] == 'G' || letter_phone[i] == 'H' || letter_phone[i] == 'I')
			phone_array[i] = '4';
		else	if (letter_phone[i] == 'J' || letter_phone[i] == 'K' || letter_phone[i] == 'L')
			phone_array[i] = '5';
		else	if (letter_phone[i] == 'M' || letter_phone[i] == 'N' || letter_phone[i] == 'O')
			phone_array[i] = '6';
		else	if (letter_phone[i] == 'P' || letter_phone[i] == 'Q' || letter_phone[i] == 'R' || letter_phone[i] == 'S')
			phone_array[i] = '7';
		else	if (letter_phone[i] == 'T' || letter_phone[i] == 'U' || letter_phone[i] == 'V')
			phone_array[i] = '8';
		else    if (letter_phone[i] == 'W' || letter_phone[i] == 'X' || letter_phone[i] == 'Y' || letter_phone[i] == 'Z')
			phone_array[i] = '9';
		else
			phone_array[i] = letter_phone[i];			
	}															//一系列转换语句,其中要注意数据类型
	printf("In numeric form :");
	for (int i = 0; letter_phone[i]!='\0'; i++) {
		printf("%c", phone_array[i]);		
	}

}

 结果如下

 12.修改第7章的编程题5,用数组存储字母的值,数组有26个元素,对应字母表的26个字母,例如元素0存储1(A的字面值为1),等等,每读取一个单词中 的一个字母,程序都会利用数组确定字符的拼字值,使用数组初始化式来建立该数组。

#include<stdio.h>
#include<ctype.h>
int main() {
	char word[15];
	int number = 0, number_value = 0;
	printf("Enter a word:");
	while ((word[number] = getchar()) != '\n') {	//从键盘上一个一个的输入字符
		number++;
	}
	word[number] = '\0';
	number = 0;
	while (word[number]!='\0'){
		word[number]=toupper( word[number] );
		number++;
	}
	for (int i = 0; i < word[i] != '\0'; i++) {
		if (word[i] == 'A' || word[i] == 'E' || word[i] == 'I'||word[i]=='L'||word[i]=='N')
			number_value += 1;
		else	if (word[i] == 'O' || word[i] == 'R' || word[i] == 'S'||word[i]=='T'||word[i]=='U')
			number_value += 1;
		else	if (word[i] == 'D' || word[i] == 'G')
			number_value += 2;
		else	if (word[i] == 'B' || word[i] == 'C' || word[i] == 'M'||word[i]=='P')
			number_value += 3;
		else	if (word[i] == 'F' || word[i] == 'H' || word[i] == 'V'||word[i]=='W'||word[i]=='Y')
			number_value += 4;
		else	if (word[i] == 'K')
			number_value += 5;
		else	if (word[i] == 'J' || word[i] == 'X' )
			number_value += 8;
		else    if (word[i] == 'Q' || word[i] == 'Z' )
			number_value += 10;			
	}
	printf("Scrabble:%d", number_value);
}

结果如下

13.修改第7章的编程题11,给输出加上标签:

我写的方法很烂,不推荐使用我的方法

#define _CRT_SECURE_NO_DEPRECATE									//VS前面要加的头文件,防止scanf报错
#include<stdio.h>	
int main() {
	int i=0,n=0,f=0,s=0;												
	char name[20],Name[100],a;
	printf("Enter a first and last name:");
	while ((a=getchar())!= '\n'){
		Name[i] = a;
		i++;
	}	//输入那句话,把那句话看做一个字符串
	Name[i] = '\0';													//结尾的标志符
	i = 0;
	for (int j = 0; Name[j] != '\0'; j++) {
		if ((Name[j] != ' ')&&(Name[j + 1] != ' ')&&(f==0)) {
			a = Name[j];
			f = 1;
		}				//找出话中的姓															
		if (Name[j] != ' '&&Name[j + 1] == ' '&&f==1) { //姓的结尾
			f = 2;
			continue;
		}
		if ((Name[j] != ' ')&&(Name[j + 1] != ' ')&&(f ==2)) {
			name[n]=Name[j];
			n++;
		}															//用来找名字
		if (((Name[j] != ' ')&&(f==2)&&(Name[j+1]==' ')&&(name[0]!=' '))||((Name[j] != ' ') && (f == 2)&&(Name[j+1]=='\0'))){
			name[n] = '\0';
			break;
		}
	}																//名字的结尾,名字的结尾比较麻烦,
	printf("You enered the name:  ");												//因为最后可能会由空格,也可能没有
	while (i<n) {
		printf("%c", name[i]);
		i++;
	}																//输出名字
		printf(",%c",a);									//输出姓
	
	return 0;
}

 这里是CSDN的大神写出来的代码(侵删)

victor_sha的回答

的代码

#include<stdio.h>
//#include<ctype.h>
int main(void)
{
	char d, c;
	int i = 0;
	printf("Enter a first and last name :");
	scanf(" %c", &d);				//这里领用了scanf的特性.不管你输入多少个空格,程序都只读第一个数,就是姓氏的首字母
	while (c = getchar() != ' ')
		;							//这里是读取姓氏,就相当于过滤一遍	
	while ((c = getchar()) != '\n')
	{
		if (c == ' ')
			;
		else
			putchar(c);
	}								//输出名字
	printf(",%c",d);				//输出我们保存的姓

	return 0;
}

给果如下

 

15

已知的最古老的一种加密算法技术是凯撒加密。该方法把一条消息中的每个字母用字母表中固定距离之后的那个字母来替代。(如果越过Z,会绕回到字母表的起始位置。例如,如果每个字母都用字母表中两个位置之后的字母代替,那么Y就被替为A, Z就被替为B.)编写程序用凯撒加密算法对消息进行加密。用户输入待加密的消息和移位计数(字母移动的位置数目):
输入待加密的消息:Go ahead, make my day.
输入移位数:3
加密后的消息: Jr dkhdg, pdnh pb gdb.
注意:当用户输入26与移位计数的差值时,程序可以对消息进行解密:
输入待解密的消息: Jr dkhdg, pdnh pb gdb.
输入移位数:23
加密后的消息: Go ahead, make my day.
可以假定消息的长度不超过80个字符。不是字母的那些字符不要改动。此外,加密时不要改变字母的大小写。
提示:为解决前面的绕回问题,要以用表达式((ch-'A')+n)%26+'A'计算大写字母的密码,其中ch存储字母,n存储移位计数。(小写字母也需要一个类似的表达式。)

我的代码如下

#include<stdio.h>
//#include<ctype.h>
int main(void)
{
	char d, c;
	int i = 0;
	printf("Enter a first and last name :");
	scanf(" %c", &d);				//这里领用了scanf的特性.不管你输入多少个空格,程序都只读第一个数,就是姓氏的首字母
	while (c = getchar() != ' ')
		;							//这里是读取姓氏,就相当于过滤一遍	
	while ((c = getchar()) != '\n')
	{
		if (c == ' ')
			;
		else
			putchar(c);
	}								//输出名字
	printf(",%c", d);				//输出我们保存的姓

	return 0;
}

 结果如下

解密

 16

测试两个单词是否为变位词(相同字母的重新排序):

Enter first word: smartest

Enter second word:mattress

The words are anagrams.

 

 

Enter first word: dumbest

Enter second word:stumble

The words are angrams.

用一循环将逐个字符读取在第一个单词内,用一个26元的整数数组纪录每个字母的出现次数。例如去读单词abc,数组的元素值为(11100000000000000000000000),表示abc就只有1个a,一个b,一个c。用另一个循环读取第二个单词,每次读取都把对应的数组元素减一,两个循环都应该忽略哪里不是字母的其他元素,并且不区分大小写,第二个循环结束后,在用一个循环来检查数组元素是不是全为0,如果是,那么这两个词就是变位词

#include<stdio.h>
#include<ctype.h>
int main(void) {
	int arr[26] = {0};									//数组初始化
	char a;
	printf("Enter first word:");
	while ((a = getchar()) != '\n') {
		if (isalpha(a)) {								//判断输入的字符是不是字母
			a = tolower(a);								//把大写字母变为小写字母
				arr[a - 97] += 1;
		}

	}													//数组累加	
	printf("Enter second word:");
	while ((a = getchar()) != '\n') {
		if (isalpha(a)) {
			a = tolower(a);
				arr[a - 97] -= 1;
		}												//数组累减
		
	}
	for (int i = 0; i < 26; i++) {						//判断循环并输出
		if (arr[i] != 0) {
			printf("The words are not anagrams.");
			break;
		}
		if (arr[i] == 0&&i==25)
			printf("The words are anagrams.");
	}

}

结果如下

 

 17

编程程序打印n*n的幻方(1,2,......n*n)d的方针排列,且每行,每列和每条对角线上的值都相等。由用户指定n的值

代码如下

#include<stdio.h>
#include<ctype.h>
int ox=0, oy=0;
int a[1000][1000] = { 0 };
int main(void) {
	
	int k, i = 1, line = 0, list = 0, And,t,part_number;
	int line_sum[99] = { 0 }, list_sum[99] = { 0 }, main_diagonal = 0, diagonal = 0;
	void Four_magic(int);
	void DoubleFour_magic(int, int);
	void Single_Double_Number(int , int,int);

	printf("This program creates a magic square of specified size\n");
	printf("This size must be an odd number between 1 and 99");
	printf("\nEnter size of magic square:");
	scanf("%d", &k);
	And= k * k + 1;

	if (k % 2 == 1) {
		int Max = k * k + 1;
		Single_Double_Number(k, i,Max);
	}																		//奇数幻方的赋值过程
	else {																	//偶数幻方的赋值过程
		if (k % 4 == 0) {													//4*n阶幻方的赋值过程

			i = 1;
			for (int j = 0; j < k; j++) {
				for (int z = 0; z < k; z++) {
					a[j][z] = i;
					i++;
				}
			}

			i = 1;
			for (int j = 0; j < k; j++) {
				for (int z = 0; z < k; z++)
					printf("%-6d ", a[j][z]); {
					i++;
				}
				printf("\n");
			}													//这个是输出的测试语句


			if (k == 4) {
				ox = 0;
				oy = 0;
				Four_magic(And);
			}
			else if (k % 4 == 0&&k!=4) {
				part_number = k * k / 4 / 4;
				printf("part_number is %d\n", part_number);
				DoubleFour_magic(part_number, And);
			}
		}
		else {											//这个是4*n+2阶幻方的构造过程																			
			int Max;
			i = 1;
			Max = k * k / 4 * 1;
			
			Single_Double_Number(k / 2, i, Max);

			ox = k / 2;
			oy = k / 2;
			i = k * k / 4 + 1;
			Max = k * k / 4 * 2;
			Single_Double_Number(k / 2, i, Max);
			
			ox = 0;
			oy = k / 2;
			i = k * k / 4*2 + 1;
			Max = k * k / 4 * 3;
			Single_Double_Number(k / 2, i, Max);
			
			ox = k / 2;
			oy = 0;
			i = k * k / 4*3 + 1;
			Max = k * k ;
			Single_Double_Number(k / 2, i, Max);
			
			
			int k1;
			 k1= k / 2;
			for (int i = k1/2; i < k1 /2  + (2 * k1 - 2) / 4; i++) {
				int t;
				t = a[k1/2][i];
				a[k1/2][i] = a[(3 * k1 - 1)/2][i];
				a[(3 * k1 - 1)/2][i] = t;
			}

			
			for (int j=0;j<k1;j++) {
				for (int i = 0; i <= (2 * k1 - 2) / 4-1; i++) {
					if (j != k1/2) {
						t = a[j][i];
						a[j][i] = a[k1 + j][i];
						a[k1 + j][i] = t;
					}
				}
			}																		//AC象限交换完毕

			
			for (int j = 0; j < k1; j++) {
				int z = (k - 2) / 4 - 1-1;
				for (int i = (k/2+k-1)/2; i >=(k / 2 + k - 1) / 2-z; i--) {
					
						t = a[j][i];
						a[j][i] = a[k1 + j][i];
						a[k1 + j][i] = t;
					
					
					
				}
			}
			






			
		}


	}


		for (int i = 0; i < k; i++) {
			for (int j = 0; j < k; j++) {
				line_sum[i] += a[i][j];
				list_sum[i] += a[j][i];
			}
			main_diagonal += a[i][i];
			diagonal += a[i][k - 1 - i];
		}




		for (int i = 0; i < k; i++) {
			if (line_sum[i] == list_sum[i] && list_sum[i] == main_diagonal && main_diagonal == diagonal)
				;
			else {
				printf("程序错误\n");
				printf("i is %d\n", i);
				if (main_diagonal != diagonal)
					printf("主副不同\n");
				if (line_sum[i] != list_sum[i])
					printf("行和列不同\n 行是%d  列是%d\n", line_sum[i], list_sum[i]);
				break;
			}
			if (i == k - 1)
				printf("程序正确\n");

		}																			//检验程序是否正确
																					//是检验代码

		for (int i = 0; i < k; i++) {
			for (int j = 0; j < k; j++)
				printf("%-6d", a[i][j]);
			printf("\n");
		}																			//输出程序
	}


void Single_Double_Number(int k,int i,int Max) {									//奇数幻方的构造过程
	int list_limit_left;
	int line_limit_below;
	int line, list;
	line = ox;
	list = oy + k / 2;
	int line_limit = ox;
	int list_limit = oy+k-1;
	list_limit_left = oy;
	line_limit_below = line + k-1;
	a[line][list]= i;															//给中间值赋值,就是赋值第一行中间的1
	while (i != Max) {
		if (line - 1 < line_limit && list + 1 <= list_limit) {								//这个情况是行超出的
			if (a[line_limit_below][list+1] == 0) {												//判断我们要赋值的地方有没有被占
					line = line_limit_below;		//这里有改
					list += 1;
				
			}
			else
				line += 1;
			a[line][list] = ++i;
		}
		else	 if (list + 1 > list_limit && line - 1 >= line_limit) {						//列超出的情况
			if (a[line - 1][list_limit_left] == 0) {												//判断我们要赋值的地方有没有被占

				list = list_limit_left;
				line -= 1;
			}
			else
				line += 1;
			a[line][list] = ++i;
		}
		else if (line - 1 < line_limit && list + 1 > list_limit ) {							//行和列均超出的情况
																	//判断我们要赋值的地方有没有被占
				
				line += 1;
			a[line][list] = ++i;
		}
		else if (list + 1 <= list_limit  && line - 1 >= line_limit) {							//行和列均没有超出的情况
			if (a[line - 1][list + 1] == 0) {									//判断我们要赋值的地方有没有被占
				line -= 1;
				list += 1;
			}
			else
				line += 1;
			a[line][list] = ++i;
		}
		else
			;
	}
 }



void Four_magic(int n) {										//4阶幻方的构造
	for (int i = 0; i < 4; i++) {
		a[ox + i][oy + i] = n - a[ox + i][ox + i];
		a[ox + i][4-i-1+ox] = n - a[ox + i][4-i-1+ox];
	}
}
void DoubleFour_magic(int z,int n) {						//4*n阶幻方的构造
	for (int i=0; i <z*z; i+=4) {
		for (int j=0;j < z*z; j+=4) {
			a[i][j] = n - a[i][j];
			a[i+1][j+1] = n - a[i+1][j+1];
			a[i+2][j+2] = n - a[i+2][j+2];
			a[i+3][j+3] = n - a[i+3][j+3];


			a[i][j+3] = n - a[i][j+3];
			a[i+1][j + 2] = n - a[i+1][j + 2];
			a[i+2][j + 1] = n - a[i+2][j + 1];
			a[i+3][j] = n - a[i+3][j ];
		}
	}
	
}

截图如下

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值