C Primer Plus--Chapter 16--The C Preprocessor and the C Library--10. 练习题

C Primer Plus--Chapter 16--The C Preprocessor and the C Library--10. 练习题

  • 1. Start developing a header file of preprocessor definitions that you want to use.
  • 2. The harmonic mean of two numbers is obtained by taking the inverses of the two numbers, averaging them, and taking the inverse of the result. Use a #define directive to define a macro “function” that performs this operation. Write a simple program that tests the macro.
  • 3. Polar coordinates describe a vector in terms of magnitude and the counterclockwise angle from the x-axis to the vector. Rectangular coordinates describe the same vector in terms of x and y components (see Figure 16.3). Write a program that reads the magnitude and angle (in degrees) of a vector and then displays the x and y components.
  • 4. The ANSI library features a clock() function with this description:
  • 5. Write a function that takes as arguments the name of an array of type int elements, the size of an array, and a value representing the number of picks. The function then should select the indicated number of items at random from the array and prints them. No array element is to be picked more than once. (This simulates picking lottery numbers or jury members.) Also, if your implementation has time() (discussed in Chapter 12) or a similar function available, use its output with srand() to initialize the rand() randomnumber generator. Write a simple program that tests the function.
  • 6. Modify Listing 16.17 so that it uses an array of struct names elements (as defined after the listing) instead of an array of double. Use fewer elements, and initialize the array explicitly to a suitable selection of names.
  • 7. Here’s a partial program using a variadic function:>

1. Start developing a header file of preprocessor definitions that you want to use.

#include
char *s_gets(char *s, int n);
void eatline(void);
int input(int min, int max);

2. The harmonic mean of two numbers is obtained by taking the inverses of the two numbers, averaging them, and taking the inverse of the result. Use a #define directive to define a macro “function” that performs this operation. Write a simple program that tests the macro.

#include
#define HMEAN(X, Y) ( 2.0 * (X) * (Y) / ((X) + (Y)))
int main(void)
{
  double x, y, ans;
  puts("Enter two numbers (nonumeric to quit):");
  while(scanf("%lf %lf",&x, &y) == 2 && getchar() == '\n')
  {
    ans = HMEAN(x,y);
    printf("%g = harmetic mean of %g and %g.\n",ans,x,y);
    puts("Next numbers:");
  }
  puts("Bye");
  return 0;
}

3. Polar coordinates describe a vector in terms of magnitude and the counterclockwise angle from the x-axis to the vector. Rectangular coordinates describe the same vector in terms of x and y components (see Figure 16.3). Write a program that reads the magnitude and angle (in degrees) of a vector and then displays the x and y components.

The relevant equations are these:
x = r cos A y = r sin A
To do the conversion, use a function that takes a structure containing the polar coordinates and returns a structure containing the rectangular coordinates (or use pointers to such structures, if you prefer).
C Primer Plus--Chapter 16--The C Preprocessor and the C Library--10. 练习题_第1张图片坐标转化时注意,cos()函数的参数是弧度值(C 库函数 double cos(double x) 返回弧度角 x 的余弦。)

#include
#include
struct polar
{
 double mag;
 double theta;
};
struct rect
{
  double x;
  double y;
};
struct rect p_to_r(const struct polar *p);
int main(void)
{
  struct polar input;
  struct rect output;
  printf("Please enter the magnitude and angle: ");
  while(scanf("%lf %lf", &input.mag, &input.theta) == 2 && input.mag >= 0 &&
  getchar() == '\n')
  {
    output = p_to_r(&input);
    printf("Polar coord: %g %f\n",input.mag, input.theta);
    printf("Rectangular coord: %g %g\n",output.x,output.y);
    printf("Enter magnitude and angle in degrees (nonumeric to quit): ");
  }
  puts("Bye");
  return 0;
}
struct rect p_to_r(const struct polar *p)
{
  struct rect out;
  double pi = 4 * atan(1);
  double deg_rad = pi / 180; 
  out.x = p->mag * cos(p->theta * deg_rad);
  out.y = p->mag * sin(p->theta * deg_rad);
  return out;
}

4. The ANSI library features a clock() function with this description:

#include
clock_t clock (void);

Here, clock_t is a type defined in time.h. The function returns the processor time, which is given in some implementation-dependent units. (If the processor time is unavailable or cannot be represented, the function returns a value of -1.) However,
CLOCKS_PER_SEC, also defined in time.h, is the number of processor time units per second. Therefore, dividing the difference between two return values of clock() by CLOCKS_PER_SEC gives you the number of seconds elapsed between the two calls.
Typecasting the values to double before division enables you to get fractions of a second.
Write a function that takes a double argument representing a desired time delay and then runs a loop until that amount of time has passed. Write a simple program that tests the function.

分析:
参考: C语言time.h中clock()函数的使用
clock_t 是长整型,clock() 返回的是程序执行到调用函数cpu时钟计时数,计时数除以 CLOCKS_PER_SEC (每秒计时单元数目)为时间(秒)。
要求是写一个延时函数。

#include
#include
void delay(double a);
double input_t(void);
int main(void)
{
  double time;
  printf("Enter the delay time (s): ");
  time = input_t();
  clock_t start = clock();
  delay(time);
  clock_t finish = clock();
  double times = (double)((finish - start)/CLOCKS_PER_SEC);
  printf("function delay runs %f seconds.\n",times);
  return 0;
}
double input_t(void)
{
  int status;
  int ok = 1;
  double n;
  while(ok)
  {
    status = scanf("%lf",&n);
    if(status != 1 || n <= 0 || getchar() != '\n' )
    {
      printf("Enter again (time greater than 0): ");
      while(getchar() != '\n')
      	   continue;
      continue;
    }
    else
    return n;
  }
}
void delay(double t)
{
  clock_t start = clock();
  double times = t * CLOCKS_PER_SEC;
  double d = 0;
  while((t - d) != 0) 
   d = ((double)clock() - start) / CLOCKS_PER_SEC;
}

5. Write a function that takes as arguments the name of an array of type int elements, the size of an array, and a value representing the number of picks. The function then should select the indicated number of items at random from the array and prints them. No array element is to be picked more than once. (This simulates picking lottery numbers or jury members.) Also, if your implementation has time() (discussed in Chapter 12) or a similar function available, use its output with srand() to initialize the rand() randomnumber generator. Write a simple program that tests the function.

程序分析:

  1. 利用随机数产生函数 rand() 产生随机数数组,用时间做种子使每次产生的随机数不同。
  2. 在数组中随即选取部分数据输出,已经选择的数据下次不能再输出。
#include
#include
#include
#include
#include
void init(int *a, int size);
int input(int min, int max);
char getlet(char *s);
void r_pick(int *a, int size, int num);
int main(void)
{
  int size, num;
  char c;
  printf("Please enter the total numbers: ");
  while(scanf("%d",&size) == 1 && getchar() == '\n' && size > 0)
  {
    int *ar = (int *)malloc(size * sizeof(int));
    init(ar, size);
    do
    {
      printf("Please enter the number of selected values (no more than %d): ",size);
      num = input(0, size);
      r_pick(ar, size, num);
      size -= num;
      printf("\nAgain? \n");
      c = getlet("yn");
    } while(c == 'y');
    free(ar);
    printf("\nPlease enter the next array number (nonumeric to quit): ");
  }
  puts("Bye");
  return 0;
}
void init(int *a, int size)
{
  srand((unsigned int) time(NULL));
  for(int i = 0; i < size; i++)
  {
   a[i] = rand();
   printf("%d ",a[i]);
   if((i+1) % 5 == 0)
   putchar('\n');
  }
  if(size % 5 != 0)
  putchar('\n');
}
int input(int min, int max)
{
  int status;
  long n;
  int ok = 1;
  while(ok)
  {
    status = scanf("%ld", &n);
    if(status != 1 || n < min || n > max || getchar() != '\n')
    {
      printf("Enter a number between %d to %d: ",min,max);
      while(getchar() != '\n')
      continue;
      continue;
    }
    else
    return (int)n;
  }
}
void r_pick(int *a, int size, int num)
{
  int index, temp; 
  srand((unsigned int) time(NULL));
  for(int i = 0; i < num; i++)
    {
     index = rand() % (size); //得到数值范围为 0 ~ size-1
     temp = a[index]; //随机选出的数组中的数
     printf("%d ", temp);
     if((i+1) % 5 == 0)
     printf("\n"); //每输出5个数换行
     a[index] = a[size-1];//将选出的数与最后一个数交换
     a[size-1] = temp;
     size--;
    }
    if(num % 5 != 0)
    putchar('\n');
}
char getlet(char *s)
{
  char c;
  int ok = 1;
  while(ok)
  {
    c = getchar();
    c = tolower(c);
    if(strchr(s,c) == NULL || getchar() != '\n')
    {
      printf("Enter again: ");
      while(getchar() != '\n')
      continue;
      continue;
    }
    else
    return c;
  }
}

6. Modify Listing 16.17 so that it uses an array of struct names elements (as defined after the listing) instead of an array of double. Use fewer elements, and initialize the array explicitly to a suitable selection of names.

程序实现以下功能:

  1. 从文件读取名字列表,如果文件不存在则创建数组并初始化为空,再通过用户输入名字列表。
  2. 对名字按字母从小到大顺序进行快速排序,先比较名,相同则比较列。
  3. 将排序好的列表存入文件中保存。
#include
#include
#include
#define N 10
#define LEN 40
typedef struct 
{
 char fname[20];
 char lname[20];
} name;
void eatline(void);
void init(name *staff, int n);
char *s_gets(char *s, int n);
void showname(name *staff, int n);
int mycomp(const void *p1, const void *p2);
int main(void)
{
 char filename[LEN];
 FILE *fp;
 name staff[N]; 
 size_t size = sizeof(name);
 printf("Enter the file name: ");
 s_gets(filename, N);
 if((fp = fopen(filename,"rb")) == NULL)
  {
   init(staff, N);
   printf("\nOriginal name list:\n");
  }
 else
 {
   int ok = 1;
   for(int i = 0; i < N, ok == 1; i++)
   ok = fread(&staff[i], size, 1, fp);
   fclose(fp);
 }
 showname(staff, N);
 qsort(staff, N, size, mycomp);
 printf("\nSorted name list:\n");
 showname(staff, N);
 if((fp = fopen(filename, "wb")) == NULL)
 {
  fprintf(stderr, "Can't open file %s.\n",filename);
  exit(EXIT_FAILURE);
 }
 for(int i = 0; i < N; i++)
 fwrite(&staff[i], size, 1, fp);
 fclose(fp);
 return 0;
}
void eatline(void)
{
 while(getchar() != '\n')
 continue;
}
void init(name *staff, int n)
{
int i;
int ok = 1;
for(i = 0; i < N; i++)
{
 strcpy(staff[i].fname,"");
 strcpy(staff[i].lname,"");
}
printf("Plese enter the name list (first name last name):\n");
for(i = 0; i < N, ok == 1; i++)
{
  ok = 0;
  printf("name %d:\n",i+1);
  if(s_gets(staff[i].fname, 20) && s_gets(staff[i].lname, 20) && staff[i].fname[0] != '\0'&& staff[i].lname[0]!='\0')
  ok = 1;  
}
if(staff[i-1].lname[0] == '\0' || staff[i-1].fname[0] == '\0')
{
 strcpy(staff[i-1].fname,"");
 strcpy(staff[i-1].lname,"");
}
}
char *s_gets(char *s,  int n)
{
 char *ret_val, *find;
 ret_val = fgets(s, n, stdin);
 if(ret_val)
 {
   find = strchr(s, ' ');
   if(find)
   {
     *find = '\0';
     eatline();
   }
   else
   {
     find = strchr(s, '\n');
     if(find)
     *find = '\0';
     else
     eatline();
   }
 }
 return ret_val;
}
void showname(name *staff, int n)
{
 for(int i = 0; i < n; i++)
  printf("%-10s %-10s\n",staff[i].fname, staff[i].lname);
}
int mycomp(const void *p1, const void *p2)
{
 const name *n1 = (const name *) p1;
 const name *n2 = (const name *) p2;
 int s = strcmp(n1->fname, n2->fname);
 if(s != 0)
 return s;
 else
 return strcmp(n1->lname, n2->lname);
}

结果:

Enter the file name: name.dat
Plese enter the name list (first name last name):
name 1:
fu
du
name 2:
bai
li
name 3:
yong
liu
name 4:
shi
su
name 5:
xun
su
name 6:
zhe
su
name 7:
zongyuan
zong
name 8:
juyi
bai
name 9:
qingzhao
li
name 10:
s


Original name list:
fu         du        
bai        li        
yong       liu       
shi        su        
xun        su        
zhe        su        
zongyuan   zong      
juyi       bai       
qingzhao   li        
                     

Sorted name list:
                     
bai        li        
fu         du        
juyi       bai       
qingzhao   li        
shi        su        
xun        su        
yong       liu       
zhe        su        
zongyuan   zong 

7. Here’s a partial program using a variadic function:>

#include
#include
#include
void show_array(const double ar[], int n);
double * new_d_array(int n, …);
int main()
{
double * p1;
double * p2;
p1 = new_d_array(5, 1.2, 2.3, 3.4, 4.5, 5.6);
p2 = new_d_array(4, 100.0, 20.00, 8.08, -1890.0);
show_array(p1, 5);
show_array(p2, 4);
free(p1);
free(p2);
return 0;
}

The new_d_array() function takes an int argument and a variable number of double arguments. The function returns a pointer to a block of memory allocated by malloc().
The int argument indicates the number of elements to be in the dynamic array, and the double values are used to initialize the elements, with the first value being assigned to the first element, and so on. Complete the program by providing the code for show_
array() and new_d_array().

考察:可变参数

#include
#include
#include
double *new_d_array(int n, ...);
void show_array(const double ar[], int n);
int main(void)
{
  double *p1, *p2;
  p1 = new_d_array(5, 1.2, 2.3, 3.4, 4.5, 5.6);
  p2 = new_d_array(4, 100.0, 20.0, 8.08, -1890.0);
  show_array(p1, 5);
  show_array(p2, 4);
  free(p1);
  free(p2);
  return 0;
}
double *new_d_array(int n, ...)
{
  va_list ap;
  int i;
  double *p;
  va_start(ap, n);
  p = (double *) malloc(n * sizeof(double));
  for(i = 0; i < n; i++)
  p[i] = va_arg(ap, double);
  va_end(ap);
  return p;
}
void show_array(const double *a, int n)
{
  for(int i = 0; i < n; i++)
  printf("%g ",a[i]);
  putchar('\n');
}

你可能感兴趣的:(C,Primer,Plus)