C语言 - 学习笔记
Harvard CS50 计算机科学概论
Harvard CS50 计算机科学概论
  • Prologue
  • WEEK 0 Introduction
  • WEEK 1 C
  • WEEK 2 Arrays
  • WEEK 3 Algorithms
  • WEEK 4 Memory
  • WEEK5 Data Structures
  • WEEK6 Python
  • WEEK7 SQL
  • WEEK8 HTML, CSS, JavaScript
  • WEEK9 Flask
  • C语言总结
Powered by GitBook
On this page

C语言总结

  1. Unsigned和Signed比较会变成Unsigned。

  2. malloc之后就可以使用,但是是Garbage Value。

  3. strcpy等函数注意给dest预留\0的内存。

  4. typedef struct ht_node* node; 只是一个指针类型,内存为8字节。

  5. 不要在函数内返回在该函数内生成的栈内存指针,因为在函数结束时会失效。

  6. inline内联函数不等于宏,宏会收到钱后运算符优先级的影响。

  7. 指针算数和类型有关系。

  8. 使用getopt解析命令行参数。

    代码:

    #include <stdio.h>
    #include <unistd.h>
    
    int main (int argc, char **argv){
        int opt;
        while ((opt = getopt (argc, argv, ":abc:d")) != -1){
            if (opt == '?'){
                printf("unknown flag: %c\n", optopt);
            } else if (opt == ':'){
                printf("flag: %c, value not given\n", optopt);
            }
            else {
                printf("flag: %c, value: %s\n", opt, optarg);
            }
        }
        for (int i = optind; i < argc; i++) {
            printf("remaining: %s\n", argv[i]);
        }
    }

    结果:

    ubuntu@c-test-node:~/cmu15213/lec13$ ./getopt -abd -c
    flag: a, value: (null)
    flag: b, value: (null)
    flag: d, value: (null)
    flag: c, value not given
    ubuntu@c-test-node:~/cmu15213/lec13$ ./getopt -aef
    flag: a, value: (null)
    unknown flag: e
    unknown flag: f
    ubuntu@c-test-node:~/cmu15213/lec13$ ./getopt -a -b -d -c 100 200 300
    flag: a, value: (null)
    flag: b, value: (null)
    flag: d, value: (null)
    flag: c, value: 100
    remaining: 200
    remaining: 300
    ubuntu@c-test-node:~/cmu15213/lec13$ ./getopt -a -b -d  200 300 -c 100
    flag: a, value: (null)
    flag: b, value: (null)
    flag: d, value: (null)
    flag: c, value: 100
    remaining: 200
    remaining: 300
    ubuntu@c-test-node:~/cmu15213/lec13$ ./getopt -abd -c100
    flag: a, value: (null)
    flag: b, value: (null)
    flag: d, value: (null)
    flag: c, value: 100
  9. Never cast a pointer to a larger type and dereference it, this accesses memory with undefined contents.

  10. Never cast to a smaller type; will truncate (lose) data.

  11. Integer Type Casting:

    • signed <-> unsigned: change interpretation of most significant bit

    • smaller signed -> larger signed: sign-extend (duplicate the sign bit)

    • smaller unsigned -> larger unsigned: zero-extend (duplicate 0)

  12. Number mallocs = Number frees

    • Number mallocs > Number Frees: definitely a memory leak

    • Number mallocs < Number Frees: definitely a double free

  13. void* type is C’s provision for generic types.

    • Raw pointer to some memory location (unknown type)

    • Can cast back and forth between void* and other pointer types

  14. Header Files

    • #include <lib> for standard libraries

    • #include "file" for your source files

    • Never include .c files (bad practice)

    • Only include function prototypes/macros; no implementation code!

  15. Header Guards

    • Double-inclusion problem: include same header file twice

      //grandfather.h
      
      //father.h
      #include "grandfather.h"
      
      //child.h
      #include "father.h"
      #include "grandfather.h"

      Error: child.h includes grandfather.h twice.

    • Solution: header guard ensures single inclusion

      //grandfather.h
      #ifndef GRANDFATHER_H
      #define GRANDFATHER_H
      #endif
      
      //father.h
      #ifndef FATHER_H
      #define FATHER_H
      #endif
      
      //child.h
      #include "father.h"
      #include "grandfather.h"
  16. These functions can return error codes

    • malloc could fail.

    • a file couldn’t be opened.

    • a string may be incorrectly parsed.

  17. Macros

    • Why macros? “Faster” than function calls

    • Drawbacks

      • Less expressive than functions

      • Arguments are not typechecked, local variables

        • This can easily lead to errors that are more difficult to find

    • #define twice(x) 2*x

      • Not OK, twice(x+1) becomes 2 * x + 1

      • Correct: #define twice(x) (2 *(x))

      • Always wrap in parentheses; it's a naive search-and-replace!

  18. inline

    • At compile-time replaces "function calls" with code

    • More efficient than a normal function call

      • Less overhead - no need to set up stack/function call

      • Useful for functions that are

        • Called frequently

        • Small, e.g., int add(int x, int y);

    • 可以理解为调用时建议编译器进行内联展开,编译的时候可能不会创建栈帧(pushq),而是直接运行函数体。

    • static inline:

      • GCC不会特意为static inline函数生成独立的汇编码,除非出现了必须生成不可的情况(如通过函数指针调用和递归调用)。

      • GCC的static inline函数仅能作用于文件范围内。

    • inline:

      • GCC的inline函数相对于普通extern函数来说只是在同一个文件内调用时建议编译器进行内联展开。

      • GCC一定会为inline函数生成一份独立的汇编码,以便其在本文件之外被调用。在别的文件内看来,这个inline函数和普通的extern函数无异,

      • GCC的inline函数是全局性的:在文件内可以作为一个内联函数被内联展开,而在文件外可以调用它。

    • 例子:

      • 如果不加static会报错。Normally GCC’s file scope is “not extern linkage”. That means inline function is never ever provided to the linker which is causing linker error. To resolve this problem use “static” before inline. Using static keyword forces the compiler to consider this inline function in the linker, and hence the program compiles and run successfully.

    #include <stdio.h>
      
    // Inline function in C
    static inline int foo()
    {
        return 2;
    }
      
    // Driver code
    int main()
    {
      
        int ret;
      
        // inline function call
        ret = foo();
      
        printf("Output is: %d\n", ret);
        return 0;
    }
  19. Macros和inline区别:

    • Macros done at pre-compile time

    • Inline functions done at compile time

      • Stronger type checking / Argument consistency

    • Macros cannot return anything (why not?)

    • Macros can have unintended side effects

      • #define xsquared(x) (x * x$

    • Hard to debug macros

      • errors generated on expanded code, not code that you typed

  20. 指针转化

    • 指针的值不会发生任何改变,改变体现在Deferencing的时候。

    • Cannot dereference expressions with type void*

    • Dereferencing a t * evaluates to a value with type t

    int * ptr1 = malloc(sizeof(int));
    *ptr1 = 0xdeadbeef;
    int val1 = *ptr1;
    int val2 = (int) *((char *) ptr1);
    // val1 = 0xdeadbeef;
    // val2 = 0xffffffef; 
PreviousWEEK9 Flask

Last updated 2 years ago