wujr5 / c-and-cpp-language-learning

C和C++编程语言学习 - 2015级
67 stars 34 forks source link

软件:week1 代码风格检查 #1

Open wujr5 opened 8 years ago

wujr5 commented 8 years ago

week1 代码风格检查

唠叨几句:

大家叫师兄就好了,不要叫老师,听着别扭=_=。

上了实验课或者上了理论课,可能比较多的同学会有这样的想法:学了这些到底有什么用?好像觉得就只是敲几行不知道在干嘛的代码,输出一些不知道干嘛的结果。非常无聊。

对于这个问题,我还真不知道怎么回答。因为我大一的时候也是这样想的。其实软件工程专业,c语言是非常基础的一门语言,很多计算机类专业都以c语言作为入门语言。作为初学者,最重要的是对语言本身语法的了解和认识,算法的话,学有余力可以深究,这门课不会对算法有过高的要求。

我觉得现在同学们coding最大的动力来源于学业要求和把题目做对的成就感吧。在我们学校,你能真正利用编程做出产品或者有趣的东西,可能要到大二,那个时候你可能真的要迷恋上编程了。现在的话,我建议是,加油吧,好好学~慢慢的你会发现其实敲代码挺有意思的。

一、本周情况小结

第一周要求很低。基本上是熟悉练习系统Sicily,还有编辑器DevCpp的使用。对于这两个要求,我相信不会有什么问题。问题集中出现在同学们对c语言语法的理解上面。

下面列出出现频率较高的错误。

Sicily系统没有在编程风格上作要求,只要你的代码能运行,输入输出没问题,就可能可以通过。但是这样会写出可能可读性很差的代码。因此我们TA强烈要求同学们一定要注意自己的代码编写的风格。

下面介绍一个工具的使用来进行代码风格检查。

步骤1:安装python

教程:安装python

要注意的是,教程中说的系统变量就是python的安装路径。

步骤2:检查python是否安装成功

  1. 打开命令行窗口(win键+R;输入cmd;回车)如下:
  2. 如果安装成功,在命令行窗口输入python将会出现以下的输出:

    步骤3:下载cpplint.py

点击下载cpplint.py

步骤4:代码风格检查

  1. cpplint.py文件复制到你的程序代码所在的目录。比如:
  2. 打开命令行窗口,方法就是步骤2的第一点。导航到代码所在目录。

    cd命令的含义是打开目录,dir命令的含义是查看该目录下地文件和文件夹

  3. 运行命令

    python cpplint.py --filter=-whitespace/tab filename.c

    注意finename.c是你的源代码的文件名

    然后就会有如下的输出:

    注意错误,如test.c:7: Line ends in whitespace. Consider deleting these extra spaces. [whitespace/end_of_line] [4]test.c指的是文件名,7指的是行号,后面的 Line ends in whitespace. Consider deleting these extra spaces. [whitespace/ end_of_line] [4]指的是代码中出现的错误。

    步骤5:根据输出的改善代码

根据输出的错误,逐行改进代码。直到错误数目为0。如Total errors found: 0

步骤6:提交到Sicily

把通过google style的cpplint.py测试的代码,也就是Total errors found: 0,再把代码提交到Sicily。

总结

进行google style风格检测的目的是让同学们写出可读性良好的代码。按照上面的流程编写代码,能帮助你养成良好的编程习惯。希望同学们重视。

有任何问题欢迎评论。我们会持续改进。

参考

  1. cmd命令行大全
  2. google style guide
  3. cpplint
wujr5 commented 8 years ago

第一周的知识挺简单的,如果有同学觉得很难听懂,花了大量时间还是搞不定的话,最好及时请教同学或者TA。不然后面的学习会很吃力,因为后面要学的知识都是以前面的知识为基础的。

ghostbody commented 8 years ago

为什么要检查代码风格

到底为什么要用这么复杂的方法来检查代码风格?

大家看看这两段代码:

这是第一段c程序

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "Global.h"
#include "Catalog.h"
#include "Json.h"
#include "Serializer.h"
#include "Find.h"

int comp(const void*a,const void*b) {
  return (*(file_position **)a)->id - (*(file_position **)b)->id;
}

/* commands for the project
   -h : help
   -i <file> : insert file
   -cc : checkout the catalog
   -f <A> = <B> : find <key, value>
 */

const char * command[] = {
  "-h","-i","-cc","-f"
};

void help() {
  printf("usage:\n");
  printf("-h : help\n");
  printf("-i <file> : insert file\n");
  printf("-cc : checkout the catalog\n");
  printf("-f <A> = <B> : find <key,value>\n");
  printf("\n");
}

void CheckoutCatolog() {
  catalog_record * CATALOG = NULL;
  if(!catalog_build(&CATALOG)) {
    printf("CheckoutCatolog : CATALOG LOADED FAILED!\n");
    return;
  }

  if(CATALOG == NULL) {
    printf("CheckoutCatolog : EMPTY!\n");
    return;
  }
  catalog_traversal(CATALOG);
}

void Insert(const char * file) {
  FILE * toInsert = fopen(file, "r");
  if(toInsert == NULL) {
    printf("Insert FILE : '%s', no such file\n", file);
  }
  time_t clock_start, clock_end;
  char json[10000];
  catalog_record * CATALOG = NULL;
  int counter = 1;
  catalog_build(&CATALOG);
  FILE * storage = fopen(DATA_FILE, "ab+");

  clock_start = clock();

  static char IOBUFFER[PAGE_SIZE];

  if (setvbuf(storage, IOBUFFER, _IOFBF, PAGE_SIZE) != 0) {
    printf("failed to set up buffer for qurey\n");
  } else {
    printf("buffer(8KB) set up for input file\n"); 
  }

  while(fgets(json, 10000, toInsert) != NULL) {
    {
      json_parser * parser;
      int len = 0;
      parser = ParseJson(json, &len);
      static int max_id = 0;
      JsonSerializer(json, parser, len, &max_id, &CATALOG, storage);
    }
    if (counter % 1000 == 0)
      printf("process at %d\n", counter);
    counter++;
  }
  clock_end = clock();

  printf("insert file done!\n");
  printf("time waste: %.2fs\n", (double)(clock_end-clock_start)/CLOCKS_PER_SEC);

  catalog_save(CATALOG);
  fclose(storage);
}

void Find(const char * A, const char * B) {
  catalog_record * CATALOG = NULL;
  FILE * storage = fopen(DATA_FILE, "rb");
  file_position **file_index;
  int count;
  time_t clock_start, clock_end;

  printf("\n note that:\n");
  printf("\t use raw_int for int values\n");
  printf("\t use 'string' for string values\n");
  printf("\t use true or false for bool values\n");
  printf("\t use [] for array\n");
  printf("\t use {} for json\n\n");

  static char IOBUFFER[PAGE_SIZE];
  if (setvbuf(storage, IOBUFFER, _IOFBF, PAGE_SIZE) != 0) {
    printf("failed to set up buffer for input file\n");
  } else {
    printf("buffer(8KB) set up for input file\n"); 
  }

  clock_start = clock();

  count = build_data_file_index(&file_index, storage);
  printf("set up file index!\n");

  catalog_build(&CATALOG);
  qsort(file_index, count, sizeof(file_position *), comp);
  find(A, B, CATALOG, file_index, count, storage);

  clock_end = clock();
  printf("time waste: %.2fs\n", (double)(clock_end-clock_start)/CLOCKS_PER_SEC);
}

int main(int argc, char * argv[]) {

  printf("Simple Sinew System\n\n");

  if(argc <= 1) {
    printf("parameter -h for usage\n");
    exit(EXIT_FAILURE);
  }

  const char * Argument = argv[1];

  if(!strcmp(Argument, command[0])) {
    help();
    exit(EXIT_SUCCESS);
  } else if(!strcmp(Argument, command[1])) {
    const char * file = argv[2];
    if(file == NULL) {
      printf("No input file!\n");
      printf("parameter -h for usage\n");
      exit(EXIT_FAILURE);
    }
    printf("insert file '%s'\n", file);
    Insert(file);
    exit(EXIT_SUCCESS);
  } else if(!strcmp(Argument, command[2])) {
    CheckoutCatolog();
    exit(EXIT_SUCCESS);
  } else if(!strcmp(Argument, command[3])) {
    const char * A = argv[2];
    // argv[3] is '='
    const char * B = argv[4];
    if(A == NULL || B == NULL) {
      printf("Incomplete expression!\n");
      printf("parameter -h for usage\n");
      exit(EXIT_FAILURE);
    }
    printf("find %s = %s\n", A, B);
    Find(A, B);
    exit(EXIT_SUCCESS);
  } else {
    printf("No such Command!\n");
    printf("parameter -h for usage\n");
    exit(EXIT_FAILURE);
  }
}

这是第二段c程序

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "Global.h"
#include "Catalog.h"
#include "Json.h"
#include "Serializer.h"
#include "Find.h"
int comp(const void*a,const void*b) {
return (*(file_position **)a)->id - (*(file_position **)b)->id;}
const char * command[] = {
"-h","-i","-cc","-f"
};
void help() {
printf("usage:\n");
printf("-h : help\n");
printf("-i <file> : insert file\n");
printf("-cc : checkout the catalog\n");
printf("-f <A> = <B> : find <key,value>\n");
printf("\n");}
void CheckoutCatolog() {
catalog_record * CATALOG = NULL;
if(!catalog_build(&CATALOG)) {
printf("CheckoutCatolog : CATALOG LOADED FAILED!\n");
return;}
if(CATALOG == NULL) {
printf("CheckoutCatolog : EMPTY!\n");
return;}
catalog_traversal(CATALOG);}
void Insert(const char * file) {
FILE * toInsert = fopen(file, "r");
if(toInsert == NULL) {
printf("Insert FILE : '%s', no such file\n", file);}
time_t clock_start, clock_end;
char json[10000];
catalog_record * CATALOG = NULL;
int counter = 1;
catalog_build(&CATALOG);
FILE * storage = fopen(DATA_FILE, "ab+");
clock_start = clock();
static char IOBUFFER[PAGE_SIZE];
if (setvbuf(storage, IOBUFFER, _IOFBF, PAGE_SIZE) != 0) {
printf("failed to set up buffer for qurey\n");
} else {
printf("buffer(8KB) set up for input file\n"); }
while(fgets(json, 10000, toInsert) != NULL) {{
json_parser * parser;
int len = 0;
parser = ParseJson(json, &len);
static int max_id = 0;
JsonSerializer(json, parser, len, &max_id, &CATALOG, storage);}
if (counter % 1000 == 0)
printf("process at %d\n", counter);
counter++;}
clock_end = clock();
printf("insert file done!\n");
printf("time waste: %.2fs\n", (double)(clock_end-clock_start)/CLOCKS_PER_SEC);
catalog_save(CATALOG);
fclose(storage);}
void Find(const char * A, const char * B) {
catalog_record * CATALOG = NULL;
FILE * storage = fopen(DATA_FILE, "rb");
file_position **file_index;
int count;
time_t clock_start, clock_end;
printf("\n note that:\n");
printf("\t use raw_int for int values\n");
printf("\t use 'string' for string values\n");
printf("\t use true or false for bool values\n");
printf("\t use [] for array\n");
printf("\t use {} for json\n\n");
static char IOBUFFER[PAGE_SIZE];
if (setvbuf(storage, IOBUFFER, _IOFBF, PAGE_SIZE) != 0) {
printf("failed to set up buffer for input file\n");
} else {
printf("buffer(8KB) set up for input file\n"); }
clock_start = clock();
count = build_data_file_index(&file_index, storage);
printf("set up file index!\n");
catalog_build(&CATALOG);
qsort(file_index, count, sizeof(file_position *), comp);
find(A, B, CATALOG, file_index, count, storage);
clock_end = clock();
printf("time waste: %.2fs\n", (double)(clock_end-clock_start)/CLOCKS_PER_SEC);}
int main(int argc, char * argv[]) {
printf("Simple Sinew System\n\n");
if(argc <= 1) {
printf("parameter -h for usage\n");
exit(EXIT_FAILURE);}
const char * Argument = argv[1];
if(!strcmp(Argument, command[0])) {
help();
exit(EXIT_SUCCESS);
} else if(!strcmp(Argument, command[1])) {
const char * file = argv[2];
if(file == NULL) {
printf("No input file!\n");
printf("parameter -h for usage\n");
exit(EXIT_FAILURE);}
printf("insert file '%s'\n", file);
Insert(file);
exit(EXIT_SUCCESS);
} else if(!strcmp(Argument, command[2])) {
CheckoutCatolog();
exit(EXIT_SUCCESS);
} else if(!strcmp(Argument, command[3])) {
const char * A = argv[2];
const char * B = argv[4];
if(A == NULL || B == NULL) {
printf("Incomplete expression!\n");
printf("parameter -h for usage\n");
exit(EXIT_FAILURE);}
printf("find %s = %s\n", A, B);
Find(A, B);
exit(EXIT_SUCCESS);
} else {
printf("No such Command!\n");
printf("parameter -h for usage\n");
exit(EXIT_FAILURE);}}

你发现了什么?

没错,这两个程序的逻辑是一模一样的,可是可读性差别非常大!!

第二个程序基本上是人读不出来。

所以,不可以忽视缩进、换行这些问题!这些习惯必须从开始学习编程就抓起!

另外,变量不要随意乱用,代码结构优化,要写注释这些也是要求,不过是后话了。

因此,代码风格非常重要,请大家注意!

langzi989 commented 8 years ago

Scanf与printf


针对上面家荣师兄写的第一个关于scanf和printf的问题,大多数同学在第一节实验课上对此还是感到疑惑,我现在在着补充一下,希望师弟师妹们看了之后不但会用,而且还能深入理解.

头文件


首先scanf和printf这两个标准输入输出函数的原型是由库stdio.h提供的,所以每次使用这两个函数之前要 在代码前面加#include 这句来包含库函数,

形式及详解


scanf("格式字符串", 地址列表); printf("格式字符串", 参数表); 从函数原型中我们可以看出scanf和printf的区别,scanf中的第二个参数为地址列表,所以若输入一个(例如) 整数a时需要在a的前面加上去地址符号&,而printf不需要,这是两个函数最主要的区别,其中a表示的是变量 名,&a表示变量在内存中所在的地址.

格式字符串


格式字符串的一般形式为: %类型(这里是教简单的形式,随着学习的深入我们可以在格式化处规定字符串的长度,小数的精 度等,有兴趣的同学可以自己了解一下) 类型有一下几种(常用)
格式 字符意义

  • d 输入十进制整数
  •    <li>o    输入八进制整数</li>
       <li>x    输入十六进制整数</li>
       <li>u            输入无符号十进制整数</li>
       <li>f            输入实型数(用小数形式或指数形式)</li>
       <li>c            输入单个字符</li>
       <li>s            输入字符串</li>