C语言基础知识 && C++与STL && 数据结构基础

C语言基础知识

程序设计入门

  1. 在C语言中,整数值用%d输出,实数用 %f 输出。如:

    printf("%d\n",1+2);

    printf("%.1f\n",8.0/5.0);

  2. 一般来说,只要在程序中用到了数学函数,就需要在程序最开始处包含头文件 math.h,并在编译时连接数学库。

  3. scanf 中的占位符和变量的数据类型一一对应,且每个变量前需要加“&”符号。如:scanf("%d%d", &a, &b);

  4. 在算法竞赛中,输入前不要打印提示信息。输出完毕后应立即终止程序,不要等待用户按键,因为输入输出过程都是自动的,没有人工干预。

  5. 在一般情况下,你的程序不能直接读取键盘和控制屏幕:不要在算法竞赛中使用 getch()、getche()、gotoxy() 和 clrscr() 函数。

  6. 在算法竞赛中,每行输出均应以回车符结束,包括最后一行。

  7. 尽量用 const 关键字声明常数。如:const double pi = acos(-1.0);

  8. printf 的格式字符串中可以包含其他打印符号,打印时原样输出。如:printf("%d %d\n", a, b);

  9. C99 并没有规定int类型的确切大小,但在当前流行的竞赛平台中,int都是32位整数,范围是-2147483648~2147483647.

循环结构程序设计

  1. 在循环体开始处定义的变量,每次执行循环体时会重新声明并初始化。

  2. 可以使用 time.h 和 clock() 函数获得程序运行的时间。常数 CLOCKS_PRE_SEC 和操作系统相关,请不要直接使用 clock() 的返回值,而应总是除以 CLOCKS_PRE_SEC。

  3. 如果输入的个数不确定,可以这样判断:while(scanf("%d", &x)==1){}

    在 Windows 下,输入完毕后先按Enter键,再按 Ctrl+Z 键,最后再按 Enter 键,即可结束输入。在 Linux 下,输入完毕后按 Ctrl+D 键即可结束输入。

  4. 变量在未赋值之前的值是不确定的。特别地,它不一定等于0.

  5. 使用文件最简单的方法是使用输入输出重定向,只需在 main 函数的入口处加入以下两条语句:

    freopen("input.txt", "r", stdin);
    freopen("output.txt", "w", stdout);
    

数组和字符串

  1. 比较大的数组应尽量声明在 main 函数外,否则程序可能无法运行。

  2. 如果要从数组a赋值k个元素到数组b,可以这样做:memcpy(b, a, sizeof(int)*k)。使用 memcpy 函数要包含头文件 string.h。如果需要把数组a直接复制到数组b中,可以写得简单一些:memcpy(b,a,sizeof(a));

  3. 把数组a清零:memset(a,0,sizeof(a)); // 它也在string.h中定义

  4. 字符常量可以用单引号法表示。在语法上可以把字符当作int型使用。

  5. 在 “scanf(”%s", s)" 中,不要在 s 前面加上 “&” 符号。注意,“scanf(”%s", s)" 遇到空白字符(空格、TAB和回车符)会停下来。

  6. 函数 strchr 的作用是在一个字符串中查找单个字符。

  7. printf 输出到屏幕,fprintf 输出到文件,而sprintf 输出到字符串(应当保证字符串足够大,可以容纳输出信息)。

  8. C语言中的字符串是以 “\0” 结尾的字符数组,函数 strlen(s) 的作用是获取字符串 s 的实际长度(结束标记之前的字符个数)。

  9. 字符串只能用 strcpy(a, b), strcmp(a, b), strcat(a, b) 来执行”赋值“、”比较“和”连接“操作,而不能用”=“、”==“、”<=“、”+“等运算符。上述函数都在 string.h 中声明。

  10. 使用 fgetc(fin) 可以从打开的文件 fin 中读取一个字符。一般情况下应当在检查它不是 EOF (while((c = getchar()) != EOF){...})后再将其转换成 char 值。从标准输入读取一个字符可以用 getchar, 它等价于 fgetc(stdin)。

  11. “fgets(buf, maxn, fin)” 将读取完整的一行放在字符数组 buf 中。当一个字符都没有读到时,fgets 返回 NULL。

  12. C语言中的 gets(s) 存在缓冲区漏洞,不推荐使用。在C11标准里,该函数已被正式删除。

  13. 善用常量数组往往能简化代码。定义常量数组时无须指明大小,编译器会计算。

  14. 头文件 ctype.h 中定义的 isalpha、isdigit、isprint 等工具可以用来判断字符的属性,而 toupper、tolower 等工具可以用来转换大小写。如果ch是大写字母,则 ch-‘A’ 就是它在字母表中的序号(A的序号是0,B的序号是1,以此类推);类似地,如果 ch 是数字,则 ch-‘0’ 就是这个数字的值本身。

函数和递归

  1. 在算法竞赛中,请总是让main函数返回0.

  2. 为了使用方便,往往用 “typedef struct { 域定义; }类型名;” 的方式定义一个新类型名。这样,就可以像原生数据类型一样使用这个自定义类型。如:typedef struct { double x, y; }Point;

  3. 对复杂的表达式进行化简有时不仅能减少计算量,还能减少甚至避免中间结果溢出。

  4. 建议把谓词(用来判断某事物是否具有某种特性的函数)命名成 “is_xxx” 的形式,返回 int 值,非0表示真,0表示假。

  5. 操作全局变量有风险,应谨慎使用。

  6. 变量名前面加"&"得到的是该变量的地址。用 int*a 声明的变量a是指向int型变量的指针。*a 是指”a指向的变量“,而不仅是”a指向的变量所拥有的值“。

  7. 以数组为参数调用函数时,实际上只有数组首地址传递给了函数,需要另加一个参数表示元素个数。除了把数组首地址本身作为实参外,还可以利用指针加减法把其他元素的首地址传递给函数。如:

    //计算数组的元素和
    
    //法一
    int sum(int* a, int n){
    	int ans = 0;
    	for(int i = 0; i < n; i++)
    		ans += a[i];
    	return ans;
    }
    
    //法二 计算左闭右开区间内的元素和
    int sum(int* begin, int* end){
    	int n = end-begin;
    	int ans = 0;
    	for(int i = 0; i < n; i++)
    		ans += begin[i];
    	return ans;
    }
    
    //法三
    int sum(int* begin, int* end){
    	int *p = begin;
    	int ans = 0;
    	for(int *p=begin; p!=end; p++)
    		ans += *p;
    	return ans;
    }
    

C++ 与 STL

  1. 与C程序相比,头文件的变化为:在C头文件之前加一个小写的c字母,然后去掉.h后缀。如:stdio.h 变成了cstdio,string.h变成了 cstring,math.h 变成了cmath,ctype.h 变成了cctype……

  2. algorithm提供了一些常用的算法,如 min。

  3. C++中可以使用流简化输入输出操作。标准输入输出流在头文件iostream中定义,存在于命名空间std中。如果使用了 using namespace std; 语句,则可以直接使用。

  4. 声明数组时,数组大小可以使用 const 声明的常数,而不是用 #define 声明常数。

  5. C++中的引用就是变量的”别名“,它可以在一定程度上代替C中的指针。例如,可以用“传引用”的方式(在参数名之前加一个"&"符号)让函数内直接修改实参。

  6. algorithm 头文件中的 sort 可以给任意对象排序,包括内置类型(数组用 sort(a, a+n) 的方式调用,vector 用 sort(v.begin(), v.end() 的方式调用))和自定义类型,前提是类型定义了 “<” 运算符。排序之后可以用 lower_bound 查找大于或等于 x 的第一个位置。unique 函数可以删除有序数组中的重复元素。

  7. vector 头文件里的 vector 是一个不定长数组,可以用 clear() 清空,resize() 改变大小,用 push_back() 和 pop_back() 在尾部添加和删除元素,用 empty() 测试是否为空。vector 之间可以直接赋值或者作为函数的返回值。

  8. set 头文件中的 set(每个元素最多只出现一次)和 map 头文件中的 map(从键(key)到值(value)的映射)分别是集合与映射。二者都支持 insert、find、count 和 remove 操作,并且可以按照从小到大的顺序循环遍历其中的元素。map 还提供了"[]" 运算符,使得 map 可以向数组一样使用。事实上,map 也称为“关联数组”。例如可以用一个 map month_name 来表示“月份名字到月份编号”的映射,然后用 month_name[“July”] = 7 这样的方式来赋值。

  9. STL 的 stack 头文件提供了栈,用 “stack s” 的方式定义,用 push() 和 pop() 实现元素的入栈和出栈操作,top() 取栈顶元素(但不删除)。

  10. STL 的 queue 头文件提供了队列,用 “queue s” 的方式定义,用 push() 和 pop() 实现元素的入队和出队操作,front() 取队首元素(但不删除)。

  11. STL 的 queue 头文件提供了优先队列,用 “priority_queue s” 方式定义,用 push() 和 pop() 实现元素的入队和出队操作,top() 取队首元素(但不删除)。对于一些常见的优先队列,STL 提供了更为简单的定义方法,例如,“越小的整数优先级越大的优先队列”可以写成"priority_queue pq"。注意,最后两个">“符号不要写在一起,否则会被很多编译器误认为是”>>"运算符。

  12. cstdlib 中的 rand() 函数可生成闭区间[0, RAND_MAX] 内均匀分布的随机整数,其中 RAND_MAX 至少为32767。如果要生成更大的随机整数,在精度要求不太高的情况下可以用 rand() 的结果“放大”得到。

  13. 可以使用 cstdlib 中的 srand 函数初始化随机数种子。如果需要程序每次执行时使用一个不同的种子,可以用 ctime 中的 time(NULL) 为参数调用 srand (即 srang(time(NULL)))。一般来说,只在程序执行的开头调用一次 srand。

  14. 随即程序:

    void fill_random_int(vector &v, int cnt) {
        v.clear();
        for(int i = 0; i < cnt; i++)
            v.push_back(rand());
    }
    

    把 vector 作为参数或者返回值时,应尽量改成引用方式传递参数,以避免不必要的值被复制。

  15. C++ 支持函数重载,但函数的参数类型必须不同(不能只有返回值类型不同)。

  16. **测试时往往使用 assert。**其用法是:“assert(表达式)”,当表达式为假时强行终止程序,并给出错误提示。

  17. 可以给结构体重载赋值运算符,使得用起来更方便。

  18. 可以给结构体声明一些属于该结构体类型的静态成员变量,方法时加上 static 修饰符。静态成员变量在结构体外部使用时要写成:“结构体名::静态成员变量名”。

数据结构基础

  1. 如果要在“队列”两端进行插入和删除,可以用 STL 中的双端队列 deque。

  2. 简单的表达式解析可以借助栈来完成。

  3. 如果要定义一棵二叉树,一般是定义一个“结点”类型的 struct(如叫 Node),然后保存树根的指针(如 Node* root)。

    //结点类型
    struct Node{
        bool have_value; //是否被赋值过
        int v; //结点值
        Node *left, *right; 
        Node():have_value(false), left(NULL), right(NULL){} //构造函数
    };
    
    Node* root; //二叉树的根结点
    

你可能感兴趣的:(c++,c语言,stl,数据结构)