1、编写一个数组的声明,把数组的某些特定位置初始化为特定的值。这个数组的名字应该叫char_value,它包含3×6×4×5个无符号字符。下面的表中列出的这些位置应该用相应的值进行静态初始化。
位置 | 值 | 位置 | 值 | 位置 | 值 |
---|---|---|---|---|---|
1,2,2,3 | ‘A’ | 1,1,1,1 | ’ ’ | 1,3,2,2 | 0xf3 |
2,4,3,2 | ‘3’ | 1,4,2,3 | ‘\n’ | 2,2,3,1 | ‘\121’ |
2,4,3,3 | 3 | 2,5,3,4 | 125 | 1,2,3,4 | ‘x’ |
2,1,1,2 | 0320 | 2,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~$23350 | 15% |
23350~56550 | 3502.50+28% |
56550~117950 | 12798.50+31% |
117950~256500 | 31832.50+36% |
>256500 | 81710.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=1∑yAi,k∗Bk,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");
}
}