1.开发一个包含你需要的预处理器定义的头文件。
写一个.h的头文件,包含你此次练习的题目就可以了。注意防止头文件被重复引用导致的错误,需要用#ifndef或者#pragma once,下面题目需要的声明和结构都在对应题目中。
方法1 使用#ifndef的方法
#ifndef __16NEED__H__ //防止头文件被重复引用
#define __16NEED__H__ //第一次调用头文件,创建声明
/*
...
头文件主要包含的内容
...
*/
#endif
方法2 使用#pargma once的方法
#pargma once //VS2019头文件的默认模板就有,防止头文件被重复调用
/*
...
头文件内容
...
*/
定义调和平均数的宏函数,可以先定义一个平均数的宏,再定义调和平均书。该题目需要注意宏函数的变量规范,注意括号,防止意外的错误
#define MEAN(X,Y) (X+Y)/2 //平均数
#define HMMEAN(X,Y) 1/MEAN(1.0/X,1.0/Y) //调和平均数
正确的写法(每个变量都需要加括号,同时表达式也需要括起来,防止运算错误)
#define MEAN(X,Y) (((X)+(Y))/2) //平均数
#define HMMEAN(X,Y) (1/MEAN(1.0/(X),1.0/(Y))) //调和平均数
#include <stdio.h>
//测试调和平均数
int main()
{
int a = 1;
int b = 3;
printf("%.2f %.2f\n", MEAN(1.0/a, 1.0/b),HMMEAN(a,b));
printf("%.2f", HMMEAN(2, 4));
return 0;
}
题目的大意是编写极坐标转换直角坐标的函数。为了方便表示极坐标和直角坐标,编写极坐标和直角坐标的结构体,同时再写极坐标转换到直角坐标的函数。
#include <stdio.h>
#include <math.h>
#define DEG_PER_RAD (180/(acos(-1)))//1弧度对应多少角度
struct Polar_C //定义极坐标系
{
float angel;
float len;
};
struct Rect_C //定义直角坐标系
{
float x;
float y;
};
typedef struct Polar_C PolarC;
typedef struct Rect_C RectC;
void PolarToRect(RectC* pr,const PolarC* pp)
{
pr->x = cos((pp->angel) / DEG_PER_RAD) * (pp->len);
pr->y = sin((pp->angel) / DEG_PER_RAD) * (pp->len);
}
void ShowPolar(const PolarC* pp)
{
printf("The angel is %.2f° The length is %.2f.\n", pp->angel, pp->len);
}
void ShowRect(const RectC* pr)
{
printf("X %.2f Y %.2f.\n", pr->x, pr->y);
}
int main() //测试
{
PolarC polar = { 30,8 };
RectC rect;
ShowPolar(&polar);
PolarToRect(&rect, &polar);
ShowRect(&rect);
return 0;
}
4.ANSI库这样描述clock()函数的特性:
#include <time.h>
clock_t clock (void);
题目的大意是用clock()函数编写类似sleep()函数的功能。函数的参数是时间延迟的秒数,实现的功能是让程序暂停几秒。
#include <stdio.h>
#include <time.h>
//#define CLOCKS_PER_SEC 1000 //CLOCKS_PER_SEC实质是1000
void MySleep(double time)
{
clock_t start = clock();
while (1)
{
double past = ((double)clock() - (double)start) / CLOCKS_PER_SEC;
//printf("%.3f\n", past); //验证程序
if (past >= time)
break;
}
}
int main()
{
MySleep(10.0); //暂停10s
return 0;
}
题目的大意是实现从N个成员中,抽出n个不重复的元素出来,实现抽奖的效果。假设原本的数据源没有重复的,通过产生[0 - N)的随机索引值,来取成员,较为简单。因此难点是如何产生n个不重复的随机索引?
//N个元素的数组的索引随机值
int RandLimit(int up) //[0,up)随机数
{
return rand() % (up);
}
2. 产生n个不重复的随机值
如果要产生不重复的随机值,则需要记录产生的随机值,可以通过数组储存已产生的不同随机数。而且当我们使用随机数时,我们也可以通过该数组取用随机数。
因此编写产生n个不同的随机数时,我们要讲随机数存储在数组中,传入参数要包含数组名,随机数的个数和随机数的范围上限。
//rarr是随机数数组 n是随机数个数 up是随机数范围上限
void NoReRand(int* rarr, int n,int up) //产生n个无重复的随机数
{
for (int i = 0; i < n; i++)
{
again:
int randnum = RandLimit(up);
for (int j = 0; j < i; j++) //筛选有无重复值
{
if (rarr[j] == randnum) //如果有重复值,则重新生成随机数,重新筛选
goto again;
}
//没有重复值,才可以脱出for循环
rarr[i] = randnum; //筛选完毕后,填充到数组中
}
}
因为随机数的个数是动态的,是个变量,如果你的编译器支持变长数组,可以用变长数组,这里我用malloc函数实现变长数组的功能。我们产生10个随机数,随机整数范围为0-9,对上述函数进行测试
#include <stdlib.h>
#include <stdio.h>
void TestRand(int n, int up)
{
int* randarr = (int*)malloc(n * sizeof(int)); //储存产生的随机数,防止重复
NoReRand(randarr, n, up);
for (int i = 0; i < n; i++)
{
printf("%5d\n", randarr[i]);
}
free(randarr); //释放空间
}
int main()
{
for (int i = 0; i < 10; i++) //测试10次
{
TestRand(10, 10);
system("pause");
}
return 0;
}

可以看到,并没有相同的随机数产生。
接下来,就是抽奖的实现
为了实现动态的效果,在抽奖的过程,显示浮动的号码。通过上一题写的MySleep函数控制屏幕刷新时间,可以做到动态的效果(程序不足是,不知道如何实现按下一个键,使抽奖停止)。为了方便,数组的元素我只通过填充数字的方式,数组的元素可以用名字,电话号码填充,可以达到更好的抽奖效果。
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#define SIZE 200
//模拟随机抽奖
void MySleep(double time) //sleep函数
{
clock_t start = clock();
while (1)
{
double past = ((double)clock() - (double)start) / CLOCKS_PER_SEC;
//printf("%.3f\n", past); //验证程序
if (past >= time)
break;
}
}
void InitArr(int* pa, int n) //初始化数组
{
for (int i = 0; i < n; i++)
pa[i] = i+1;
}
int RandLimit(int up) //[0,up)随机数
{
return rand() % (up);
}
void NoReRand(int* rarr, int n,int up) //产生n个无重复的随机数
{
for (int i = 0; i < n; i++)
{
again:
int randnum = RandLimit(up);
for (int j = 0; j < i; j++) //筛选有无重复值
{
if (rarr[j] == randnum)
goto again;
}
//没有重复值,才可以脱出for循环
rarr[i] = randnum; //筛选完毕后,填充到数组中
}
}
void Lotto(int* arr,int sz,int n)
{
int* randarr = (int*)malloc(n * sizeof(int)); //储存产生的随机数,防止重复
NoReRand(randarr, n, sz);
for (int i = 0; i < n; i++)
{
printf("%7d\n", arr[randarr[i]]);
}
free(randarr); //释放空间
}
int main()
{
srand((unsigned int)time(NULL));
int arr[SIZE] = { 0 };
InitArr(arr, SIZE);
for (int i = 0; i < 1000; i++)
{
Lotto(arr, SIZE, 10);
MySleep(0.1);
system("cls");
}
return 0;
}
题目大意是使用stdlib的qsort函数对struct names元素进行快速排序。关键是编写比较函数,比较struct name的顺序。
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define NAME 15
struct name
{
char fname[15];
char lname[15];
};
typedef struct name name;
void ShowName(name* pn, int n)
{
for (int i = 0; i < n; i++)
{
printf("%s %s\n", pn[i].fname, pn[i].lname);
}
}
int comp(const void* p1, const void* p2) //编写比较函数,qsort的第四个参数
{
name* a = (const name*)p1;
name* b = (const name*)p2;
int cmp = strcmp(a->fname, b->fname); //先比较姓
if (cmp == 0) //如果姓相同,则比较名,返回1,0和-1
{
return strcmp(a->lname, b->lname);
}
else
return cmp;
}
int main()
{
name school[5] = { {"Jack","Brown"},{"Mike","Cui"},{"Cui","Xi"}, {"Xiao","Ming"},{"Hong","Bao"} };
ShowName(school, 5);
printf("\n");
qsort(school, 5, sizeof(name), comp); //说明-1为排列的顺序,从小到大
ShowName(school, 5);
return 0;
}
题目大意是编写两个函数,一个是输入函数,一个打印函数。第一个是变参函数,参数的数目不固定,将输入的参数存储到对应的数组中,并且返回数组地址。第二个函数是显示数组对应的内容(简单)。
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
void show_arr(const double ar[], int n);
double* new_d_arr(int n, ...);
int main()
{
double* p1 = NULL;
double* p2 = NULL;
p1 = new_d_arr(5, 1.2, 2.3, 3.4, 4.5, 5.6);
p2 = new_d_arr(4, 100.2, 20.3, 34.4, 42.5);
show_arr(p1, 5);
show_arr(p2, 4);
free(p1);
free(p2);
return 0;
}
void show_arr(const double arr[], int n)
{
for (int i = 0; i < n; i++)
{
printf("%.2f\n", arr[i]);
}
printf("\n\n");
}
double* new_d_arr(int n, ...)
{
double* pd = (double*)malloc(n * sizeof(double));
va_list ap; //创建变参列表,va_list实质是char*
va_start(ap, n); //变参列表的初始化
for (int i = 0; i < n; i++)
{
pd[i] = va_arg(ap, double); //取用列表中对应类型的元素
}
va_end(ap); //清理变参列表
return pd;
}
本文介绍C语言中预处理器的使用方法,宏定义的应用技巧,结构体与函数的设计,包括如何实现抽奖程序、变参函数及数组排序等功能。





