函数指针

  • 定义形式: 类型名 (*指针变量名)(参数类型1, 参数类型2, ...);

  • 使用方法: 函数指针名(实参表);

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    #include <stdio.h>
    void PrintMin(int a, int b) {
    if (a < b)
    printf("%d", a);
    else
    printf("%d", b);
    }
    int main() {
    void (*pf)(int, int);
    int x = 4, y = 5;
    pf = PrintMin;
    pf(x, y);
    }
  • qsort库函数

    • void qsort(void *base, int nelem, unsigned int width,int (*pfCompare)(const void *, const void *));

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      #include <stdio.h>
      #include <stdlib.h>
      int MyCompare(const void *elem1, const void *elem2) {
      unsigned int *p1, *p2;
      p1 = (unsigned int *)elem1; // *elem1 非法
      p2 = (unsigned int *)elem2; // *elem2 非法
      return (*p1 % 10) - (%p2 % 10); // 负数升序, 正数降序
      }
      #define NUM 5
      int main() {
      unsigned int an[NUM] = {8, 123, 11, 10, 4};
      qsort(an, NUM, sizeof(unsigned int), MyCompare);
      for (int i = 0; i < NUM; i++)
      printf("%d ", an[i]); // 10 11 123 4 8
      return 0;
      }

命令行参数

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

    • argc: 启动程序时, 命令行参数的个数 (至少为1, 第一个表示可执行程序本身的文件名)

    • argv: 存放命令行参数

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      #include <stdio.h>
      int main(int argc, char *argv[]) {
      for (int i = 0; i < argc; i++)
      printf("%s\n", argv[i]);
      return0;
      }
      /*
      将上面的程序编译成sample.exe, 然后在控制台窗口敲:
      sample para1 para2 s.txt "hello world"
      输出结果为:
      sample
      para1
      para2
      s.txt
      hello world
      */

位运算

  • &: 将某变量中的某些位清0且同时保留其他位不变 或 用来获取某变量中的某一位

  • |: 将某变量中的某些位置1且保留其他位不变

  • ^: 将某变量中的某些位取反且保留其他位不变

    • 如果 a ^ b = c, 则 c ^ b = a 或 c ^ a = b (可用于加密)

    • 不通过临时变量交换两个变量的值

      1
      2
      3
      4
      int a = 5, b = 7;
      a = a ^ b;
      b = b ^ a;
      a = b ^ a;
  • ~

  • <<: 左移n位, 即乘2n (比乘法快很多)

  • >>: 右移n位, 即除以2n, 且将结果往小取整

引用

  • 类型名 & 引用名 = 某变量名;

  • 某个变量的引用, 等价于这个变量, 相当于该变量的一个别名

    1
    2
    3
    4
    5
    6
    void swap(int &a, int &b) {
    int tmp;
    tmp = a; a = b; b = tmp;
    }
    int n1, n2;
    swap(n1, n2); // n1, n2的值被交换
  • 函数返回类型为引用, 则可以让该函数为表达式的左值

  • 常引用: const T &

    • 不能通过常引用去修改其引用的内容
    • T &类型的引用或T类型的变量可以用来初始化const T &类型的引用
    • const T类型的常变量和const T &类型的引用不能用来初始化T &类型的引用, 除非进行强制类型转换

const关键字和常量

  • 常量指针

    • 不可通过常量指针修改其指向的内容

      1
      2
      3
      4
      5
      int n, m;
      const int *p = &n;
      *p = 5; //编译出错
      n = 4; //ok
      p = &m; //ok, 常量指针的指向可以变化
    • 不能把常量指针赋值给非常量指针, 反过来可以

      1
      2
      3
      4
      5
      const int *p1;
      int *p2;
      p1 = p2; //ok
      p2 = p1; //error
      p2 = (int *) p1; //ok
  • 函数参数为常量指针时, 可避免函数内部不小心改变参数指针所指地方的内容

  • 不能通过常引用修改其引用的变量

    1
    2
    3
    4
    int n;
    const int &r = n;
    r = 5; //error
    n = 4; //ok

动态内存分配

  • new运算符实现动态内存分配

    • 分配一个变量 P = new T;

      1
      2
      3
      int *pn;
      pn = new int;
      *pn = 5;
    • 分配一个数组 P = new T[N];

  • delete运算符释放动态分配的内存

    • delete指针必须指向new出来的空间
    • 一片空间不能被delete多次
    • 释放数组空间: delete []p;

内联函数和重载函数

  • 内联函数

    • 函数调用是有时间开销的, 如果函数本身只有几条语句, 执行非常快, 而且函数被反复执行很多次, 相比之下调用函数所产生的这个开销就会显得比较大

    • 内联函数机制: 编译器处理对内联函数的调用语句时, 是将整个函数的代码插入到调用语句处, 而不会产生调用函数的语句

    • 定义内联函数: 再函数定义前加 inline

    • 弊端: 可执行文件体积增大

  • 函数重载

    • 函数名相同, 参数表不同
    • 使函数命名简单

函数缺省参数

  • 定义函数时, 可以让最右边的连续若干个参数有缺省值

    1
    2
    3
    4
    void func(int x1, int x2 = 2, int x3 = 3) {}
    func(10); // == func(10, 2, 3)
    func(10, 8); // == func(10, 8, 3)
    func(10, ,8); // error, 只能最右边的连续若干个参数缺省
  • 提高程序的可扩充性, 如果某个写好的函数要添加新的参数, 而原先那些调用该函数的语句, 未必需要使用新增的参数, 那么为了避免对原先那些函数调用语句的修改, 就可以使用缺省参数

面向对象程序设计

  • 对象的内存分配

    • 对象的大小 = 所有成员变量的大小之和
  • 在类外定义成员函数

    • T 类名::函数名() {};