C语言程序设计精髓 第十一周 指针的孪生兄弟
从这一章开始难度才算是真正开始加大了,前面可以说都在过家家。
练兵区——编程题——不计入总分
1找出按字典顺序排在最前面的国名(4分)
题目内容:
输入5个国名,编程找出并输出按字典顺序排在最前面的国名。
提示:所谓字典顺序就是将字符串按由小到大的顺序排列,因此找出按字典顺序排在最前面的国名指的就是最小的字符串。
#include<stdio.h>
#include<string.h>
#define NUM 5
#define STR_LEN 10
void findMinimumStr(char *str, int row, int column);
int main(){
// we haven't learned how to define dynamic array
char country[NUM][STR_LEN];
printf("Input five countries' names:\n");
for(int i = 0; i < NUM; i++){
gets(country[i]);
}
findMinimumStr(*country, NUM, STR_LEN);
printf("The minimum is:%s\n", country[0]);
return 0;
}
// search by row needle, so that we can ignore the size of array
void findMinimumStr(char *str, int row, int column){
char temp[column];
for(int i = 0; i < row - 1; i++){
for(int j = 1; j < row - i; j++){
if(strcmp(str + j * column, str + (j - 1) * column) < 0){
// swap
strncpy(temp, str + j * column, column);
strncpy(str + j * column, str + (j - 1) * column, column);
strncpy(str + (j - 1) * column, temp, column);
}
}
}
}
- 为了练习指针的使用,函数里没有用传统的下标来遍历数组,而是使用列指针来访问数组。
- 球球别写这种code了,因为没有初始化指针,搁着乱用指针!(感觉自己有点蠢
所以试图使用char *temp = NULL; *temp = "ddd";
char *country[];
但是没有初始化的指针数组,来存储多个不同长度的字符串方式是不可取的! - 切记:对指针进行的运算操作,加上或减去的是
sizeof(基类型)
- 例如:
char str[2][3]
对于str++
等同于:str + sizeof(char [3])
对于str[0]++
等同于:str + sizeof(char)
- 再例如:
str + j * column
,来遍历多维字符数组,每一纬度代表一个字符串,为什么要加j * column
?因为传入的是一个字符指针,它指向str[0][0]
,要指向第j
个字符串,注意指针的指针char *str
的基类型,str + j
只是指向了str[0][1]
,而不是str[1][0]
!
- 例如:
- 另外,这道题不能用前面视频里那样:字符指针数组 + 交换指针提升效率。因为我们还没学到动态数组,所以只能采取最原始的方式。
3月份表示(4分)
题目内容:
用指针数组保存表示每个月份的英文单词以及“Illegal month”的首地址,然后编程实现:从键盘任意输入一个数字表示月份值n,程序输出该月份的英文表示,若n不在1~12之间,则输出“Illegal month”。
#include<stdio.h>
int main() {
int input;
char *month[] = {"Illegal month", "January", "Feburary", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"};
printf("Input month number:\n");
scanf("%d", &input);
if(input > 0&&input <= 12){
printf("month %d is %s\n", input, month[input]);
}
else printf("%s\n", month[0]);
return 0;
}
4程序改错——1(4分)
题目内容:
从键盘任意输入m个学生n门课程的成绩,然后计算每个学生各门课的总分sum和平均分aver。下面程序存在极为隐蔽的错误,请分析错误的原因,并修改程序,同时按照给出的程序运行示例检查修改后的程序。
#include <stdio.h>
#define STUD 30 //最多可能的学生人数
#define COURSE 5 //最多可能的考试科目数
void Total(int *score, int sum[], float aver[], int m, int n);
void Print(int *score, int sum[], float aver[], int m, int n);
int main(void)
{
int i, j, m, n, score[STUD][COURSE], sum[STUD];
float aver[STUD];
printf("Enter the total number of students and courses:\n");
scanf("%d%d",&m,&n);
printf("Enter score:\n");
for (i=0; i<m; i++)
{
for (j=0; j<n; j++)
{
scanf("%d", &score[i][j]);
}
}
Total(*score, sum, aver, m, n);
Print(*score, sum, aver, m, n);
return 0;
}
void Total(int *score, int sum[], float aver[], int m, int n)
{
int i, j;
for (i=0; i<m; i++)
{
sum[i] = 0;
for (j=0; j<n; j++)
{
sum[i] = sum[i] + *(score + i * COURSE + j);
}
aver[i] = (float) sum[i] / n;
}
}
void Print(int *score, int sum[], float aver[], int m, int n)
{
int i, j;
printf("Result:\n");
for (i=0; i<m; i++)
{
for (j=0; j<n; j++)
{
printf("%4d", *(score + i * COURSE + j));
}
printf("%5d%6.1f\n", sum[i], aver[i]);
}
}
5程序改错——2(4分)
题目内容:
下面主函数调用函数SortString()按奥运会参赛国国名在字典中的顺序对其入场次序进行排序,目前程序存在错误,请修改正确,并按照给出的程序运行示例检查修改后的程序。
#include <stdio.h>
#include <string.h>
#define M 150 /* 最多的字符串个数 */
#define N 10 /* 字符串最大长度 */
void SortString(char ptr[][M], int n);
int main()
{
int i, n;
char pStr[N][M];
printf("How many countries?\n");
scanf("%d",&n);
getchar(); /* 读走输入缓冲区中的回车符 */
printf("Input their names:\n");
for (i=0; i<n; i++)
{
gets(pStr[i]); /* 输入n个字符串 */
}
SortString(pStr, n); /* 字符串按字典顺序排序 */
printf("Sorted results:\n");
for (i=0; i<n; i++)
{
puts(pStr[i]); /* 输出排序后的n个字符串 */
}
return 0;
}
void SortString(char ptr[][M], int n)
{
int i, j;
char temp[M];
for (i=0; i<n-1; i++)
{
for (j=i+1; j<n; j++)
{ // 交换排序
if (strcmp(ptr[j], ptr[i]) < 0)
{
strncpy(temp, ptr[i], M);
strncpy(ptr[i], ptr[j], M);
strncpy(ptr[j], temp, M);
}
}
}
}
6找数组最值(4分)
题目内容:
按如下函数原型编程从键盘输入一个m行n列的二维数组,然后计算数组中元素的最大值及其所在的行列下标值。其中,m和n的值由用户键盘输入。已知m和n的值都不超过10。
void InputArray(int *p, int m, int n);
int FindMax(int *p, int m, int n, int *pRow, int *pCol);//函数返回最大值,pRow和pCol分别返回最大值所在的行列下标
#include<stdio.h>
#define MAX_SIZE 10
void InputArray(int *p, int m, int n);
int FindMax(int *p, int m, int n, int *pRow, int *pCol);//函数返回最大值,pRow和pCol分别返回最大值所在的行列下标
int main(){
int arr[MAX_SIZE][MAX_SIZE], row, column, pRow, pCol;
printf("Input m,n:\n");
scanf("%d,%d", &row, &column);
InputArray(*arr, row, column);
FindMax(*arr, row, column, &pRow, &pCol);
printf("max=%d,row=%d,col=%d\n", arr[pRow][pCol], pRow, pCol);
return 0;
}
void InputArray(int *p, int m, int n){
printf("Input %d*%d array:\n", m, n);
for(int i = 0; i < m; i++){
for(int j = 0; j < n; j++){
scanf("%d", p + i * MAX_SIZE + j);
}
}
}
int FindMax(int *p, int m, int n, int *pRow, int *pCol){
*pCol = 0;
*pRow = 0;
for(int i = 0; i < m; i++){
for(int j = 0; j < n; j++){
if(*(p + i * MAX_SIZE + j) > *(p + *pRow * MAX_SIZE + *pCol)){
*pCol = j;
*pRow = i;
}
}
}
return 0;
}
- 感觉直接融会贯通了。
7冒泡排序(4分)
题目内容:
采用冒泡法进行升序排序法的基本原理是:对数组中的n个数执行n-1遍检查操作,在每一遍执行时,对数组中剩余的尚未排好序的元素进行如下操作:对相邻的两个元素进行比较,若排在后面的数小于排在前面的数,则交换其位置,这样每一遍操作中都将参与比较的数中的最大的数沉到数组的底部,经过n-1遍操作后就将全部n个数按从小到大的顺序排好序了。
- 比较基础,所以加上之前思考题两种优化
- 去除排序开始末尾为有序时的无用排序
- 去除排序将要结束时数组前面的元素已经有序
#include<stdio.h>
#define N 10
void inputArr(int n, int *arr);
void outputArr(int n, int *arr);
void bubbleSort(int n, int *arr);
int main(){
int n, arr[N];
printf("Input n:");
scanf("%d", &n);
inputArr(n, arr);
bubbleSort(n, arr);
printf("Sorting results:");
outputArr(n, arr);
return 0;
}
void inputArr(int n, int *arr){
printf("Input %d numbers:", n);
for(int i = 0; i < n; i++){
scanf("%d", arr + i);
}
}
void outputArr(int n, int *arr){
for(int i = 0; i < n; i++){
printf("%4d", *(arr + i));
}
}
void bubbleSort(int n, int *arr){
int temp, flag, lastChangeIndex, boundaryPoint = n;
for(int i = 0; i < n - 1; i++){
flag = 0;
for(int j = 1; j < boundaryPoint; j++){
if(*(arr + j) < *(arr + j - 1)){
temp = *(arr + j);
*(arr + j) = *(arr + j - 1);
*(arr + j -1) = temp;
flag = 1;
lastChangeIndex = j;
}
}
boundaryPoint = lastChangeIndex;
if(!flag) {
break;
}
}
}
8删除字符串中与某字符相同的字符(4分)
题目内容:
在字符串中删除与某字符相同的字符,要求用字符数组作函数参数。
#include<stdio.h>
#define N 100
int deleteDuplicates(char str[], char ch);
int main(){
char str[N], ch;
printf("Input a string:\n");
gets(str);
printf("Input a character:\n");
ch = getchar();
deleteDuplicates(str, ch);
printf("Results:%s\n", str);
return 0;
}
int deleteDuplicates(char str[], char ch){
int count = 0;
char *temp;
for(; *str; str++){
if(*str == ch){
count++;
temp = str;
while(*temp){
*temp = *(temp + 1);
temp++;
}
}
}
return count;
}
9求最大数和最小数的最大公约数(4分)
题目内容:
从键盘输入10个正整数,求出最大数,最小数,以及他们的最大公约数。要求用数组实现。
#include<stdio.h>
#define N 10
void inputArr(int *arr, int size);
void findMinMax(int *min, int *max, int *arr, int size);
int commonDivisor(int a, int b);
int main(){
int arr[N];
int minP;
int maxP;
printf("Input 10 numbers:\n");
inputArr(arr, N);
findMinMax(&minP, &maxP, arr, N);
int res = commonDivisor(arr[minP], arr[maxP]);
printf("maxNum=%d\n", arr[maxP]);
printf("minNum=%d\n", arr[minP]);
if(res > 0){
printf("%d", res);
}
return 0;
}
void inputArr(int *arr, int size){
for(int i = 0; i < size; i++){
scanf("%d", arr + i);
}
}
void findMinMax(int *min, int *max, int *arr, int size){
*min = 0;
*max = 0;
for(int i = 0; i < size; i++){
if(*(arr + i) < *(arr + *min)){
*min = i;
}
if(*(arr + i) > *(arr + *max)){
*max = i;
}
}
}
int commonDivisor(int a, int b){
if(a <= 0 || b <= 0) return -1;
if(a == b) return a;
if(a > b) commonDivisor(a - b, b);
else commonDivisor(a, b - a);
}
10数列合并(4分)
题目内容:
已知两个不同长度的降序排列的数列(假设序列的长度都不超过5),请编程将其合并为一个数列,使合并后的数列仍保持降序排列。
#include<stdio.h>
#define N 5
void Merge(int a[], int b[], int c[], int m, int n);
void inputArr(int *arr, int size);
void outputArr(int *res, int size);
int main(){
int m, n, arr1[N], arr2[N], res[2*N];
printf("Input m,n:");
scanf("%d,%d", &m, &n);
printf("Input array a:");
inputArr(arr1, m);
printf("Input array b:");
inputArr(arr2, n);
Merge(arr1, arr2, res, m, n);
outputArr(res, m + n);
return 0;
}
void inputArr(int *arr, int size){
for(int i = 0; i < size; i++){
scanf("%d", arr + i);
}
}
void outputArr(int *res, int size){
for(int i = 0; i < size; i++){
printf("%4d", *(res + i));
}
}
void Merge(int a[], int b[], int c[], int m, int n){
int i = 0, j = 0;
while(i < m&&j < n){
if(*(a + i) >= *(b + j)){
*(c + i + j) = *(a + i);
i++;
}
else{
*(c + i + j) = *(b + j);
j++;
}
}
if(i != m){
for(;i < m;i++){
*(c + i + j) = *(a + i);
}
}
if(j != n){
for(;j < n;j++){
*(c + i + j) = *(b + j);
}
}
}
第11周编程题在线测试
1山地训练(4分)
题目内容:
为了能在下一次跑步比赛中有好的发挥,小白在一条山路上开始了她的跑步训练。她希望能在每次训练中跑得尽可能远,不过她也知道农场中的一条规定:女孩子独自进山的时间不得超过M秒(1 <= M <= 10,000,000)。假设整条山路划分成T个长度相同的路段(1 <= T <= 100,000),并且小白用si表示第i个路段的路况,用u、f、d这3个字母分别表示第i个路段是上坡、平地、下坡。小白跑完一段上坡路的耗时是U秒(1 <= U <= 100),跑完一段平地的耗时是F秒(1 <= F <= 100),跑完一段下坡路的耗时是D秒(1 <= D <= 100)。注意,沿山路原路返回时,原本是上坡的路段变成了下坡路段,原本是下坡的路段变成了上坡路段。小白想知道,在能按时返回农场的前提下,她最多能在这条山路上跑多少个路段。请你编程帮助她计算。
#include<stdio.h>
#define T_MAX 100000
long Fun(long M, long T, long U, long F, long D, char str[]);
int main(){
long m, t, u, f, d;
char str[T_MAX];
printf("Input M,T,U,F,D:");
scanf("%ld%ld%ld%ld%ld", &m, &t, &u, &f, &d);
printf("Input conditions of road:");
scanf("%s", str);
long res = Fun(m, t, u, f, d, str);
printf("num=%ld\n", res);
return 0;
}
long Fun(long M, long T, long U, long F, long D, char str[]){
long count = 0, timeUsed = 0;
while(*str){
if(*str == 'u'){
timeUsed += (U + D);
}
if(*str == 'd'){
timeUsed += (U + D);
}
if(*str == 'f'){
timeUsed += 2 * F;
}
if(timeUsed > M){
break;
}
count++;
str++;
}
return count;
}
2奇偶数分离(4分)
题目内容:
输入n个整数(n从键盘输入,假设n的值不超过100),按奇偶数分成两组并输出。输出两行,第一行为所有奇数,第二行为所有偶数,保持数据的相对顺序与输入顺序相同。
#include<stdio.h>
#define N 100
void inputArr(int *arr, int n);
void Seperate(int a[], int n); //数组a[]存放用户输入的n个整数
int main(){
int n, arr[N];
printf("Input n:");
scanf("%d", &n);
inputArr(arr, n);
Seperate(arr, n);
return 0;
}
void inputArr(int *arr, int n){
printf("Input numbers:");
for(int i = 0; i < n; i++){
scanf("%d", arr + i);
}
}
void Seperate(int a[], int n){
int flag = 1;
for(int i = 0; i < n; i++){
if(a[i] % 2 != 0){
if(flag) {
printf("%d", a[i]);
flag = 0;
}
else printf(",%d", a[i]);
a[i] = -1;
}
}
flag = 1;
for(int i = 0; i < n; i++){
if(a[i] >= 0||a[i] % 2 == 0){
if(flag) {
printf("\n%d", a[i]);
flag = 0;
}
else printf(",%d", a[i]);
}
}
}
3子串判断(4分)
题目内容:从键盘输入两个长度小于80的字符串A和B,且A的长度大于B的长度,编程判断B是不是A的子串,如果是,则输出”Yes”,否则输出”No”。这里所谓的该串的子串是指字符串中任意多个连续的字符组成的子序列。
#include<stdio.h>
#define N 80
int isSubstring(char str1[], char str2[]);
int main(){
char str1[N], str2[N];
printf("Input the first string:");
gets(str1);
printf("Input the second string:");
gets(str2);
int res = isSubstring(str1, str2);
if(res == 1){
printf( "Yes\n");
}else if(res == 0){
printf("No\n");
}
return 0;
}
int isSubstring(char str1[], char str2[]){
char *temp1, *temp2;
while(*str1){
temp1 = str1;
temp2 = str2;
while(*temp2){
if(*temp1 != *temp2){
break;
}
temp1++;
temp2++;
}
if(*temp2 == '\0'){
return 1;
}
str1++;
}
return 0;
}
4星期查找(4分)
题目内容:
任意输入英文的星期几,通过查找如图所示的星期表,输出其对应的数字,若查到表尾,仍未找到,则输出错误提示信息。
#include<stdio.h>
#include<string.h>
#define N 10
int search(char *str[], char *target, int size);
int main(){
char *str[] = {"Sunday", "Monday", "TuesDay", "Wednesday", "Thursday","Friday", "Saturday"}, target[N];
printf("Please enter a string:\n");
gets(target);
int res = search(str, target, 7);
if(res >= 0){
printf("%s is %d\n", str[res], res);
}
else{
printf("Not found!\n");
}
return 0;
}
int search(char *str[], char *target, int size){
for(int i = 0; i < size; i++){
if(strcmp(*(str + i), target) == 0){
return i;
}
}
return -1;
}