第8章--数组

1、编写一个数组的声明,把数组的某些特定位置初始化为特定的值。这个数组的名字应该叫char_value,它包含3×6×4×5个无符号字符。下面的表中列出的这些位置应该用相应的值进行静态初始化。

位置位置位置
1,2,2,3‘A’1,1,1,1’ ’1,3,2,20xf3
2,4,3,2‘3’1,4,2,3‘\n’2,2,3,1‘\121’
2,4,3,332,5,3,41251,2,3,4‘x’
2,1,1,203202,2,2,2‘’’2,2,1,1‘0’

那些在上表未提到的位置应该被初始化为二进制值0而不是字符’\0’,注意:应该使用静态初始化,在你的解决方案中不应该存在任何可执行代码!
尽管并非解决方案的一部分,你可能很想编写一个程序,通过打印数组的值来验证它的初始化,
由于某些值并不是可打印的字符,所以请把这些字符用整型的形式打印出来(用八进制或十六进制输出会更方便一些)。
注意,用两种方法解决这个问题,一次在初始化列表中使用嵌套的花括号,另一次则不使用,这样你就能深刻理解嵌套花括号的作用。

#include <stdio.h>
#include <stdlib.h>

char char_value[3][6][4][5] = {
	{
		{
			{
			},
			{	
			},
			{
			},
			{
			}
		},
		{
			{
			},
			{	
			},
			{
			},
			{
			}
		},
		{
			{
			},
			{	
			},
			{
			},
			{
			}
		},
		{
			{
			},
			{	
			},
			{
			},
			{
			}
		},
		{
			{
			},
			{	
			},
			{
			},
			{
			}
		},
		{
			{
			},
			{	
			},
			{
			},
			{
			}
		}		
	},
	{
		{
			{
			},
			{	
			},
			{
			},
			{
			}
		},
		{
			{
			},
			{
				0, ' '
			},
			{
			},
			{
			}
		},
		{
			{
			},
			{	
			},
			{
				0, 0, 0, 'A',
			},
			{
				0, 0, 0, 0, 'x'
			}
		},
		{
			{
			},
			{	
			},
			{
				0, 0, 0xf3
			},
			{
			}
		},
		{
			{
			},
			{	
			},
			{
				0, 0, 0, '\n'
			},
			{
			}
		},
		{
			{
			},
			{	
			},
			{
			},
			{
			}
		}		
	},
	{
		{
			{
			},
			{	
			},
			{
			},
			{
			}
		},
		{
			{
			},
			{
				0, 0, 0320
			},
			{
			},
			{
			}
		},
		{
			{
			},
			{
				0, '0'
			},
			{
				0, 0, '\''
			},
			{
				0, '\121'
			}
		},
		{
			{
			},
			{	
			},
			{
			},
			{
			}
		},
		{
			{
			},
			{	
			},
			{
			},
			{
				0, 0, '3', 3
			}
		},
		{
			{
			},
			{	
			},
			{
			},
			{
				0, 0, 0, 0, 125
			}
		}		
	}
};	

void main(int argc, char *argv[])
{
	int place1 = atoi(argv[1]);
	int place2 = atoi(argv[2]);
	int place3 = atoi(argv[3]);
	int place4 = atoi(argv[4]);
	int value  = char_value[place1][place2][place3][place4];

	printf("%c 0%o %d 0x%x\n", value, value, value, value);	
}

2、美国联邦政府使用下面这些规则计算1995年每个公民的个人收入所得税:

个人收入所得税
$0~$2335015%
23350~565503502.50+28%
56550~11795012798.50+31%
117950~25650031832.50+36%
>25650081710.50+39.6%

为下面的函数原型编写函数定义:
float single_tax(float income);
参数income表示应征税的个人收入,函数的返回值就是income应该征收的税额。

#include <stdio.h>
#include <stdlib.h>
#include <float.h>

float single_tax(float income);
static float standard[] = {0, 23350, 56550, 117950, 256500, DBL_MAX};
static float ratio[]    = {0.15, 0.28, 0.31, 0.36, 0.396};
static float base[]     = {0, 3502.5, 12798.5, 31832.5, 81710.5};

void main(int argc, char *argv[])
{
	float tax = single_tax(atof(argv[1]));
	printf("%f\n", tax);
}

float single_tax(float income)
{
	int level;
	float result;

	for (level = 0; income >= standard[level]; level++)
		;
	level --;
	result = base[level] + (income - standard[level]) * ratio[level];
	
	return result;
}

3、单位矩阵就是一个正方形矩阵,它除了主对角线元素值为1以外,其余元素的值均为0,例如:
1 0 0
0 1 0
0 0 1
就是一个3×3单位矩阵,编写一个名叫identity_matrix的函数,它接受一个10×10整型矩阵为参数,并返回一个布尔值,提示该矩阵是否为单位矩阵。

#include <stdio.h>
#include <stdlib.h>

#define TRUE    1
#define FALSE   0
int identity_matrix(char mat[10][10]);
char matrix[10][10] = {
	{1, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	{0, 1, 0, 0, 0, 0, 0, 0, 0, 0},
	{0, 0, 1, 0, 0, 0, 0, 0, 0, 0},
	{0, 0, 0, 1, 0, 0, 0, 0, 0, 0},
	{0, 0, 0, 0, 1, 0, 0, 0, 0, 0},
	{0, 0, 0, 0, 0, 1, 0, 0, 0, 0},
	{0, 0, 0, 0, 0, 0, 1, 0, 0, 0},
	{0, 0, 0, 0, 0, 0, 0, 1, 0, 0},
	{0, 0, 0, 0, 0, 0, 0, 0, 1, 0},
	{0, 0, 0, 0, 0, 0, 0, 0, 0, 1}
};

void main()
{
	int result = identity_matrix(matrix);
	if (result == TRUE)
		printf("this is a identity matrix\n");
	else if (result == FALSE)
		printf("this isn't a identity matrix\n");		
}

int identity_matrix(char mat[10][10])
{
	int i, j;

	for (i = 0; i < 10; i++)
		for (j = 0; j < 10; j++) 
			if (i == j) {
				if (mat[i][j] != 1)
					return FALSE;
			} 
			else {
				if (mat[i][j] != 0)
					return FALSE;
			}
			
	return TRUE;
}

4、修改前一个问题中的identity_matrix函数,它可以对数组进行扩展,从而能够接受任意大小的矩阵参数。函数的第一个参数应该是一个整型指针,你需要第二个参数,用于指定矩阵的大小。

#include <stdio.h>
#include <stdlib.h>

#define TRUE    1
#define FALSE   0
#define SIZE    9
int identity_matrix(int *mat, int size);
int matrix[SIZE * SIZE] = {
	1, 0, 0, 0, 0, 0, 0, 0, 0, 
	0, 1, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 1, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 1, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 1, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 1, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 1, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 1, 0,
	0, 0, 0, 0, 0, 0, 0, 0, 1
};

void main()
{
	int result = identity_matrix(matrix, SIZE);
	if (result == TRUE)
		printf("this is a identity matrix\n");
	else if (result == FALSE)
		printf("this isn't a identity matrix\n");		
}

int identity_matrix(int *mat, int size)
{
	int i, j;

	for (i = 0; i < size; i++)
		for (j = 0; j < size; j++) 
				if (i == j) {
					if (*mat++ != 1)
						return FALSE;
				} 
				else {
					if (*mat++ != 0)
						return FALSE;
				}
			
	return TRUE;
}

5、如果A是个x行y列的矩阵,B是个y行z列的矩阵,把A和B相乘,其结果将是另一个x行z列的矩阵C。这个矩阵的每个元素是由下面的公式决定的:
C i , j = ∑ k = 1 y A i , k ∗ B k , j C_{i,j}=\sum_{k=1}^yA_{i,k}*B_{k,j} Ci,j=k=1yAi,kBk,j
编写一个函数,用于执行两个矩阵的乘法。函数的原型如下:
void matrix_multiply(int *m1, int *m2, int *r, int x, int y, int z);
m1是一个x行y列的矩阵,m2是一个y行z列的矩阵,这两个矩阵应该相乘,结果存储于r中,它是一个x行z列的矩阵。记住,你应该对公式做些修改,以适应C语言下标从0而不是从1开始这个事实!

#include <stdio.h>
#define X   3
#define Y   2
#define Z   4

int matrix1[X*Y] = {
	2, -6, 
	3,  5, 
	1, -1
};
int matrix2[Y*Z] = {
	 4, -2, -4, -5, 
	-7, -3,  6,  7
};
int result[X*Z];

void matrix_multiply(int *m1, int *m2, int *r, int x, int y, int z);

void main()
{
	int i, j;
	
	matrix_multiply(matrix1, matrix2, result, X, Y, Z);
	for (i = 0; i < X; i++) {
		for (j = 0; j < Z; j++) 
			printf("%d ", result[i*Z + j]);
		printf("\n");
	}
}

void matrix_multiply(int *m1, int *m2, int *r, int x, int y, int z)
{
	int *m1p;
	int *m2p;
	int row;
	int column;
	int k;
	
	for (row = 0; row < x; row++)
		for (column = 0; column < z; column++) {
			m1p = m1 + row * y;
			m2p = m2 + column;
			for (k = 0; k < y; k++){
				*r += *m1p * *m2p;
				m1p += 1;
				m2p += z;
			}
			r++;
		}
}

6、如你所知,C编译器为数组分配下标时总是从0开始,而且当程序使用下标访问数组元素时,它并不检查下标的有效性,在这个项目中,你将要编写一个函数,允许用户访问“伪数组”,它的下标范围可以任意指定,并伴以完整的错误检查。下面是你将要编写的这个函数的原型:
int array_offset(int arrayinfo[],…);
这个函数接受一些用于描述伪数组的维数信息以及一组下标值,使用这个函数,用户既可以以向量的形式分配内存空间,也可以使用mallco分配空间,但按照多维数组的形式访问这些空间,这个数组之所以被称为“伪数组”是因为编译器以为它是个向量,尽管这个函数允许它按照多维数组的形式进行访问。
这个函数的参数如下:

参数含义
arrayinfo一个可变长度的整型数组,包含一些关于伪数组的信息。arrayinfo[0]指定伪数组具有的维数,它的值必须在1和10之间。arrayinfo[1]和arrayinfo[2]给出第一维的下限和上限。arrayinfo[3]和arrayinfo[4]给出第2维的下限和上限,依次类推。
参数列表的可变部分可能包含多达10个的整数,用于标识伪数组中某个特定位置的下标值。你必须使用va_参数访问它们,当函数被调用时,arrayinfo[0]参数将会被传递。

公式根据下面给出的下标值计算一个数组的位置。变量s1,s2等代表下标参数s1,s2等。变量lo1和hi1代表下标s1的下限和上限,它们来源于arrayinfo参数,其余各维以此类推。变量loc表示伪数组的目标位置,它用一个距离伪数组起始位置的整型偏移量表示。
对于一维数组:    loc = s1 - lo1
对于二维伪数组:    loc = (s1 - lo1) × (hi2 - lo2 + 1) + s2 - lo2
对于三维伪数组:    loc = [(s1 - lo1) × (hi2 - lo2 + 1) + s2 - lo2] × (hi3 - lo3 + 1) + s3 - lo3
对于四维伪数组:    loc = [[(s1 - lo1) × (hi2 - lo2 + 1) + s2 - lo2] × (hi3 - lo3 + 1) + s3 - lo3] × (hi4 - lo4 + 1) + s4 - lo4
一直到第十维为止,都可以类似的使用这种方法推导出loc的值。你可以假定arrayinfo是个有效的指针,传递给array_offset的下标参数也是正确的。对于其他情况你必须进行错误检查,可能出现的一些错误有:维的数目不处于1到10之间,下标小于low值,low值大于其对应的high值等,如果检测到这些或者其他错误,函数应该返回-1.
提示:把下标参数都复制到一个局部数组中,你接着便可以把计算过程以循环的形式编码,对每一维都使用一次循环。

#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>

int array_offset(int array_info[], ...)
{
	va_list var_arg;
	int s, lo, hi;
	int loc = 0;

	if ((array_info[0] < 1) || (array_info[0] > 10))
		return -1;
	
	va_start(var_arg, array_info);
	for (int i = 1; i <= array_info[0]; i++) {
		s = va_arg(var_arg, int);
		lo = array_info[i*2 - 1];
		hi = array_info[i*2];

		if ((lo > hi) || (s < lo) || (s > hi))
			return -1;
		
		if (i == 1)
			loc += s - lo;
		else
			loc = loc * (hi - lo + 1) + s - lo;
	}
	va_end(var_arg);
	
	return loc;
}

int main(int argc, void **argv)
{
	int offset;
	int array_info[] = {3, 4, 6, 1, 5, -3, 3};

	if (argc != 4) {
		printf("Error! Please input three number.\n");
		return 0;
	}

	offset = array_offset(array_info, atoi(argv[1]), atoi(argv[2]), atoi(argv[3]));
	printf("offset = %d\n", offset);

	return 0;
}

7、修改问题6中的array_offset函数,使它访问以列主序存储的伪数组,也就是最左边的下标率先变化。这个新函数,array_offset2,在其它方面应该与原先那个函数一样,计算这些数组下标的公式如下所示。

#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>

int array_offset2(int array_info[], ...)
{
	int i;
	int lo, hi;
	int loc = 0;
	int arg[10];
	va_list var_arg;

	if ((array_info[0] < 1) || (array_info[0] > 10))
		return -1;
	
	va_start(var_arg, array_info);
	for (i = 0; i < array_info[0]; i++)
		arg[i] = va_arg(var_arg, int);
	va_end(var_arg);
	
	for (i = array_info[0]; i > 0; i--) {
		lo = array_info[i*2 - 1];
		hi = array_info[i*2];

		if ((lo > hi) || (arg[i-1] < lo) || (arg[i-1] > hi))
			return -1;
		
		if (i == array_info[0])
			loc += arg[i-1] - lo;
		else
			loc = loc * (hi - lo + 1) + arg[i-1] - lo;
	}
	
	return loc;
}

int main(int argc, void **argv)
{
	int offset;
	int array_info[] = {3, 4, 6, 1, 5, -3, 3};

	if (argc != 4) {
		printf("Error! Please input three number.\n");
		return 0;
	}

	offset = array_offset2(array_info, atoi(argv[1]), atoi(argv[2]), atoi(argv[3]));
	printf("offset = %d\n", offset);

	return 0;
}

8、皇后是国际象棋中威力最大的棋子,在下面所示的棋盘上,皇后可以攻击位于箭头所覆盖位置的所有棋子。
在这里插入图片描述

我们能不能把8个皇后放在棋盘上,它们中任何一个都无法攻击其余的皇后?这个问题被称为八皇后问题,你的任务是编写一个程序,找到八皇后问题的所有答案,看看一共有多少种答案。
提示:如果你采用一种叫做回溯法的技巧,就很容易编写出这个程序,编写一个函数,把皇后放在某行的第一列,然后检查它是否与棋盘上的其他皇后互相攻击,如果存在互相攻击,函数把皇后移到该行的第二列再进行检查,如果每列都存在互相攻击的情况,函数就应该返回,但是如果皇后可以放在这个位置,函数接着应该递归的调用自身,把一个皇后放在下一行,当递归调用返回时,函数再把原先那个皇后移到下一列。当一个皇后成功的放置于最后一行时,函数应该打印出棋盘,显示8个皇后的位置。

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

void eightQueen(int row);
int isAttack(const int board[8][8], int row, int column);
void printBoard(const int board[8][8]);

int board[8][8];

void main(void)
{
	eightQueen(0);
}

void eightQueen(int row)
{
	int column;

	for (column = 0; column < 8; column++) {
		if (isAttack(board, row, column))
			continue;

		board[row][column] = 1;
		if (row >= 7)
			printBoard(board);
		else
			eightQueen(row + 1);
		board[row][column] = 0;
	}
}

int isAttack(const int board[8][8], int row, int column)
{
	int i;

	for (i = 0; i < 8; i++) {  
		// 检查行和列
		if ((board[row][i] == 1) || (board[i][column] == 1))
			return 1;
		// 检查对角线上半部分
		if (((row - i) >= 0) && ((column - i) >= 0) && (board[row - i][column - i] == 1))
			return 1;
		if (((row - i) >= 0) && ((column + i) <= 7) && (board[row - i][column + i] == 1))
			return 1;
	}
	
	return 0;
}

void printBoard(const int board[8][8])
{
	int i,j;
	static int num = 1;

	printf("%d. \n", num++);
	for (i = 0; i < 8; i++) {
		for (j = 0; j < 8; j++)
			printf("%d ", board[i][j]);
		printf("\n");
	}
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值