8.1 一维数组
特性 | 说明 | 代码 |
---|---|---|
数组定长 | 数组长度必须是常量表达式 但是索引时可以是变量表达式 (前提是整数) | int a[10]; |
索引 | 通过下标访问元素的操作 | a[0] = 1; |
不检查越界 | C语言不检查下标范围, 当下标超出范围时, 程序可能执行不可预知的行为. | |
数组初始化 | 1. 如果初始化式比数组短, 则剩余元素为0. 2. 可以利用初始化式确定数组长度 int a[] = {1, 2, 3}; | a[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; |
指定初始化 #C99 | 指定下标进行初始化 | int a[15] = {[3] = 3, [2] = 2};; |
数组sizeof | 计算的是整个数组的字节数 |
(程序) 数组逆向遍历
reverse.c
#include <stdio.h>
#define N 10
int main(void) {
int a[N], i;
printf("Enter %d number: ", N);
for (i = 0; i < N; i++)
scanf("%d", &a[i]);
printf("In reverse order: ");
for (i = N - 1; i >= 0; i--)
printf(" %d", a[i]);
printf("\n");
return 0;
}
输出
Enter 10 number: 1 2 3 4 5 6 7 8 9 10
In reverse order: 10 9 8 7 6 5 4 3 2 1
(程序) 检查重复数字
repdigit.c
#include <stdio.h>
#include <stdbool.h>
int main(void) {
bool digit_seen[10] = {false};
int digit;
long n;
printf("Enter a number: ");
scanf("%ld", &n);
while (n > 0) {
digit = n % 10;
if (digit_seen[digit])
break;
digit_seen[digit] = true;
n /= 10;
}
if (n > 0)
printf("Repeated digit\n");
else
printf("No repeated digit.\n");
return 0;
}
输出
Enter a number: 22576
Repeated digit
(程序) 利息
interest.c
#include <stdio.h>
#define NUM_RATES ((int) (sizeof(value) / sizeof(value[0])))
#define INITIAL_BALANCE 100.00
int main(void) {
int i, low_rate, num_years, year;
double value[5];
printf("Enter interest rate: ");
scanf("%d", &low_rate);
printf("Enter number of years");
scanf("%d", &num_years);
printf("\nYears");
for (i = 0; i < NUM_RATES; i++) {
printf("%6d%%", low_rate + i);
value[i] = INITIAL_BALANCE;
}
printf("\n");
for (year = 1; year <= num_years; year++) {
printf("%3d ", year);
for (i = 0; i < NUM_RATES; i++) {
value[i] += (low_rate + i) / 100.0 * value[i];
printf("%7.2f", value[i]);
}
printf("\n");
}
return 0;
}
输出
Enter interest rate: 6
Enter number of years5
Years 6% 7% 8% 9% 10%
1 106.00 107.00 108.00 109.00 110.00
2 112.36 114.49 116.64 118.81 121.00
3 119.10 122.50 125.97 129.50 133.10
4 126.25 131.08 136.05 141.16 146.41
5 133.82 140.26 146.93 153.86 161.05
8.2 多维数组
特性 | 说明 | 代码 |
---|---|---|
多维数组初始化 | 未指定的元素零初始化 注意: 花括号的嵌套 (可以省略花括号, 但是不建议, 可能导致初始化未对齐, 丢失元素等情况) | int a[2][2] ={{1, 2}, {3, 4}}; |
指定初始化 #C99 | int a[2][2] = {[0][0] = 1}; |
8.3 常量数组
加上const
关键字保证该数组的元素无法被修改.
const char hex_char[] = {`1`, `2`, `3`}
(程序) 抽牌
deal.c
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#include <time.h>
#define NUM_SUITS 4 // 花色
#define NUM_RANKS 13 // 数字
int main(void) {
bool in_hand[NUM_SUITS][NUM_RANKS] = {false}; // 表示手中的纸牌
int num_cards, rank, suit;
const char rank_code[] = {'2', '3', '4', '5', '6', '7', '8', '9', 't', 'j', 'q', 'k', 'a'};
const char suit_code[] = {'c', 'd', 'h', 's'};
srand((unsigned) time(NULL));
printf("Enter number of cards in hand: ");
scanf("%d", &num_cards);
printf("Your hand: ");
while (num_cards > 0) {
suit = rand() % NUM_SUITS;
rank = rand() % NUM_RANKS;
if (!in_hand[suit][rank]) {
in_hand[suit][rank] = true;
num_cards--;
printf(" %c%c", rank_code[rank], suit_code[suit]);
}
}
printf("\n");
return 0;
}
运行:
Enter number of cards in hand: 5
Your hand: qs 5h 2h 7s 2s
8.4 C99中的变长数组
特性 | 说明 | 代码 |
---|---|---|
变长 | 可以使用变量动态分配数组 | |
无法初始化 | 变长数组不能像定长数组那样初始化, 因为无法确定初始化长度 | |
无静态存储期限(持续性) | 14章学习 |
练习题
答案链接:
- http://knking.com/books/c2/answers/c8.html
- https://github.com/williamgherman/c-solutions/tree/master/08
记号说明:
- 加粗(错误): 表示错误的答案或者遗漏的知识点
- 在代码块中
(错误)
: 表示错误的答案
Practice1
前面讨论过,可以用表达式sizeof(a) / sizeof(a[0])计算数组元素个数。表达式sizeof(a) / sizeof(t)也可以完成同样的工作,其中表示数组a中元素的类型,但我们认为这是一种较差的方法。这是为什么呢?
回答: 使用变量名是更加统一的写法, 如果使用类型名可能需要回到变量生命处查看
Practice2
问与答"部分介绍了使用字母作为数组下标的方法。请描述一下如何使用数字 (字符格式的)作为数组的下标。
回答: '\xHH'
(错误)
订正: array[c - '0']
Practice3
声明一个名为weekend 的数组,其中包含7个bool 值。要求用一个初始化式把第一个和最后一个值置为true ,其他值都置为 false 。
回答: 使用C99的指定初始化比较合适
#include <stdio.h>
#include <stdbool.h>
int main(void) {
bool weekend[7] = {[0] = true, [6] = true};
for (int i = 0; i < 7; i++) {
printf(" %d", weekend[i]);
}
printf("\n");
return 0;
}
运行
1 0 0 0 0 0 1
Practice4
C99)重复练习题3,但这次用指定初始化式。要求初始化式尽可能地简短。
回答: 上题已经使用了指定初始化, 不重复
Practice5
斐波那契数为0, 1, 1, 2, 3, 5, 8, 13,...,其中每个数是其前面两个数的和。编写一个程序片段,声明一个名为fib_number 的长度为40的数组,并填入前40个斐波那契数。提示 :先填入前两个数,然后用循环计算其余的数。
回答:
#include <stdio.h>
int main(void) {
int fibonacci[40] = {1, 1, };
for (int i = 2; i < 40; i++)
fibonacci[i] = fibonacci[i - 1] + fibonacci[i - 2];
for (int i = 0; i < 40; i++)
printf(" %d", fibonacci[i]);
printf("\n");
return 0;
}
运行:
1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 4181 6765 10946 17711 28657 46368 75025 121393 196418 317811 514229 832040 1346269 2178309 3524578 5702887 9227465 14930352 24157817 39088169 63245986 102334155
Practice6
计算器、电子手表和其他电子设备经常依靠七段显示器进行数值的输出。为了组成数字,这类设备需要"打开"7个显示段中的某些部分,同时"关闭"其他部分:
_ _ _ _ _ _ _ _
| | | _| _| |_| |_ |_ | |_| |_|
|_| | |_ _| | _| |_| | |_| _|
显示灯对应的数字如下
0
_
5| _6|1
4| _ |2
3
下面是数组的可能形式,每一行表示一个数字, 请填充余下的部分。
const int segments[10][7] = {{1, 1, 1, 1, 1, 1, 0}, ...};
回答:
const int aegments[10][7] = {
{1, 1, 1, 1, 1, 1, 0}, // 0
{0, 1, 1, 0, 0, 0, 0}, // 1
{1, 1, 0, 1, 1, 0, 1}, // 2
{1, 1, 1, 1, 0, 0, 1}, // 3
{0, 1, 1, 0, 0, 1, 1}, // 4
{1, 0, 1, 1, 0, 1, 1}, // 5
{1, 0, 1, 1, 1, 1, 1}, // 6
{1, 1, 1, 0, 0, 0, 0}, // 7
{1, 1, 1, 1, 1, 1, 1}, // 8
{1, 1, 1, 1, 0, 1, 1}, // 9
}
Practice7
利用8.2节的简化方法,尽可能地缩短(练习题6中)数组 segments 的初始化式。
回答: 只想到了指定初始化, 但是感觉更复杂
订正:
const int segments[10][7] = {{1, 1, 1, 1, 1, 1},
{0, 1, 1},
{1, 1, 0, 1, 1, 0, 1},
{1, 1, 1, 1, 0, 0, 1},
{0, 1, 1, 0, 0, 1, 1},
{1, 0, 1, 1, 0, 1, 1},
{1, 0, 1, 1, 1, 1, 1},
{1, 1, 1},
{1, 1, 1, 1, 1, 1, 1},
{1, 1, 1, 1, 0, 1, 1}};
Practice8
为一个名为temperature_readings 的二维数组编写声明。该数组存储一个月中每小时的温度读数。(简单起见,假定每个月有 30天。)数组的每一行对应一个月中的每一天,每一列对应一天中的小时数。
回答:
float temperature_readings[30][24];
Practice9
利用练习题8中的数组,编写一段程序计算一个月的平均温度 (对一月中的每一天和一天中的每个小时取平均)。
回答:
#include <stdio.h>
int main(void) {
float temperature[30][24] = {1, 2, 3};
float adv_month, adv_day[30];
for (int i = 0; i < 30; i++) {
for (int j = 0; j < 24; j++) {
adv_day[i] += temperature[i][j];
}
adv_day[i] /= 24;
adv_month += adv_day[i];
}
adv_month /= 30;
printf("average temperature in month: %f\n\n", adv_month);
printf("average temperature in day:");
for (int i = 0 ; i < 30; i++) {
printf(" %.2f", adv_day[i]);
}
printf("\n");
return 0;
}
Practice10
为一个8×8的字符数组编写声明,数组名为chess_board 。用一个初始化式把下列数据放入数组(每个字符对应一个数组元素):
r n b q k b n r
p p p p p p p p
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
P P P P P P P P
R N B Q K B N R
回答:
char chess_board[8][8] = {
{'r', 'n', 'b', 'q', 'k', 'b', 'n', 'r'},
{'p', 'p', 'p', 'p', 'p', 'p', 'p', 'p'},
{'.', '.', '.', '.', '.', '.', '.', '.'},
{'.', '.', '.', '.', '.', '.', '.', '.'},
{'.', '.', '.', '.', '.', '.', '.', '.'},
{'.', '.', '.', '.', '.', '.', '.', '.'},
{'P', 'P', 'P', 'P', 'P', 'P', 'P', 'P'},
{'R', 'N', 'B', 'Q', 'K', 'B', 'N', 'R'},
};
Practice11
为一个8×8的字符数组编写声明,数组名为checker_board 。然后用一个循环把下列数据写入数组(每个字符对应一个数组元素):
提示:
B R B R B R B R
R B R B R B R B
B R B R B R B R
R B R B R B R B
B R B R B R B R
R B R B R B R B
B R B R B R B R
R B R B R B R B
回答:
#include <stdio.h>
int main(void) {
char checker_board[8][8];
char even[2] = {'B', 'R'};
char odd[2] = {'R', 'B'};
for (int i = 0 ; i < 8; i++) {
for (int j = 0; j < 8; j++) {
if (i % 2 == 0) { // even
checker_board[i][j] = even[j % 2];
} else { // odd
checker_board[i][j] = odd[j % 2];
}
}
}
for (int i = 0; i < 8; i++) {
for (int j = 0; j < 8; j++) {
printf("%c ", checker_board[i][j]);
}
printf("\n");
}
return 0;
}
运行:
B R B R B R B R
R B R B R B R B
B R B R B R B R
R B R B R B R B
B R B R B R B R
R B R B R B R B
B R B R B R B R
R B R B R B R B
代码题
code1-repdigit2
修改8.1节的程序repdigit.c ,使其可以显示出哪些数字有重复(如果有的话):
Enter a number: 939577
Repeated digit(s): 7 9
代码如下
#include <stdio.h>
#include <stdbool.h>
int main(void) {
bool digit_seen[10] = {false};
bool repeat[10] = {false};
bool flag = false; // 记录是否存在重复数字
int digit;
long n;
printf("Enter a number: ");
scanf("%ld", &n);
while (n > 0) {
digit = n % 10;
if (digit_seen[digit])
repeat[digit] = true; // 不结束循环, 记录重复数字
digit_seen[digit] = true; // 重复赋值为true不影响
n /= 10;
}
for (int i = 0; i < 10; i++) {
if (repeat[i] == true) {
flag = true;
break;
}
}
if (flag) {
printf("Repeated digit(s): ");
for (int i = 0; i < 10; i++) {
if (repeat[i] == true)
printf("%d ", i);
}
printf("\n");
}
else
printf("No repeated digit.\n");
return 0;
}
编译并运行
Enter a number: 12345
No repeated digit.
Enter a number: 939577
Repeated digit(s): 7 9
code2-repdigit3
修改8.1节的程序repdigit.c ,使其打印出一份列表,显示出每个数字在数中出现的次数:
Enter a number: 41271092
Digit: 0 1 2 3 4 5 6 7 8 9
Occurrences: 1 2 2 0 1 0 0 1 0 1
代码如下
#include <stdio.h>
#include <stdbool.h>
int main(void) {
int repeat[10] = {0};
int digit;
long n;
printf("Enter a number: ");
scanf("%ld", &n);
while (n > 0) {
digit = n % 10;
repeat[digit]++; // 不结束循环, 记录重复次数
n /= 10;
}
printf("Digit: ");
for (int i = 0 ;i < 10; i++)
printf("%d ", i);
printf("\n");
printf("Occurrences: ");
for (int i = 0 ;i < 10; i++)
printf("%d ", repeat[i]);
printf("\n");
return 0;
}
编译并运行
Enter a number: 41271092
Digit: 0 1 2 3 4 5 6 7 8 9
Occurrences: 1 2 2 0 1 0 0 1 0 1
code3-repdigit4
修改8.1节的程序repdigit.c ,使得用户可以录入多个数进行重复数字的判断。当用户录入的数小于或等于0时,程序终止。
代码如下
#include <stdio.h>
#include <stdbool.h>
int main(void) {
bool digit_seen[10] = {false};
int digit;
long n;
printf("Enter a number: ");
scanf("%ld", &n);
while (n > 0) {
while (n > 0) {
digit = n % 10;
if (digit_seen[digit])
break;
digit_seen[digit] = true;
n /= 10;
}
if (n > 0)
printf("Repeated digit\n");
else
printf("No repeated digit.\n");
printf("Enter a number: ");
scanf("%ld", &n);
}
printf("\nquit.\n");
return 0;
}
编译并运行
Enter a number: 1123
Repeated digit
Enter a number: 123
Repeated digit
Enter a number: 0
quit.
code4-reverse2
修改8.1节的程序reverse.c ,利用表达式(int) (sizeof(a) / sizeof(a[0])) (或者具有相同值的宏)来计算数组的长度。
代码如下
#include <stdio.h>
int main(void) {
int a[10], i;
printf("Enter %d number: ", (int) (sizeof(a) / sizeof(a[0])));
for (i = 0; i < (int) (sizeof(a) / sizeof(a[0])); i++)
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;
}
编译并运行
Enter 10 number: 0 1 2 3 4 5 6 7 8 9
In reverse order: 9 8 7 6 5 4 3 2 1 0
code5-interest2
修改8.1节的程序interest.c ,使得修改后的程序可以每月整合一次利息,而不是每年整合一次利息。不要改变程序的输出格式,余额仍按每年一次的时间间隔显示。
代码如下
#include <stdio.h>
#define NUM_RATES ((int) (sizeof(value) / sizeof(value[0])))
#define INITIAL_BALANCE 100.00
int main(void) {
int i, low_rate, num_years, year;
double value[5];
printf("Enter interest rate: ");
scanf("%d", &low_rate);
printf("Enter number of years: ");
scanf("%d", &num_years);
printf("\nYears");
for (i = 0; i < NUM_RATES; i++) {
printf("%6d%%", low_rate + i);
value[i] = INITIAL_BALANCE;
}
printf("\n");
for (year = 1; year <= num_years; year++) {
printf("%3d ", year);
for (i = 0; i < NUM_RATES; i++) {
for (int j = 0; j < 12; j++) {
value[i] += (low_rate + i) / 1200.0 * value[i];
}
printf("%7.2f", value[i]);
}
printf("\n");
}
return 0;
}
编译并运行
Enter interest rate: 5
Enter number of years: 5
Years 5% 6% 7% 8% 9%
1 105.12 106.17 107.23 108.30 109.38
2 110.49 112.72 114.98 117.29 119.64
3 116.15 119.67 123.29 127.02 130.86
4 122.09 127.05 132.21 137.57 143.14
5 128.34 134.89 141.76 148.98 156.57
code6-message
网络新手的原型是一个名为B1FF的人,他有一种独特的编写消息的方法。下面是一条常见的B1FF公告:
H3Y DUD3, C 15 R1LLY C00L!!!!!!!!!!
编写一个"B1FF过滤器",它可以读取用户录入的消息并把此消息翻译成B1FF的表达风格:
程序需要把消息转换成大写字母,用数字代替特定的字母(A→4, B→8, E→3, I→1, O→0, S→5),然后添加10个左右的感叹号。提示 :把原始消息存储在一个字符数组中,然后从数组头开始逐个翻译并显示字符。
Enter message: Hey dude, C is rilly cool
In B1FF-speak: H3Y DUD3, C 15 R1LLY C00L!!!!!!!!!!
代码如下
#include <stdio.h>
#include <ctype.h>
int main(void) {
char s[40] = {0};
char ch, len;
printf("Enter message: ");
while ((ch = getchar()) != '\n') {
switch(ch) {
case 'A': case 'a': ch = '4'; break;
case 'B': case 'b': ch = '8'; break;
case 'E': case 'e': ch = '3'; break;
case 'I': case 'i': ch = '1'; break;
case 'O': case 'o': ch = '0'; break;
case 'S': case 's': ch = '5'; break;
}
s[len++] = toupper(ch);
}
printf("In B1FF-speak: %s!!!!!!!!!!\n", s);
return 0;
}
编译并运行
Enter message: Hey dude, C is rilly cool
In B1FF-speak: H3Y DUD3, C 15 R1LLY C00L!!!!!!!!!!
code7-sum
编写程序读取一个5×5的整数数组,然后显示出每行的和与每列的和。
Enter row 1: 8 3 9 0 10
Enter row 2: 3 5 17 1 1
Enter row 3: 2 8 6 23 1
Enter row 4: 15 7 3 2 9
Enter row 5: 6 14 2 6 0
Row totals: 30 27 40 36 28
Column totals: 34 37 37 32 21
代码如下
#include <stdio.h>
int main(void) {
int num[5][5] = {
{8, 3, 9, 0, 10},
{3, 5, 17, 1, 1},
{2, 8, 6, 23, 1},
{15, 7, 3, 2, 9},
{6, 14, 2, 6, 0}
};
int row[5] = {0}; // 零初始化
int column[5] = {0}; // 零初始化
for (int i = 0; i < 5; i++) {
for (int j = 0; j < 5; j++) {
row[i] += num[i][j];
column[i] += num[j][i];
}
}
printf("Row totals: ");
for (int i = 0; i < 5; i++)
printf("%d ", row[i]);
printf("\n");
printf("Column totals: ");
for (int i = 0; i < 5; i++)
printf("%d ", column[i]);
printf("\n");
return 0;
}
编译并运行
Row totals: 30 27 40 36 28
Column totals: 34 37 37 32 21
code8-student
修改编程题7,使其提示用户输入每个学生5门测验的成绩,一共有5个学生。然后计算每个学生的总分和平均分,以及每门测验的平均分、高分和低分。
代码如下
#include <stdio.h>
int main(void) {
float student[5][5] = {0};
float score[5] = {0};
float average = 0;
float subject[5] = {0};
float max[5] = {0}, min[5] = {100, 100, 100, 100, 100};
for (int i = 0; i < 5; i++) {
printf("Enter a student's score: ");
scanf("%f %f %f %f %f", &student[i][0],
&student[i][1], &student[i][2],
&student[i][3], &student[i][4]);
}
for (int i = 0; i < 5; i++)
for (int j = 0; j < 5; j++) {
score[i] += student[i][j];
subject[i] += student[j][i];
if (student[j][i] > max[i])
max[i] = student[j][i];
if (student[j][i] < min[i])
min[i] = student[j][i];
}
for (int i = 0; i < 5; i++) {
average += score[i];
}
average /= 5;
for (int i = 0; i < 5; i++)
printf("student[%d]'s score: %f\n", i, score[i]);
printf("student's average score: %f\n", average);
for (int i = 0; i < 5; i++)
printf("subject[%d]'s average score: %f\n", i, subject[i] / 5);
printf("max = ");
for (int i = 0; i < 5; i++)
printf("%f ", max[i]);
printf("\n");
printf("min = ");
for (int i = 0; i < 5; i++)
printf("%f ", min[i]);
printf("\n");
return 0;
}
编译并运行
Enter a student's score: 10 20 30 40 50
Enter a student's score: 30 10 20 30 30
Enter a student's score: 60 60 70 90 50
Enter a student's score: 80 70 60 40 20
Enter a student's score: 30 40 60 50 30
student[0]'s score: 150.000000
student[1]'s score: 120.000000
student[2]'s score: 330.000000
student[3]'s score: 270.000000
student[4]'s score: 210.000000
student's average score: 216.000000
subject[0]'s average score: 42.000000
subject[1]'s average score: 40.000000
subject[2]'s average score: 48.000000
subject[3]'s average score: 50.000000
subject[4]'s average score: 36.000000
max = 80.000000 70.000000 70.000000 90.000000 50.000000
min = 10.000000 10.000000 20.000000 30.000000 20.000000
code9-random
编写程序,生成一种贯穿10×10字符数组(初始时全为字符'.' )的"随机步法"。程序必须随机地从一个元素 "走到"另一个元素,每次都向上、向下、向左或向右移动一个元素位置。已访问过的元素按访问顺序用字母A 到Z 进行标记。下面是一个输出示例:
A . . . . . . . . .
B C D . . . . . . .
. F E . . . . . . .
H G . . . . . . . .
I . . . . . . . . .
J . . . . . . . Z .
K . . R S T U V Y .
L M P Q . . . W X .
. N O . . . . . . .
. . . . . . . . . .
提示 :利用srand 函数和rand 函数(见程序deal.c )产生随机数,然后查看此数除以4的余数。余数一共有4种可能的值(0、 1、2和3),指示下一次移动的4种可能方向。在执行移动之前,需要检查两项内容:
- 一是不能走到数组外面,
- 二是不能走到已有字母标记的位置。
只要有一个条件不满足,就得尝试换一个方向移动。如果4个方向都堵住了,程序就必须终止了。下面是提前结束的一个示例:
A B G H I . . . . .
. C F . J K . . . .
. D E . M L . . . .
. . . . N O . . . .
. . W X Y P Q . . .
. . V U T S R . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
因为Y的4个方向都堵住了,所以没有地方可以放置下一步的Z了。
代码如下
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main(void) {
char matrix[10][10];
int x = 0, y = 0; // position
char ch = 'B';
int direction, try = 0;
// initialize
srand((unsigned) time(NULL));
for (int i = 0; i < 10; i++)
for (int j = 0; j < 10; j++)
matrix[i][j] = '.';
matrix[0][0] = 'A';
// 0 = up, 1 = right, 2 = down, 3 = left
direction = rand() % 4;
while (ch <= 'Z') { // 'B' = 'A' + 1
int tmp_x = x; int tmp_y = y; // 记录回溯坐标
// 选择方向
switch(direction) {
case 0: x--; break;
case 1: y++; break;
case 2: x++; break;
case 3: y--; break;
}
// 检查: 越界和堵塞
if (x < 0 || x > 9 || y < 0 || y > 9 || matrix[x][y] != '.') {
if (try == 3) {
break; // 尝试三次说明所有方向均无法移动
}
x = tmp_x;
y = tmp_y;
try++;
direction = (direction + 1) % 4; // 切换下一个方向
continue; // 跳过随机数赋值
}
try = 0; // 如果成功, try归零
matrix[x][y] = ch++;
direction = rand() % 4;
}
for (int i = 0; i < 10; i++) {
for (int j = 0; j < 10; j++) {
printf("%c ", matrix[i][j]);
}
printf("\n");
}
return 0;
}
编译并运行
只执行至X, 堵塞
A B C D E F G H I J
. . . . . . . U V K
. . . . . . S T W L
. . . . . . R Q X M
. . . . . . . P O N
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
完整执行
A B E F . . . . . .
. C D G . . . . . .
. . . H . . . . . .
. . J I T U X Y . .
. . K R S V W Z . .
. . L Q P . . . . .
. . M N O . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
code10-phone
修改第7章的编程题4,给输出加上标签:
在显示电话号码之前,程序需要将其(以原始格式或数值格式)存储在一个字符数组中。可以假定电话号码的长度不超过15个字符。
Enter phone number: 1-800-COL-LECT
In numeric form: 1-800-265-5328
代码如下
#include <stdio.h>
int main(void) {
char phone[15] = {0};
char counter = 0;
printf("Enter phone number: ");
for (int i = 0; i < 15; i++) {
if ((phone[i] = getchar()) == '\n') {
phone[i] = '\0';
break;
}
}
while (phone[counter] != '\0') {
switch(phone[counter]) {
case 'A': case 'B': case 'C':
phone[counter] = '2'; break;
case 'D': case 'E': case 'F':
phone[counter] = '3'; break;
case 'G': case 'H': case 'I':
phone[counter] = '4'; break;
case 'J': case 'K': case 'L':
phone[counter] = '5'; break;
case 'M': case 'N': case 'O':
phone[counter] = '6'; break;
case 'P': case 'Q': case 'R': case 'S':
phone[counter] = '7'; break;
case 'T': case 'U': case 'V':
phone[counter] = '8'; break;
case 'W': case 'X': case 'Y': case 'Z':
phone[counter] = '9'; break;
}
counter++;
}
printf("%s\n", phone);
return 0;
}
编译并运行
Enter phone number: 1-800-COL-LECT
1-800-265-5328
code11-character2
在十字拼字游戏中,玩家利用小卡片组成单词,每个卡片包含字母和面值。面值根据字母稀缺程度的不同而不同。(面值有:1------ AEILNORSTU,2------DG,3------BCMP,4------FHVWY,5------K,8------JX, 10------QZ。)编写程序通过对单词中字母的面值求和来计算单词的值:
编写的程序应该允许单词中混合出现大小写字母。提示 :使用 toupper 库函数。
修改第7章的编程题5,用数组存储字母的面值。数组有26个元素,对应字母表中的26个字母。例如,数组元素0存储1(因为字母A的面值为1),数组元素1存储3(因为字母B的面值为3),等等。每读取输入单词中的一个字母,程序都会利用该数组确定字符的拼字值。使用数组初始化式来建立该数组。
代码如下
#include <stdio.h>
#include <ctype.h>
int main(void) {
int value[26] = {
1, 3, 3, 2, 1, 4, 2, 4, 1, 8, 5,
1, 3, 1, 1, 3, 10, 1, 1, 1, 1, 4,
4, 8, 4, 10
};
char ch;
int counter = 0;
printf("Enter a word: ");
while ((ch = getchar()) != '\n') {
ch = toupper(ch);
counter += value[ch - 'A'];
}
printf("\nScrabble value: %d\n", counter);
return 0;
}
编译并运行
Enter a word: pitfall
Scrabble value: 12
code12-sentence
编写程序颠倒句子中单词的顺序:
提示 :用循环逐个读取字符,然后将它们存储在一个一维字符数组中。当遇到句号、问号或者感叹号(称为"终止字符")时,终止循环并把终止字符存储在一个char类型变量中。然后再用一个循环反向搜索数组,找到最后一个单词的起始位置。显示最后一个单词,然后反向搜索倒数第二个单词。重复这一过程,直至到达数组的起始位置。最后显示出终止字符。
Enter a sentence: you can cage a swallow can't you?
Reversal of sentence: you can't swallow a cage can you?
代码如下
#include <stdio.h>
int main(void) {
char sentence[50] = {0};
char ch;
int i, start, end; // 记录单词起始和终止位置
printf("Enter a sentence: ");
for (i = 0; (ch = getchar()) != '.' && ch != '?' && ch != '!'; i++)
sentence[i] = ch;
// 终止: i为末尾0, 且终止符没有写入数组
printf("Reversal of sentence: ");
for (end = i; i >= 0; i--) {
if (sentence[i] == ' ') {
start = i + 1;
for (int j = start; j < end; j++)
putchar(sentence[j]);
end = i;
printf(" ");
}
}
for (int j = 0; j < end; j++) // 打印最后一个字符
putchar(sentence[j]);
printf("%c\n", ch); // 打印结束符
return 0;
}
编译并运行
Enter a sentence: you can cage a swallow can't you?
Reversal of sentence: you can't swallow a cage can?
code13-encrypt
已知的最古老的一种加密技术是凯撒加密(得名于Julius Caesar)。该方法把一条消息中的每个字母用字母表中固定距离之后的那个字母来替代。(如果越过了字母Z,会绕回到字母表的起始位置。例如,如果每个字母都用字母表中两个位置之后的字母代替,那么Y就被替换为A, Z就被替换为B。)编写程序用凯撒加密方法对消息进行加密。用户输入待加密的消息和移位计数(字母移动的位置数目)
可以假定消息的长度不超过80个字符。不是字母的那些字符不要改动。此外,加密时不要改变字母的大小写。
Enter message to be encrypted: Go ahead, make my day.
Enter shift amount (1-25): 3
Encrypted message: Jr dkhdg, pdnh pb gdb.
代码如下
#include <stdio.h>
int main(void) {
char s[80] = {0};
int shift = 0;
printf("Enter message to be encrypted: ");
for (int i = 0; (s[i] = getchar()) != '\n'; i++);
printf("Enter shift amount (1-25): ");
scanf("%d", &shift);
for (int i = 0; s[i] != '\0'; i++) {
if ('A' <= s[i] && s[i] <= 'Z')
s[i] = (s[i] - 'A' + shift) % 26 + 'A';
if ('a' <= s[i] && s[i] <= 'z')
s[i] = (s[i] - 'a' + shift) % 26 + 'a';
}
printf("\nEncrypted message: %s\n", s);
return 0;
}
编译并运行
Enter message to be encrypted: Go ahead, make my day.
Enter shift amount (1-25): 3
Encrypted message: Jr dkhdg, pdnh pb gdb.
code14-check
编程测试两个单词是否为变位词(相同字母的重新排列):
Enter first word: smartest
Enter second word: mattress
The words are anagrams.
Enter first word: dumbest
Enter second word: stumble
The words are not anagrams.
代码如下
#include <stdio.h>
#include <stdbool.h>
int main(void) {
char counter1[26] = {0};
char counter2[26] = {};
char ch;
bool flag = 1;
printf("Enter first word: ");
while ((ch = getchar()) != '\n')
counter1[ch - 'a']++;
printf("\nEnter second word: ");
while ((ch = getchar()) != '\n')
counter2[ch - 'a']++;
for (int i = 0; i < 26; i++)
if (counter1[i] != counter2[i])
flag = 0;
if (flag)
printf("\nThe words are anagrams.\n");
else
printf("\nThe words are not anagrams.\n");
return 0;
}
编译并运行
Enter first word: smartest
Enter second word: mattress
The words are anagrams.
Enter first word: dumbest
Enter second word: stumble
The words are not anagrams.
code15-matrix
编写程序打印n * n的幻方($1, 2, ..., n^2$的方阵排列,且每行、每列和每条对角线上的和都相等)。由用户指定n的值:
This program creates a magic square of a specified size.
The size must be an odd number between 1 and 99.
Enter size of magic square: 5
17 24 1 8 15
23 5 7 14 16
4 6 13 20 22
10 12 19 21 3
11 18 25 2 9
把幻方存储在一个二维数组中。起始时把数1放在0行的中间,剩下的数$2, 3, ..., n^2$依次向上移动一行并向右移动一列。
- 当可能越过数组边界时需要"绕回"到数组的另一端。例如,如果需要把下一个数放到-1行,我们就将其存储到行(最后一行);如果需要把下一个数放到n列,我们就将其存储到0列。
- 如果某个特定的数组元素已被占用,那就把该数存储在前一个数的正下方。如果你的编译器支持变长数组,声明数组有n行n列,否则声明数组有99行99列。
代码
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int n;
printf("This program creates a magic square of a specified size.\n");
printf("The size must be an odd number between 1 and 99.\n");
printf("Enter size of magic square: ");
scanf("%d", &n);
int ** matrix = (int **) malloc(n * sizeof (int *));
for (int i = 0; i < n; i++)
matrix[i] = (int *) malloc(n * sizeof(int)); // 变长数组, 不可初始化
int x = 0, y = n / 2;
for (int i = 1; i <= n * n; i++) {
matrix[x][y] = i;
x = (x - 1 + n) % n;
y = (y + 1) %n;
if (matrix[x][y] != 0) {
x = (x + 2) % n;
y = (y - 1 + n) %n;
}
}
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
printf(" %d", matrix[i][j]);
}
printf("\n");
}
free(matrix);
return 0;
}
编译并运行
This program creates a magic square of a specified size.
The size must be an odd number between 1 and 99.
Enter size of magic square: 5
17 24 1 8 15
23 5 7 14 16
4 6 13 20 22
10 12 19 21 3
11 18 25 2 9