《C Primer Plus》手记二

本贴最后更新于 729 天前,其中的信息可能已经沧海桑田

手记一

11.文件

// 标准文件
// C会自动打开三个文件 standard input 标准输入 standard output 标准输出 standard
// error output 标准错误输出 standard input  通常为键盘 standard output
// 通常为显示器 通常标准输入为程序提供输入 getchar() scanf() 标准输出
// putchar(),puts(),printf()

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[]) {
  // 读取文件时存储每个字符
  int ch;
  // 文件指针
  FILE *fp;
  // 记录文件行数
  unsigned long count = 0;
  // 效验传入参数
  if (argc == 0) {
    printf("Usage: %s filename\n", argv[0]);
    exit(EXIT_FAILURE);
  }
  // 效验是否有文件,如果没有,指针就指不上
  if ((fp = fopen(argv[1], "r")) == NULL) {
    printf("Can't Open %s \n", *(argv + 1));
  }
  //循环读 char
  while ((ch = getc(fp)) != EOF) {
    // 输出char
    putc(ch, stdout);
    count++;
  }
  // 关闭文件
  fclose(fp);
  printf("File %s has %lu characters \n", *(argv + 1), count);
  return 0;
}

// 打开方式 fopen 第二个参数
// r 读模式打开
// w 写模式打开,文件不存在则创建一个新的文件
// a 写模式打开,把现有的文件长度截为0,不存在则创建一个新文件
// r+ 更新模式打开,r+w
// w+ 更新模式打开文件,如果文件存在则将其长度截为0,不存在则新建一个文件
// a+ 更新模式打开文件 可以读整个文件但只能在末尾添加内容
// rb 读模式打开二进制
// wb 写模式打开二进制
// x
// rwax 和 b进行组合
File file1.c has 1533 characters

getc() 和 putc()
getc() - getchar()
putc() - putchar()
不同点在于要告诉 getc 和 putc 函数使用哪一个文件,

//从标准输入中获取一个字符
ch = getchar();
// 从fp指向的文件中获取一个字符
ch = getc(fp);
// 把ch放入fpout指向的文件中
putc(ch,fpout);

指向标准文件的指针

标准输入 stdin 键盘
标准输出 stdout 显示器
标准错误 stderr 显示器
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define LEN 40

int main(int argc, char *argv[]) {
  FILE *in, *out;
  int ch;
  char name[LEN];
  int count = 0;

  // 效验参数
  if (argc < 2) {
    fprintf(stderr, "Usage %s filename\n", *argv);
    exit(EXIT_FAILURE);
  }

  // 设置输入
  if ((in = fopen(*(argv + 1), "r")) == NULL) {
    fprintf(stderr, "I couldn't open the file %s \n", *(argv + 1));
    exit(EXIT_FAILURE);
  }

  // 设置输出
  // 拷贝字符串,把第二个参数 拼接到name上,长度-5为后缀名留空间.注意\0结束符
  strncpy(name, *(argv + 1), LEN - 5);
  // 为文件添加后缀名
  strcat(name, ".red");
  // 以write方式打开文件
  if ((out = fopen(name, "w")) == NULL) {
    fprintf(stderr, "Cant't create output file\n");
    exit(3);
  }
  while ((ch = getc(in)) != EOF) {
    if (count++ % 3 == 0) {
      putc(ch, out);
    }
  }
  if (fclose(in) != 0 || fclose(out) != 0) {
    fprintf(stderr, "Error in closing files\n");
  }
  return 0;
}

单词本,区分 scanf fscanf,printf,fprintf ,带 f 的需要传指针

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX 41
int main() {

  FILE *p;
  char words[MAX];

  if ((p = fopen("wordbook", "a+")) == NULL) {
    fprintf(stdout, "OH NO YOU CANT CREATE THE FILE");
    exit(EXIT_FAILURE);
  }

  puts("Enter a word to add to the file;press the \"#\"");
  // fscanf 标准输入,从键盘读取,所以不需要参数啥的
  while ((fscanf(stdin, "%40s", words)) == 1 && *words != '#') {
    // 标准输出,把
    fprintf(p, "%s\n", words);
  }

  puts("File contents:\n");
  // 返回到文件开始处
  // p指向了文件头,所以打印出来是所有的
  rewind(p);
  while (fscanf(p, "%s", words) == 1)
    puts(words);
  puts("DONE");
  if(fclose(p)!=0){
    fprintf(stderr,"CANT CLOSE");
  }
}

倒序输出,主要函数 fseek(),ftell()

#include <stdio.h>
#include <stdlib.h>
#define CNTL_Z EOF
#define SLEN 40

int main(void) {
  char file[SLEN];
  char ch;
  FILE *fp;

  long count, last;

  puts("Enter the name of the file to be processed:");
  scanf("%80s", file);
  if ((fp = fopen(file, "rb")) == NULL) {
    fprintf(stderr, "Error the file is NULL");
    exit(EXIT_FAILURE);
  }

  // 定位到文件结尾
  fseek(fp, 0L, SEEK_END);
  // 获取指针位置
  last = ftell(fp);

  for (count = 1L; count <= last; count++) {
    // 回退,count为偏移量,SEEK_END - count 的位置
    fseek(fp, -count, SEEK_END);
    ch = getc(fp);
    if (ch != EOF) {
      putchar(ch);
    }
  }
  putchar('\n');
  fclose(fp);
}

SEEK_SET 文件开始处
SEEK_CUR 当前位置
SEEK_END 文件末尾

其他函数

// 把c指定的字符放回输入流中,如果把字符串放回输入流,下一次读取的时候顺序是相反的
int ungetc(int c, FILE *fp);
// 输出缓冲区所有的为写入数据发送到fp指定的输出文件
int fflush(FILE *fp);
//创建缓冲区存储流,fp:待处理的流,buf缓冲区,size:数组大小,mode:_IOFBF完全缓冲,IOLBF行缓冲,_IONBF无缓冲,操作成功返回0
int setvbuf(FILE *fp,char * restrict buf,int mode,size_t size);
// 处理文本信息,如果处理double类型数据,则会损失精度
fprintf()
// fread fwrite 用来处理二进制形式数据
// 把二进制数据写入文件,ptr:待写入数据块的地址,size为数据块儿大小,nmemb:待写入数据块儿的数量,fp:要写入的文件
size_t fwrite(const void * restrict ptr,size_t size,size_t nmemb,FILE * restrict fp);
// 保存一个大小为256字节的数据对象
char buffer[256];
fwrite(buffer,256,1,fp);
//保存一个内含10个double类型的数据
double earnings[10];
fwrite(earnings,sizeof(double),10,fp);
//fread
size_t fread(void * restrict ptr,size_t size,size_t nememb,FILE * restrict fp);
//恢复上述保存数据,这里fp是output不input
double earnings[10];
fread(earnings,sizeof(double),10,fp);
/*append*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define BUFSIZE 4096
#define SLEN 81
void append(FILE *source, FILE *dest);
char *s_gets(char *st, int n);

// 接收一个源指针一个目标指针
void append(FILE *source, FILE *dest) {
  size_t bytes;
  static char temp[BUFSIZE];
  // 一直到拷贝的字节数小与0
  // fread() 把source二进制数据写入temp,temp中的一块内存占一个char的大小,整块儿大小为4096bytes
  while ((bytes = fread(temp, sizeof(char), BUFSIZE, source)) > 0) {
    // 在把temp中存入的东西写入到dest中
    fwrite(temp, sizeof(char), bytes, dest);
  }
}

char *s_gets(char *st, int n) {
  char *ret_val;
  char *find;
  ret_val = fgets(st, n, stdin);
  if (ret_val) {
    find = strchr(st, '\n');
    if (find) {
      *find = '\0';
    } else {
      while (getchar() != '\n') {
        continue;
      }
    }
  }
  return ret_val;
}

int main(void) {
  // fa指向目标文件,fs指向源文件
  FILE *fa;
  FILE *fs;
  // 附加的文件数量
  int files = 0;
  // 目标文件名称
  char file_app[SLEN];
  // 源文件名称
  char file_src[SLEN];
  int ch;

  puts("Enter name of destination file:");
  //获取目标文件名称
  s_gets(file_app, SLEN);
  // 以a模式打开文件,如果指针为空
  if ((fa = fopen(file_app, "a+")) == NULL) {
    // 没有这个文件/不能打开这个文件
    fprintf(stderr, "Can't open %s\n", file_app);
    // 退出程序
    exit(EXIT_FAILURE);
  }
  // 如果验证通过证明有文件
  // 创建一个4096bytes的缓冲区->全缓冲:对于输出,数据在缓冲填满时被一次性写入。对于输入,缓冲会在请求输入且缓冲为空时被填充。
  // 如果setvbuf无法创建缓冲区,返回一个非零值
  // fa指针指向该缓冲区
  if (setvbuf(fa, NULL, _IOFBF, BUFSIZE) != 0) {
    // 不能创建缓冲区
    fputs("Can't create output buffer\n", stderr);
    //退出
    exit(EXIT_FAILURE);
  }
  puts("Enter name of first source file");
  //循环获取 file_src源文件名称,并以 空'\0'字符进行判断,是否结束
  while (s_gets(file_src, SLEN) && file_src[0] != '\0') {
    //对比源文件名称是否与目标文件名称一致,避免进入死循环
    if (strcmp(file_src, file_app) == 0) {
      fputs("Can't append file to itself\n", stderr);
    } else if ((fs = fopen(file_src, "r")) == NULL) {
      fprintf(stderr, "Can't open %s\n", file_src);
    } else {
      // 创建缓冲区 无缓冲:不使用缓冲。每个 I/O 操作都被即时写入。buffer 和 size 参数被忽略。
      // fs指向该缓冲区
      if (setvbuf(fs, NULL, _IONBF, BUFSIZE) != 0) {
        fputs("Can't append file to buffer\n", stderr);
        continue;
      }
    }
    // 将两个指针传入 append函数
    append(fs, fa);
    if (ferror(fs) != 0) {
      fprintf(stderr, "Error in reading file %s\n", file_src);
    }
    if (ferror(fa) != 0) {
      fprintf(stderr, "error in writing file %s\n", file_app);
    }
    // 关闭流
    fclose(fs);
    // 文件数自增
    files++;
    printf("File %s appended.\n", file_src);
    puts("Next file");
  }
  printf("Done appending,%d files appended", files);
  // 指针指回文件开头
  rewind(fa);
  printf("%s contens:\n", file_app);
  // 输入出文件
  while ((ch = getc(fa)) != EOF) {
    putchar(ch);
  }
  puts("Done dispalying");
  // 关闭流
  fclose(fa);
  return 0;
}

随机访问

/* 使用二进制I/O进行随机访问 */
#include <stdio.h>
#include <stdlib.h>

#define ARSIZE 1000

int main() {
  double numbers[ARSIZE];
  double value;
  const char *file = "numbers.dat";
  int i;
  long pos;
  FILE *iofile;

  for (i = 0; i < ARSIZE; i++) {
    numbers[i] = 100.0 * i + 1.0 / (i + 1);
  }
  if ((iofile = fopen(file, "wb")) == NULL) {
    fprintf(stderr, "Could not open %s for output. \n", file);
    exit(EXIT_FAILURE);
  }

  fwrite(numbers, sizeof(double), ARSIZE, iofile);
  fclose(iofile);

  if ((iofile = fopen(file, "rb")) == NULL) {
    fprintf(stderr, "Could not open %s for random access.\n", file);
    exit(EXIT_FAILURE);
  }

  // 一共1000个位置,最后一位是\0,所以是0-999
  printf("Enter an index in the range 0-%d.\n", ARSIZE - 1);

  while (scanf("%d", &i) == 1 && i >= 0 && i < ARSIZE) {
    //计算指针偏移量
    pos = (long)i * sizeof(double);
    // 定位
    fseek(iofile, pos, SEEK_SET);
    // 读取iofile,到value中
    fread(&value, sizeof(double), 1, iofile);
    printf("The value there is %f \n", value);
    printf("Next index (out of range to quit):\n");
  }
  flose(iofile);
  puts("Bye!");
  return 0;
}

小结

1.fopen()函数为标准IO打开一个文件,并创建一个用于存储文件和缓冲功能区信息的结构.并返回指向该结构的指针.

2.C把输入视为字节流

3.fread(),getc(),fgets()把每个字节看作是字符码

4.fscanf和scanf把字符码翻译并转换说明指定的其他类型

5.fwrite将二进制直接放入输出流

6.ANSIC 提供 二进制/文本文件打开方式,二进制可以逐字节读取文件.文本会把文件内容从文本的系统表示法应设为C的表示法.

7.通常 输入函数 getc(),fgets(),fscanf(),fread()都从文件开始处按顺序读取文件

8.fseek和ftell让程序可以随机访问文件中的任意位置,fgetpos()和fsetpos()把类似的功能扩展至更大的文件.

12.结构和其他数据形式

关键字:struct,union,typedef
运算符: . , ->

// book.c
//

#include <stdio.h>
#include <string.h>

char *s_gets(char *st, int n);

// 书名的最大长度+1 有空字符 \0
#define MAXTITL 41
// 作者姓名的最大长度
#define MAXAUTL 31
// 创建类
struct book {
  char title[MAXTITL];
  char author[MAXAUTL];
  float value;
};

int main(void) {
  // 把libaray声明为book类型的变量
  struct book library;
  printf("Please enter the book title.\n");
  s_gets(library.title, MAXTITL);
  printf("Now enter the author.\n");
  s_gets(library.author, MAXAUTL);
  printf("Now enter the value.\n");
  scanf("%f", &library.value);
  printf("%s by %s:$%2.f\n", library.title, library.author, library.value);
  return 0;
};

char *s_gets(char *st, int n) {
  char *ret_val;
  char *find;
  ret_val = fgets(st, n, stdin);
  if (ret_val) {
    find = strchr(st, '\n');
    if (find) {
      *find = '\0';
    } else {
      while (getchar() != '\n') {
        continue;
      }
    }
  }
  return ret_val;
}
#include <stdio.h>
#include <string.h>
#define MAXTITL 40
#define MAXAUTL 40
#define MAXBOOKS 100
char *s_gets(char *st, int n);

struct book {
  char title[MAXTITL];
  char author[MAXAUTL];
  float value;
};

int main(void) {
  // 结构数组
  struct book library[MAXBOOKS];

  int count = 0;
  int index;

  printf("Please enter the book title.\n");
  printf("Press [enter] at the start of a line to stop.\n");

  while (count < MAXBOOKS && s_gets(library[count].title, MAXTITL) != NULL &&
         library[count].title[0] != '\0') {
    printf("Now enter the author.\n");
    s_gets(library[count].author, MAXAUTL);
    printf("Now enter the value.\n");
    scanf("%f", &library[count++].value);
    while (getchar() != '\n') {
      continue;
    }
    if (count < MAXBOOKS) {
      printf("Enter the next title.\n");
    }
  }
  if (count > 0) {
    printf("Here is the list of your books:\n");
    for (index = 0; index < count; index++) {
      printf("%s by %s $ %.2f\n", library[index].title, library[index].author,
             library[index].value);
    }
  } else {
    printf("No books?Toobad .\n");
  }
  return 0;
}

char *s_gets(char *st, int n) {
  char *ret_val;
  char *find;
  ret_val = fgets(st, n, stdin);
  if (ret_val) {
    find = strchr(st, '\n');
    if (find)
      *find = '\0';
    else
      while (getchar() != '\n')
        continue;
  }
  return ret_val;
}

结构体

/**
 * @author :ferried
 * @time: 2019-12-4 17:27
 * @number: 14.4
 * @name: friends
 **/
#include <stdio.h>
#define LEN 20

struct names {
  char first[LEN];
  char last[LEN];
};

struct guy {
  struct names handle;
  char favfood[LEN];
  char job[LEN];
  float income;
};

int main(void) {
  struct guy fellow[2] = {
      {{"Ewen", "Villard"}, "grilled salmon", "personality coach", 68112.00},
      {{"a", "b"}, "c", "d", 1.00},
  };
  // 创建一个结构体指针
  struct guy *him;
  printf("address #1: %p #2: %p\n", &fellow[0], &fellow[1]);
  // 将结构体数组的首地址 给 him指针
  him = fellow;
  // him+1 是结构体数组的第二个元素
  printf("pointer #1: %p #2: %p\n",him,him+1);
  // -> 是结构体指针 的 .
  printf("him -> income is $%.2f. (*hime).income is $%.2f",him->income,(*him).income);
  printf("him -> favfood is %s: hime-> handle.last is %s\n",him->favfood,(him->handle).last) ;
  return 0;
}
/**
 * @author :ferried
 * @time: 2019-12-4 17:27
 * @number: 14.5
 * @name: funds1.c
 * @desc 结构传参
 **/

#include <stdio.h>
#define FUNDLEN 50

struct funds {
  char bank[FUNDLEN];
  double bankfund;
  char save[FUNDLEN];
  double savefund;
};

double sum(double, double);

int main(void) {
  struct funds stan = {"Garlic-Melon Bank", 4032.27,
                       "Lucky's Saveings and loan", 8543.94};

  printf("Stan has a total of $%.2f\n", sum(stan.bankfund, stan.savefund));
}

double sum(double i, double j) { return i + j; }
/**
 * @author :ferried
 * @time: 2019-12-4 17:27
 * @number: 14.5
 * @name: funds1.c
 * @desc 结构地址传参
 **/

#include <stdio.h>
#define FUNDLEN 50

struct funds {
  char bank[FUNDLEN];
  double bankfund;
  char save[FUNDLEN];
  double savefund;
};

// 参数为一个指针
double sum(const struct funds *);

int main(void) {
  struct funds stan = {"Garlic-Melon Bank", 4032.27,
                       "Lucky's Saveings and loan", 8543.94};

  printf("Stan has a total of $%.2f.\n", sum(&stan));
  return 0;
}

double sum(const struct funds *stan) { return stan->bankfund + stan->savefund; }

结构体传参

#include <stdio.h>
#include <string.h>

#define NLEN 30

struct namect {
  char fname[NLEN];
  char lname[NLEN];
  int letters;
};

void getinfo(struct namect *);
void makeinfo(struct namect *);
void showinfo(const struct namect *);
char *s_gets(char *st, int n);

int main(void) {
  struct namect person;
  getinfo(&person);
  makeinfo(&person);
  showinfo(&person);
  return 0;
}

void getinfo(struct namect *pst) {
  printf("Please enter your first name.\n");
  s_gets(pst->fname, NLEN);
  printf("Please enter your last name.\n");
  s_gets(pst->lname, NLEN);
}

void makeinfo(struct namect *pst) {
  pst->letters = strlen(pst->fname) + strlen((*pst).lname);
}

void showinfo(const struct namect *ppp) {
  printf("%s %s,your name contains %d letters.\n", ppp->fname, ppp->lname,ppp->letters);
}

char *s_gets(char *st, int n) {
  char *ret_val;
  char *find;
  ret_val = fgets(st, n, stdin);
  if (ret_val) {
    find = strchr(st, '\n');
    if (find) {
      *find = '\0';
    } else {
      while (getchar() != '\n') {
        continue;
      }
    }
  }
  return ret_val;
}

复合结构字面量

#include <stdio.h>
#define MAXTITL 41
#define MAXAUTL 31

struct book {
  char title[MAXTITL];
  char author[MAXAUTL];
  float value;
};

int main(void) {
  struct book readfirst;
  int score;

  printf("Enter test score");
  scanf("%d", &score);
  if (score >= 84) {
    // 复合结构字面量
    readfirst =
        (struct book){"Crime and Punishment", "Fyodor Dostoyevsky", 11.25};
  } else {
    readfirst = (struct book){"Mr.Bouncy's Nice Hat", "Fred Winsome", 5.99};
  }

  printf("Your assigned reading: \n");
  printf("%s by %s:$%.2f\n", readfirst.title, readfirst.author, readfirst.value);
  return 0;
}

结构体伸缩长度

/**
 * @author :ferried
 * @time: 2019-12-4 17:27
 * @number: 14.12
 * @name: flexmemb
 * @desc 伸缩性数组成员
 **/

#include <stdio.h>
#include <stdlib.h>

struct flex {
  int count;
  double average;
  double scores[];
};

void showFlex(const struct flex *p);

int main(void) {
  struct flex *pf1, *pf2;
  int n = 5;
  int i;
  int tot = 0;

  //为结构和数组分配空间
  pf1 = malloc(sizeof(struct flex) + n * sizeof(double));
  pf1->count = n;

  for (i = 0; i < n; i++) {
    pf1->scores[i] = 20.0 - i;
    tot += pf1->scores[i];
  };

  pf1->average = tot / n;
  showFlex(pf1);

  n = 9;
  tot = 0;
  pf2 = malloc(sizeof(struct flex) + n * sizeof(double));
  pf2->count = n;
  for (i = 0; i < n; i++) {
    pf2->scores[i] = 20.0 - i / 2.0;
    tot += pf2->scores[i];
  }
  pf2->average = tot / n;
  showFlex(pf2);
  free(pf1);
  free(pf2);
  return 0;
}

void showFlex(const struct flex *p) {
  int i;
  printf("Scores: ");
  for (i = 0; i < p->count; i++) {
    printf("%g,", p->scores[i]);
  }
  printf("\nAverage:%g\n", p->average);
}

保存结构体到文件中

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXTITL 40
#define MAXAUTL 40
#define MAXBKS 10

char *s_gets(char *st, int n);
struct book {
  char title[MAXTITL];
  char author[MAXAUTL];
  float value;
};

int main(void) {
  // 结构数组
  struct book library[MAXBKS];
  int count = 0;
  int index, filecount;
  // 文件指针
  FILE *pbooks;
  // 获取 book 结构体的 长度
  int size = sizeof(struct book);
  // 文件指针指向 book.dat,append 和 二进制模式
  if ((pbooks = fopen("book.dat", "a+b")) == NULL) {
    fputs("Can't open book.dat file\n", stderr);
    exit(1);
  }
  // 定位到文件开始
  rewind(pbooks);
  // 如果count 小于 最大books数量,每个元素为一个book结构体的长度,每次读一个结构体,输入指针为pbooks
  while (count < MAXBKS && fread(&library[count], size, 1, pbooks) == 1) {
    if (count == 0) {
      puts("Current contents of book.dat:");
      printf("%s by %s: $%.2f\n", library[count].title, library[count].author,library[count].value);
      count++;
    }
  }

  filecount = count;
  // 如果count达到结构体数组容纳上限
  if (count == MAXBKS) {
    fputs("The book.dat file is full.", stderr);
    exit(2);
  }

  puts("Please add new book titles.");
  puts("Press [enter] at the start of a line to stop.");
  while (count < MAXBKS && s_gets(library[count].title, MAXTITL) != NULL &&
         library[count].title[0] != '\0') {
    puts("Now enter the author");
    s_gets(library[count].author, MAXAUTL);
    puts("Now enter the value.");
    scanf("%f", &library[count++].value);
    while (getchar() != '\n') {
      continue;
    }
    if (count < MAXBKS) {
      puts("Enter the next title.");
    }
    if (count > 0) {
      puts("Here is the list of your books:");
      for (index = 0; index < count; index++) {
        printf("%s by %s: $%.2f\n", library[index].title, library[index].author,
               library[index].value);
        fwrite(&library[filecount], size, count - filecount, pbooks);
      }
    } else {
      puts("No books?Toobad.\n");
    }
  }
};

char *s_gets(char *st, int n) {
  char *ret_val;
  char *find;
  ret_val = fgets(st, n, stdin);
  if (ret_val) {
    find = strchr(st, '\n');
    if (find) {
      *find = '\0';
    } else {
      while (getchar() != '\n') {
        continue;
      }
    }
  }
  return ret_val;
}

枚举

enum levels {low = 100,medium = 500,high = 2000};
// cat = 1 lynx = 10 puma = 11 tiger = 12
enum feline {cat , lynx = 10,puma,tiger};
#include <stdbool.h>
#include <stdio.h>
#include <string.h>

#define LEN 30

char *s_gets(char *st, int n);
enum spectrum { red, orange, yellow, green, blue, violet };
const char *colors[] = {"red", "orange", "yellow", "green", "blue", "violet"};

int main(void) {
  char choice[LEN];
  enum spectrum color;
  bool color_is_found = false;

  puts("Enter a color (empty line to quit):");
  while (s_gets(choice, LEN) != NULL && choice[0] != '\0') {
    for (color = red; color < violet; color++) {
      if (strcmp(choice, colors[color]) == 0) {
        color_is_found = true;
        break;
      }
    }
    if (color_is_found) {
      switch (color) {
      case red:
        puts("Roses are red.");
        break;
      case orange:
        puts("Poppies are orange.");
        break;
      case yellow:
        puts("Sunflowers are yellow.");
        break;
      case green:
        puts("Grass is green.");
        break;
      case blue:
        puts("Bluebells are blue.");
        break;
      case violet:
        puts("Violets are violet.");
        break;
      }
    }
  }
  return 0;
}

char *s_gets(char *st, int n) {
  char *ret_val;
  char *find;

  ret_val = fgets(st, n, stdin);
  if (ret_val) {
    find = strchr(st, '\n');
    if (find) {
      *find = '\0';
    }
    else{
      while(getchar()!='\n')
        continue;
    }
  }
  return ret_val;
}

指针指向函数

#include <ctype.h>
#include <stdio.h>
#include <string.h>
#define LEN 81
// 获取输入
char *s_gets(char *st, int n);
// 展示菜单
char showmenu(void);
// 清除行
void eatline(void);
// 操作输入结果并展示,第一个参数为一个指向void函数的指针*fp,参数是一个
// 指向char类型的指针 二参为一个指向char类型的指针
void show(void (*fp)(char *), char *str);
// 大写
void ToUpper(char *);
// 小写
void ToLower(char *);
// 反转
void Transponse(char *);
// 不操作
void Dummy(char *);

int main(void) {
  // 初始化两个数组和一个字符
  char line[LEN];
  char copy[LEN];
  char choice;
  // 初始化一个指向 void类型并携带指针参数的函数的指针 pfun
  void (*pfun)(char *);

  puts("Enter a string (empty to quit):");
  while (s_gets(line, LEN) != NULL && line[0] != '\0') {
    // 循环获取输入,一遍展示菜单一边输入
    while ((choice = showmenu()) != 'n') {
      switch (choice) {
        // 按照不同的输入将pfun去指向不同的函数
      case 'u':
        pfun = ToUpper;
        break;
      case 'l':
        pfun = ToLower;
        break;
      case 't':
        pfun = Transponse;
        break;
      case 'o':
        pfun = Dummy;
        break;
      }
      // 拷贝
      strcpy(copy, line);
      // 根据所选不同的函数来进行不同操作
      show(pfun, copy);
    }
  }
}

char showmenu(void) {
  char ans;
  puts("Enter menu choice:");
  puts("u) uppercase  l)lowercase");
  puts("t) transposed case  o)original case");
  puts("n)  next string");
  // 从标准输入中获取一个字符
  ans = getchar();
  // 将字符小写
  ans = tolower(ans);
  // 清理输入行
  eatline();
  // 如果字符不在ulton中
  while (strchr("ulton", ans) == NULL) {
    // 重新提示
    puts("Please enter a menu item:");
    // 重新输入
    ans = tolower(getchar());
    // 清理行
    eatline();
  }
  return ans;
}

void eatline(void) {
  while (getchar() != '\n')
    continue;
}

void ToUpper(char *str) {
  while (*str) {
    *str = toupper(*str);
    str++;
  }
}

void ToLower(char *str) {
  while (*str) {
    *str = tolower(*str);
    str++;
  }
}

void Transponse(char *str) {
  while (*str) {
    if (islower(*str)) {
      *str = toupper(*str);
    }
    if (isupper(*str))
      *str = tolower(*str);
    str++;
  }
}

void Dummy(char *str) { *str = *str; }

void show(void (*fp)(char *), char *str) {
  (*fp)(str);
  puts(str);
}

char *s_gets(char *st, int n) {
  char *ret_val;
  char *find;
  ret_val = fgets(st, n, stdin);
  if (ret_val) {
    find = strchr(st, '\n');
    if (find) {
      *find = '\0';
    } else {
      while (getchar() != '\n') {
        continue;
      }
    }
  }
  return ret_val;
}
  • C

    C 语言是一门通用计算机编程语言,应用广泛。C 语言的设计目标是提供一种能以简易的方式编译、处理低级存储器、产生少量的机器码以及不需要任何运行环境支持便能运行的编程语言。

    62 引用 • 163 回帖 • 364 关注

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...