目录

Harvard CS50 学习笔记(二)

摘要
Harvard CS50 学习笔记(二)。

2 Array

2.1 Lecture

2.1 Make

2.2 Clang

  1. C 语言 的编译器前端。

  2. clang <name>.c 源码文件,对源码文件进行编译,并生成可执行文件a.out (默认名称)。

  3. 如果需要指定名称,使用 clang -o <name> <name>.c

  4. 如果源码包含了非标准库的头文件,使用clang 编译时需要指定关联,否则报错。

    clang -o <name> <name>.c -l<name of .h file>

2.3 Compiling (Four Steps)

  1. Preprocessing
  2. Compiling
  3. Assembling
  4. Linking

2.4 Preprocessing

/images/Harvard_CS50/Lecture_2/preprocessing_1.png
preprocessing_1
  1. 源码最上面的 # ,实际为 preprocessor directive,即预处理指令。
  2. 含有 # 的代码会被特殊处理。
  3. # 引入的头文件,类似于找到头文件的代码,复制粘贴到源码最上方。(其实只是函数的声明,没有实现)
/images/Harvard_CS50/Lecture_2/preprocessing_2.png
preprocessing_2

2.5 From source code to machine code

  1. C语言,编译为汇编语言(Assembling Language)。
  2. 左边的东西叫 汇编指令Assembling Instruction)。
/images/Harvard_CS50/Lecture_2/compiling.png
compiling

2.6 Assembling

  • 把汇编语言变成01字节码。
/images/Harvard_CS50/Lecture_2/assembling.png
assembling

2.7 Linking

  1. 把用到的不同程序,例如引入的头文件的源码,与当前程序进行链接。
  2. 头文件只有声明,这一步是找到其实现,进行链接。

2.8 Debugging

2.9 buggy.c

2.10 printf

2.11 debug50

2.12 Rubber Duck Debugging

2.13 get_negative_int

2.14 Step in

2.15 Types and their sizes

/images/Harvard_CS50/Lecture_2/types_and_sizes.png
types_and_sizes

2.16 Memory

2.17 scores.c

2.18 Arrays

  • 数组:储存同一数据类型。

2.19 Sizing arrays

2.20 Arrays of characters

  1. 强制转换:(类型) 变量名。
  2. 字符串就是字符数组。

2.21 NUL character

  1. \0,对应的数字是0。
  2. 字符串最后会加一位 NUL(占 1 byte),用来表示一个字符串的结束(不然无法知道字符串直之间的开始与结束),方便内存存储。
  3. 只有字符串会这么做,因为长度不固定,其他类型的长度是定死的,不需要加 NUL(\0)

2.22 length.c

2.23 strlen

#include <string.h>

2.24 Manual pages

https://manual.cs50.io/

2.25 ASCII

2.26 string.c

for 循环可以声明多个参数。

1
2
3
for (i = 0, n = strlen(str); i < n; i++) {
  ......
}

2.27 uppercase.c

2.28 Check for lowercase

2.29 islower

2.30 toupper

2.31 Command-line Arguments

2.32 argc and argv

  1. argc —> argument count
  2. argv —> argument vector

2.33 argv[0]

1
2
3
4
5
6
#include <stdio.h>

int main(int argc, string argv[])
{
    ...
}

2.34 argv[1]

  • argv[] 会接受控制台的所有指令。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
#include <stdio.h>

int main(int argc, string argv[])
{
   if (argc == 2) {
     printf("hello, %s\n", argv[1]);
   } else {
     printf("hello. world\n");
   }
}

2.35 Arrays of arguments

2.36 Exit status

  • 没问题返回 0,有问题返回非 0(即 1 )。
  • main() 方法默认会返回 0
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
#include <stdio.h>

int main(int argc, string argv[])
{
   if (argc != 2) {
     printf("Missing command-line argument!\n");
     return 1;
   printf("hello, %s\n", argv[1]);
     return 0;
}

2.37 Readability

2.38 Cryptography


2.2 Shorts

2.2.1 Functions

/images/Harvard_CS50/Lecture_2/functions/functions.png
functions_1
/images/Harvard_CS50/Lecture_2/functions/what_is_a_function_1.png
what_is_a_function_1.png
/images/Harvard_CS50/Lecture_2/functions/what_is_a_function_2.png
what_is_a_function_2
/images/Harvard_CS50/Lecture_2/functions/what_is_a_function_3.png
what_is_a_function_3
/images/Harvard_CS50/Lecture_2/functions/why_call_it_a_black_box_1.png
why_call_it_a_black_box_1
/images/Harvard_CS50/Lecture_2/functions/why_call_it_a_black_box_2.png
why_call_it_a_black_box_2
/images/Harvard_CS50/Lecture_2/functions/why_call_it_a_black_box_3.png
why_call_it_a_black_box_3
/images/Harvard_CS50/Lecture_2/functions/why_use_functions.png
why_use_functions
  • 组织性
  • 简易性
  • 复用性

/images/Harvard_CS50/Lecture_2/functions/function_declarations_1.png
function_declarations_1
/images/Harvard_CS50/Lecture_2/functions/function_declarations_2.png
function_declarations_2
/images/Harvard_CS50/Lecture_2/functions/function_declarations_3.png
function_declarations_3
/images/Harvard_CS50/Lecture_2/functions/function_declarations_4.png
function_declarations_4
/images/Harvard_CS50/Lecture_2/functions/function_declarations_5.png
function_declarations_5
/images/Harvard_CS50/Lecture_2/functions/function_definition_1.png
function_definition_1
/images/Harvard_CS50/Lecture_2/functions/function_definition_2.png
function_definition_2
/images/Harvard_CS50/Lecture_2/functions/function_calls.png
function_calls
/images/Harvard_CS50/Lecture_2/functions/function_miscellany.png
function_miscellany
/images/Harvard_CS50/Lecture_2/functions/practice_problem_1.png
practice_problem_1
/images/Harvard_CS50/Lecture_2/functions/practice_problem_2.png
practice_problem_2

2.2.2 Variables And Scope

/images/Harvard_CS50/Lecture_2/variables_and_scope/variable_scope_1.png
variable_scope_1
/images/Harvard_CS50/Lecture_2/variables_and_scope/variable_scope_2.png
variable_scope_2
/images/Harvard_CS50/Lecture_2/variables_and_scope/variable_scope_3.png
practice_problem_2
/images/Harvard_CS50/Lecture_2/variables_and_scope/variable_scope_4.png
variable_scope_4
  • Java 的重要区别!
  • C 中参数传递都是值的拷贝,非地址值。

/images/Harvard_CS50/Lecture_2/variables_and_scope/variable_scope_5.png
variable_scope_5
/images/Harvard_CS50/Lecture_2/variables_and_scope/variable_scope_6.png
variable_scope_6
/images/Harvard_CS50/Lecture_2/variables_and_scope/variable_scope_7.png
variable_scope_7
/images/Harvard_CS50/Lecture_2/variables_and_scope/variable_scope_8.png
variable_scope_8

2.2.3 Arrays

/images/Harvard_CS50/Lecture_2/arrays/array_1.png
array_1
/images/Harvard_CS50/Lecture_2/arrays/array_2.png
array_2
/images/Harvard_CS50/Lecture_2/arrays/array_3.png
array_3
  • C 中数组越界不一定就报错,要特别谨慎!

/images/Harvard_CS50/Lecture_2/arrays/array_declaration_1.png
array_declaration_1
/images/Harvard_CS50/Lecture_2/arrays/array_declaration_2.png
array_declaration_2
/images/Harvard_CS50/Lecture_2/arrays/array_declaration_3.png
array_declaration_3
/images/Harvard_CS50/Lecture_2/arrays/array_4.png
array_4
/images/Harvard_CS50/Lecture_2/arrays/array_5.png
array_5
/images/Harvard_CS50/Lecture_2/arrays/array_6.png
array_6
/images/Harvard_CS50/Lecture_2/arrays/array_7.png
array_7
/images/Harvard_CS50/Lecture_2/arrays/array_8.png
array_8
/images/Harvard_CS50/Lecture_2/arrays/array_9.png
array_9
  • C中,array(数组)不能直接通过变量赋值,需要循环。

/images/Harvard_CS50/Lecture_2/arrays/array_10.png
array_10
/images/Harvard_CS50/Lecture_2/arrays/array_11.png
array_11
  • C中,array(数组)不是值传递,而是引用传递!

2.2.4 Command Line Arguments

/images/Harvard_CS50/Lecture_2/command_line_arguments/command_line_arguments_1.png
command_line_arguments_1
  • 命令行参数,新东西,要注意一下。

/images/Harvard_CS50/Lecture_2/command_line_arguments/command_line_arguments_2.png
command_line_arguments_2
  • argc 参数数量;argv 参数数组。

/images/Harvard_CS50/Lecture_2/command_line_arguments/command_line_arguments_3.png
command_line_arguments_3
  • 注意参数用空格分隔。

/images/Harvard_CS50/Lecture_2/command_line_arguments/command_line_arguments_4.png
command_line_arguments_4
/images/Harvard_CS50/Lecture_2/command_line_arguments/command_line_arguments_5.png
command_line_arguments_5

2.3 Lab 2

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#include <stdio.h>
#include <cs50.h>
#include <ctype.h>
#include <string.h>

// declare functions
string getInput(int player);
int calculateScores(string input);
void compareAndOutput(int score1, int score2);

char letterArr[26] = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'};
int  numArr[26] = {1,3,3,2,1,4,2,4,1,8,5,1,3,1,1,3,10,1,1,1,1,4,4,8,4,10};

int main(void) {
    // get user input
    string player1 = getInput(1);
    string player2 = getInput(2);

    // calculate scores
    int player1Score = calculateScores(player1);
    int player2Score = calculateScores(player2);

    // compare and output
    compareAndOutput(player1Score, player2Score);
}

string getInput(int player) {
    return get_string("Player %i: ", player);
}

int calculateScores(string input) {
    int sum = 0;
    for (int i = 0, length = strlen(input); i < length; i++) {
        for (int j = 0; j < 26; j++) {
            char letter = toupper(input[i]);
            if (letter == letterArr[j]) {
                sum += numArr[j];
        }
    }
    }
    return sum;
}

void compareAndOutput(int score1, int score2) {
    if (score1 > score2) {
        printf("Player 1 wins!\n");
    } else if (score1 < score2) {
        printf("Player 2 wins!\n");
    } else {
        printf("Tie!\n");
    }
}

2.4 Problem Set 2

2.4.1 Readability

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
#include <cs50.h>
#include <stdio.h>
#include <string.h>
#include <math.h>

// declare finctions
string getInput();
int countLetters(string text);
int countSentences(string text);
int countWords(string text);
void calculatteGrade(int letterCount, int sentenceCount, int wordCount);

int main(void) {
    // getInput
    string text = getInput();

    // count letters
    int letterCount = countLetters(text);

    // count sentences
    int sentenceCount = countSentences(text);

    // count words
    int wordCount = countWords(text);

    // calculate grade
    calculatteGrade(letterCount, sentenceCount, wordCount);

}

string getInput() {
    return get_string("Text: ");
}

int countLetters(string text) {
    int letterCount = 0;
    for (int i = 0, n = strlen(text); i < n; i++) {
        if (text[i] >= 'A' && text[i] <= 'z') {
            letterCount++;
        }
    }
    return letterCount;
}

int countSentences(string text) {
    int sentenceCount = 0;
    for (int i = 0, n = strlen(text); i < n; i++) {
        if (text[i] == '!' || text[i] == '.' || text[i] == '?') {
            sentenceCount++;
        }
    }
    return sentenceCount;
}

int countWords(string text) {
    int wordCount = 0;
    for (int i = 0, n = strlen(text); i < n; i++) {
        if (text[i] == ' ') {
            wordCount++;
        }
    }
    return ++wordCount;
}

void calculatteGrade(int letterCount, int sentenceCount, int wordCount) {
    // 这里有个坑,C 不会自动转换类型,int 运算后结果还是 int,即便结果我用double 类型接收,需要手动转换,或者在运算中加入浮点型
    double averageLetterCount = letterCount * 100.0 / wordCount;
    double averageSentenceCount = sentenceCount * 100.0 / wordCount;
    int grade = round(0.0588 * averageLetterCount - 0.296 * averageSentenceCount - 15.8);
    if (grade < 1) {
        printf("Before Grade 1\n");
    } else if (grade >=16) {
        printf("Grade 16+\n");
    } else {
        printf("Grade %i\n", grade);
    }
}

2.4.2 Substitution

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
#include <cs50.h>
#include <stdio.h>
#include <ctype.h>
#include <string.h>

// delcare functions
int judgeArgument(int argc, string argv[]);
void encryptTheInput();
int checkLength(int argc, string argv[]);
int checkLetter(string str);
int checkDuplicate(string str);


string key = "";

int main(int argc, string argv[]) {
    // judge argument
    if (judgeArgument(argc, argv) != 0) {
        return 1;
    } else {
        // crypt the input
        encryptTheInput();
        return 0;
    }
}

int judgeArgument(int argc, string argv[]) {
    if (checkLength(argc, argv) != 0) {
        return 1;
    } else {
        string str = argv[1];
        if (checkLetter(str) != 0) {
            return 1;
        } else {
            if (checkDuplicate(str) != 0) {
                return 1;
            }
        }
    }
    key = argv[1];
    return 0;
}

int checkLength(int argc, string argv[]) {
    if (argc != 2) {
        printf("Usage: ./substitution key\n");
        return 1;
    } else {
        string str = argv[1];
        int length = strlen(str);
        if (length != 26) {
            printf("Key must contain 26 characters.\n");
            return 1;
        }
    return 0;
}
}

int checkLetter(string str) {
    int length = strlen(str);
    for (int i = 0; i < length; i++) {
        if (str[i] < 'A' || str[i] > 'z') {
            return 1;
        } else if (str[i] > 'Z' && str[i] < 'a') {
            return 1;
        }
    }
    return 0;
}

int checkDuplicate(string str) {
    int length = strlen(str);
    for (int i = 0; i < length; i++) {
        for (int j = 0; j < length; j++) {
            if (i != j) {
                if (str[i] == str[j]) {
                return 1;
            }
            }
        }
    }
    return 0;
}

void encryptTheInput() {
    string input = get_string("plaintext:  ");
    int length = strlen(input);
  	// 这里有个大坑,就是如果输出的加密信息,不是字符串类型,而直接使用数组,那么会出现分割问题,部分结果最后可能会多 ‘\n’,无法通过检测
    string output = input;
    for (int i = 0; i < length; i++) {
        if (input[i] >= 'A' && input[i] <= 'Z') {
            int index = input[i] - 'A';
            output[i] = toupper(key[index]);
        } else if (input[i] >= 'a' && input[i] <= 'z') {
            int index = input[i] - 'a';
            output[i] = tolower(key[index]);
        }
    }
    printf("ciphertext: %s", output);
    printf("\n");
}

不要一上来就写代码,多想,尤其多考虑边界条件