哈佛CS50x 2025 | Week1: C语言 课堂笔记 | 211 cs新生自救指北 | 计算机科学概论

王者杯·14天创作挑战营·第5期 10w+人浏览 273人参与

WEEK 1 课堂笔记


  • 回顾与学习重点
    • 回顾
    • 学习重点
  • Hello, World
  • 头文件和CS50手册
    • 头文件与库 Header Files and libraries
  • 从Scratch语言到C语言
  • Hello, You
  • 类型 Types
    • 格式代码
    • 数据类型
    • CS50手册 CS50 manual pages
  • 条件语句 Conditionals
  • 运算符 Operators
  • 变量 Variables
  • Compare.c
  • Agree.c
  • 循环 Loops和meow.c
    • while循环句
    • for 循环句
  • 函数 Function
    • do while 循环句
  • 正确性、设计、风格
  • 马里奥
  • 注释 Comments
  • 关于运算符的更多信息
  • 截断 Truncation

回顾与学习重点


回顾

  • 在上一节课中,我们了解了 Scratch,一种可视化编程语言。
  • 事实上,当您学习如何编程任何编程语言时,Scratch 中介绍的所有基本编程概念都将被利用。Scratch 中的函数条件循环变量是您可以在任何编程语言中找到的基本构建块。
  • 回想一下,机器只能理解二进制。在人类编写源代码source code(人类可读的计算机指令列表)的地方,机器只能理解我们现在可以称之为机器代码 matchine code的东西。该机器代码是产生所需效果的 1 和 0 的模式。
  • 事实证明,我们可以使用一种非常特殊的软件(称为编译器 )将源代码转换为机器代码。今天,我们将向您介绍一个编译器,它允许您将编程语言 C 的源代码转换为机器代码。

学习重点

  • 今天,除了学习如何编程之外,您还将学习如何编写调用源代码.

  • 重点讨论通过源代码将某种类型的输入转化成输出

    在这里插入图片描述

    • 必备编译器工具: VS code

Hello, world


  • 我们将使用三个命令来编写、编译和运行我们的第一个程序:

    code hello.c
    make hello 
    ./hello
    
    
    • 第一个命令代码 code hello.c 创建 一个新文件(将源代码转译为机器码)并允许我们键入该程序的指令。

    • 第二个命令 make hello 根据我们的 C 语言的指令 编译make 文件, 并创建一个名为hello的可执行文件。

    • 最后一个命令 ./hello 运行名为hello的程序。

  • 现在, 我们可以通过在终端窗口中键入code hello.c 来用 C语言构建您的第一个程序。

    • 请注意,我们特意将整个文件名小写并包含 .c 扩展名。然后,在出现的文本编辑器中,编写代码如下:

      /* 建立一个 Hello world 程序 */
      #include <stidio.h>
      int main(viod)
      { 
          printf("hello, world\n");
      }
      
      

    ⚠️ 请注意,上面的每个字符都有其用途。如果输入错误,程序将无法运行!

    • printf 是一个可以输出一行文本的函数。
    • 在终端窗口中单击后退,您可以通过执行 make hello 来编译代码。
      • 请注意,我们省略了 .cmake 是一个编译器,它将查找我们的 hello.c 文件并将其转换为一个名为 hello 的程序。(如果执行此命令没有错误,则可以继续。如果没有,请仔细检查您的代码以确保其与上述内容匹配。)
    • 现在,键入 ./hello,您的程序将执行说 hello, world
  • 注意! 此刻左上侧的文件资源管理器。您会注意到,现在有一个名为 hello.c 的文件和另一个名为 hello 的文件。

    • hello.c 能够被编译器读取的源代码, 存储在云端某处的文件。
    • hello 是一个可执行文件,您可以运行它,但编译器无法读取。

头文件和库


头文件header files 与 库 Libraries

  • 任何以 .h 为结尾的文件,称之为 头文件 header files.
  • 如果代码初始缺失头文件的命令, 则无权访问库libraries*(图书馆)*
    • 库是某程序员为您所编写的代码合集,从而您可以通过头文件再次访问库.
  • <stdio.h> 全名 Standard io.h, 在这库中我们可以调用printf函数以及许多其他的函数, 这是我们可以在自己的代码中使用它们.
    • ⚠️ io.h 代表 I/O头文件, 囊括了C语言编程领域的文档.

从Scratch 语言到C 语言


  • 在 Scratch 中,我们利用 say块 在屏幕上显示任何文本。

    在这里插入图片描述

  • 我们在在CS50.h的的库中, 已经调用了这个函数. 一个名为 printf 的函数可以做到这一点。

  • 请注意,调用了 printf 函数。传递给 printf 的参数是 hello, world\n。代码语句用 ;.

    printf("hello, world\n")
    
  • 代码中出现错误很常见。按如下方式修改您的代码:

    // \n is missing
    #include <stidio.h>
    int main(viod)
    {
        printf("hello, world");
    }
        
    

    ⚠️ 请注意,调用换行\n 占位符现在不见了。

    • 在终端窗口中,运行 make hello。在终端窗口中输入 ./hello,您的程序是如何更改的?这个 \ 字符称为转义字符 ,它告诉编译器 \n 是调用换行(转义符号)的特殊指令。
  • 您还可以使用其他转义字符

    \n          /* 建立新的行列 */
    \r         /* 光标移动到行首 */
    \"        /* 印刷出双引号 */
    \'       /* 印刷出单引号 */
    \\      /* 印刷出反斜杠 */
    
    
  • 将程序恢复到以下状态:

    // A program that says hello to the world 
    #include <stdio.h>
    int main(viod)
    {
        printf("hello, world\n")
    }
    

    请注意, ;\n 已恢复。

Hello, You


在这里插入图片描述

❓ 回想一下,在 Scratch 中,我们可以用蓝色的 ask区块询问用户“你叫什么名字?”,获取用户名字后更具交互性的反馈用户“你好, (用户名)”。而在C语言中我们该如何操作呢?

  • get_string 函数用来获取用户的文本字符串: 字符、单词、句子、段落…

  • answer变量来储存ask函数块的返回值, 将返回同等类型的函数(变量)给return语句

  • 在 C 语言中,修改代码如下:

    • get_string函数用于从用户那里获取 string 字符串的变量,然后answer 将变量传返回给printf函数.
    • 然后, 在终端窗口中再次运行make hello. 注意, 出现大量错误。
    // get_string and printf with incorrect placeholder
    
    #include <stdio.h>
    
    int main(void)
    {
        string answer = get_string("What's your name? ");
        printf("hello, answer\n");
    }
    
  • 查看错误,编译器string 无法与get_string 识别. 我们必须通过添加一个名为cs50.h 的头文件以此授权编译器能够再次访问<cs50.h>的库.

    • 此外, 此外,我们注意到并answer没有按预期提供变量。请按如下方式修改代码:

      // get_string and printf with %s
      
      #include <cs50.h>
      #include <stdio.h>
      
      int main(void)
      {
          string answer = get_string("What's your name? ");
          printf("hello, %s\n", answer);
      }
      

      get_string函数用于从用户那里获取字符串。然后,answer将变量传递给printf函数。%s告诉printf函数准备好接收文本字符串**string。**

      • string字符串: 仅仅指文本, 无论它是零个还是多个字符.
      • %s: 是一个称为***格式代码*** 的***占位符***,它告诉printf函数准备接收stringanswerstring传递给 的%s
  • 现在,make hello再次在终端窗口中运行程序,输入 即可运行./hello。程序会询问您的姓名,然后按照预期说“hello”,并附加上您的名字。

类型


格式代码 format codes

%c
%f
%i        /* %i用于 int/整数的 变量 */
%li
%s.       /* %s用于string变量 */
  • printf允许使用多种格式代码/占位符。以下是本课程中可能用到的代码(非完整列表):
    • 您可以在手册页上找到更多信息。

数据类型 Data types

  • 这些格式代码对应于 C 中可用的许多数据类型:
  • 在本课程中,我们将使用 C 的许多可用数据类型。
bool            /* 布尔值: T or F */
char           /* 单个的字符, 而不是完整的短语或句子 eg: y/n */
                ⚠️  在C语言中, 当使用单个字符的时候用‘ ’单引号      
float         /* 双精度数和浮点数, 带有小数点的实数, 等同于分数 */
int          /* 整数 */
long         /* 比默认输入的整数更大的整数 */
string       /* 一串字符 */
...

CS50 手册页

  • CS50 有自己的库,名为cs50.h . 其中包含了许多函数,可以在您开始使用C语言时提供辅助:
get_char
get_double
get_float
get_int        /* 将数值向下取整为最接近的整数 */
get_long
get_string   /* 获取文本字符串 */
  • 接下来在您的程序中使用这个库。
    • 您可以在手册页上阅读有关此库的所有功能。手册页提供了一种更好地理解各种命令的功能及其工作原理的方法。

条件语句 Conditionals


  • 在 Scratch 中使用的另一个基础块是条件语句Conditionals

    • 例如,如果 x > y,你可能想执行某件事。此外,如果该条件不满足,你可能想执行其他操作。
  • 我们来看几个来自 Scratch 的例子.

    • 在 C 语言中,可以按如下方式比较两个值:

      // Conditionals that are mutually exclusive
      
      if (x < y)
      {
          printf("x is less than y\n");
      }
      else
      {
          printf("x is not less than y\n");
      }
      

    注意,如果x < y,则会出现一种结果。如果x不小于y,则会出现另一种结果。

    • 同样,我们可以规划三种可能的结果:

      // Conditional that isn't necessary
      
      if (x < y)
      {
          printf("x is less than y\n");
      }
      else if (x > y)
      {
          printf("x is greater than y\n");
      }
      else if (x == y)
      {
          printf("x is equal to y\n");
      }
      

    请注意,并非所有这些代码行都是必需的。我们如何才能消除上面不必要的计算呢?

    • 您可能已经猜到我们可以按如下方式改进此代码:

运算符 Operators



 =
 <
 <=          /* 小于或等于 */
 >
 >=          /* 大于或等于 */
 ==          /* 等于 */
 !=          /* 不等于 */
 %          /* 剩余部分 */
 /          /* 除法 */
 *          /* 乘法 */
 -          /* 减法 */
 +         /* 加法 */
 
 ...
  • 运算符是指编译器支持的数学运算。在 C 语言中,这些数学运算符包括:
  • 单个 “=” 是赋值运算符, 将代码从右到左赋于返回值的意思
    • ❓那如果要表达 “平等,相等” 这一概念, 则用“==“

      // Compare integers
      
      if (x < y)
      {
          printf("x is less than y\n");
      }
      else if (x > y)
      {
          printf("x is greater than y\n");
      }
      else
      {
          printf("x is equal to y\n");
      }
      

      注意最后的语句是如何被替换的else

变量 Variables


  • 在 C 语言中,您可以按如下方式为一个int或整数赋值:
int counter = 0;

注意, counter如何为类型为int的变量分配0值.

  • 也可以通过 C 语言编程来将counter +1,如下所示:
counter = counter + 1;

注意如何1将添加到的值中counter

  • 这也可以表示为:
counter += 1;
  • 再进一步简化为:
counter++;

注意如何++使用来加 1。

  • 您还可以按counter如下方式减去一个:
counter--;

请注意, 如何将1值从counter中删除。

  • 注意, 变量只存在于他们所存在的{ }范围内. 所以必须要在其函数最外层(一个范围外)提前声明变量, 然后在其他地方初始化它(定义它).
    • 声明变量, 不赋予它任何值
    • 在{ 赋值 }

Compare.c


  • 利用有关如何为变量赋值的新知识,您可以编写第一个条件语句。
  • 在终端窗口中,键入code compare.c 并编写如下代码:
code compare.c
  • 并编写如下代码:

#include <cs50.h>
#include <stdio.h>

int main(void)
{
    // Prompt user for integers
    int x = get_int("What's x? ");
    int y = get_int("What's y? ");

    // Compare integers
    if (x < y)
    {
        printf("x is less than y\n");
    }
}

注意,我们创建了两个变量,一个int名为 或整数x,另一个名为y。它们的值由get_int函数填充。

  • make compare您可以在终端窗口中执行 ,然后执行 来运行代码./compare。如果收到任何错误消息,请检查代码中是否有错误。

  • 流程图是检查计算机程序运行方式的一种方式。这类图表可以用来检查代码的效率。

    • 通过流程图检查该程序,您可以看到我们的代码设计决策的效率。

    在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

  • 查看上述代码的流程图,我们可以注意到许多缺陷。

    • 我们可以通过如下编码来改进您的程序:
    #include <cs50.h>
    #include <stdio.h>
    
    int main(void)
    {
        // Prompt user for integers
        int x = get_int("What's x? ");
        int y = get_int("What's y? ");
    
        // Compare integers
        if (x < y)
        {
            printf("x is less than y\n");
        }
        else if (x > y)
        {
            printf("x is greater than y\n");
        }
        else
        {
            printf("x is equal to y\n");
        }
    }
    

    注意,所有可能的结果都已考虑在内。

    Agree.c


  • 考虑另一种称为的数据类型char,我们可以通过在终端窗口中输入code agree.c来启动一个新程序。

    • 其中 string是一系列字符, 使用 “ ”; char是单个字符, 使用 ‘ ’.
  • 在文本编辑器中,编写代码如下:

/* 与小写字符比较 */
#include <cs50.h>
#include <stdio.h>

int main(void)
{
    /* 提示用户选择同意与否? */
    char c = get_char("Do you agree? ");

    /* 核实是否达成一致 */
    if (c == 'y')
    {
        printf("Agreed.\n");
    }
    else if (c == 'n')
    {
        printf("Not agreed.\n");
    }
}

此外,注意,它==确保某个字符等于 另一个字符,而在 C 语言中,单个等号的作用则截然不同。您可以通过在终端窗口中输入make agree,然后输入来测试您的代码./agree

  • 我们还可以拓展程序输入大写和小写字符:
#include <cs50.h>
#include <stdio.h>

int main(void)
{
  /* 提示用户选择同意与否? */
    char c = get_char("Do you agree? ");

    /* 核实是否达成一致 */
    if (c == 'y')
    {
        printf("Agreed.\n");
    }
    else if (c == 'Y')
    {
        printf("Agreed.\n");
    }
    else if (c == 'n')
    {
        printf("Not agreed.\n");
    }
    else if (c == 'N')
    {
        printf("Not agreed.\n");
    }
}
  • 请注意,尽管它提供了额外的选项。然而,这并不是高效的代码。
/* 运用新的逻辑运算符 */

#include <cs50.h>
#include <stdio.h>

int main(void)
{
    /* 提示用户选择同意与否? */
    char c = get_char("Do you agree? ");

     /* 核实是否达成一致 */
    if (c == 'Y' || c == 'y')
    {
        printf("Agreed.\n");
    }
    else if (c == 'N' || c == 'n')
    {
        printf("Not agreed.\n");
    }
}

请注意,||意味着

循环Loops 和 meow.c


在这里插入图片描述

  • 我们还可以在 C 程序中使用 Scratch 中的循环构建块。
  • 在终端窗口中,键入code meow.c并编写如下代码:
/* 运行更好的设计 */

#include <stdio.h>

int main(void)
{
    printf("meow\n");
    printf("meow\n");
    printf("meow\n");
}

注意,这符合预期,但还有更好的设计空间。代码一遍又一遍地重复。

  • 我们可以通过如下修改您的代码来改进我们的程序:
/* 再次精进设计 */

#include <stdio.h>

int main(void)
{
    int i = 3;             /* 将整数初始化为3 */
    while (i > 0)         /* i是否大于0? */
    {
        printf("meow\n");
        i--;
    }
}

注意,我们创建了一个int计数器, 调用函数i,并初始化赋值为3。然后,我们创建一个**while循环**,运行条件是i > 0然后在每次迭代后递减,直到i不再大于0为止。

  • while循环句

    在C语言中,while循环是一种基本的循环结构,它允许程序重复执行一段代码,只要指定条件为真, 就会重复执行

    • while循环最适合在不确定循环次数,但知道循环的终止条件时使用。如果循环条件一开始就是假的,循环体可能一次都不会执行。
      • 执行顺序:
      1. 首先检查条件
      2. 如果条件为真,执行循环体
      3. 循环回到步骤1继续检查条件
      4. 如果条件为假,跳过循环体继续执行后面的代码

类似地,我们可以通过修改代码来实现排序1-3的计数,如下所示:

// Print values of i

#include <stdio.h>

int main(void)
{
    int i = 1;
    while (i <= 3)
    {
        printf("meow\n");
        i++;
    }
}

注意我们的计数器i是如何从 1开始的。每次循环运行时,它都会将计数器+1。一旦计数器大于3,它就会停止循环。

  • 一般来说,在计算机科学中,我们从0开始计数。最好将代码修改如下:
// Better design

#include <stdio.h>

int main(void)
{
    int i = 0;
    while (i < 3)
    {
        printf("meow\n");
        i++;
    }
}

注意, 我们现在从0开始数。

  • for循环句

    除了while循环之外,C语言中还有for循环,这种循环结构在执行次数已知的情况下特别有用。

    • for循环的基本语法包含三个部分:初始化、条件检查和更新。

      /* 使用for循环的更优设计 */
      
      #include <stdio.h>
      
      int main(void)
      {
          for (int i = 0; i < 3; i++)
          {
              printf("meow\n");
          }
      }
      

      注意, for循环的三个参数组成部分:

      • 初始化:int i = 0 - 在循环开始前使计数器从零开始
      • 条件:i < 3 - 每次循环迭代前要检查的条件
      • 更新:i++ - 每次指示循环运行时+1。

      for循环比之前的while循环更简洁,因为它将所有控制逻辑放在了一行中。

  • 我们甚至可以使用以下代码永远循环:

/* 无限循环 */

#include <cs50.h>
#include <stdio.h>

int main(void)
{
    while (true)
    {
        printf("meow\n");
    }
}

请注意,这种true情况始终存在。因此,代码将始终运行。运行此代码后,您将失去对终端窗口的控制。您可以通过敲击control-C键盘来中断无限循环。

函数 Function


  • 虽然我们稍后会提供更多指导,但您可以按如下方式在 C 中创建自己的函数:
    • **初始值void**表示函数不返回任何值。(void)表示没有向函数提供任何值。
void meow(void)
{
    printf("meow\n");
}
  • 该函数可以在主函数中使用,如下所示:
// Abstraction

#include <stdio.h>

void meow(void);

int main(void)
{
    for (int i = 0; i < 3; i++)
    {
        meow();
    }
}

// Meow once
void meow(void)
{
    printf("meow\n");
}

注意, 如何meow使用指令调用该函数meow()。这是可能的,因为该meow函数定义在代码的底部,并且该函数的原型 在代码的顶部以void meow(void) 的形式提供声明。

  • 您的meow函数可以进一步修改以接受输入:
//带有参数的抽象化指令

#include <stdio.h>

void meow(int n);

int main(void)
{
    meow(3);
}

// 设定猫叫的次数
void meow(int n)
{
    for (int i = 0; i < n; i++)
    {
        printf("meow\n");
    }
}

请注意,原型已更改为,void meow(int n)以显示meow接受int作为其输入。

  • 此外,我们可以获取用户输入:
/* 加入用户输入 */

#include <cs50.h>
#include <stdio.h>

void meow(int n);

int main(void)
{
    int n;
    do
    {
        n = get_int("Number: ");
    }
    while (n < 1);
    meow(n);
}

/* 需要“meow”几次? */
void meow(int n)
{
    for (int i = 0; i < n; i++)
    {
        printf("meow\n");
    }
}

请注意,get_int用于从用户那里获取一个号码。n传递给meow

  • 我们甚至可以测试以确保用户提供的输入是正确的:
/* 添加返回值 */

#include <cs50.h>
#include <stdio.h>

int get_positive_int(void);
void meow(int n);

int main(void)
{
    int n = get_positive_int();
    meow(n);
}

// Get number of meows
int get_positive_int(void)      /* 获取一个正整数 */
{
    int n;                     /* 提前声明int n */
    do
    {
        n = get_int("Number: ");
    }
    while (n < 1);
    return n;
}

/* Meow some number of times */
void meow(int n)              /* 创建一个没有输出的函数, 副作用是表示其存在 */
{
    for (int i = 0; i < n; i++)
    {
        printf("meow\n");
    }
}

请注意,一个名为get_positive_int 的新函数会在n < 1 时, 再次要求用户输入一个整数。获取正整数后,该函数将return n返回到main函数。

  • do while 循环

    do while 循环它保证循环体至少会执行一次,无论条件是否为真。

    • 基本语法:

      do
      {
          // 循环体 - 这里的代码至少会执行一次
      } 
      while (condition); // 注意这里有分号
      
    • 执行顺序:

      1. 首先执行循环体内的代码
      2. 然后检查条件
      3. 如果条件为真,返回到步骤1继续执行循环体
      4. 如果条件为假,退出循环
    • 适用场景:

      • 当你需要至少执行一次循环体时
      • 当你需要在条件检查前先获取用户输入时
    • 与普通while循环的区别:

      • while循环可能一次都不执行(如果条件一开始就是假的)
      • do while循环至少执行一次,然后再检查条件

    在前面的代码示例中,do while循环被用来确保用户输入的是正整数,如果用户输入的数小于1,循环会继续要求用户输入,直到得到一个正整数为止。

正确性、设计、风格


  • CS50的编程环境中, 这3个命令行工具将会评估您的代码:
    • 首先,正确性是指“代码是否按预期运行?”您可以使用检查代码的正确性check50
    • 其次,设计是指“代码设计的怎么样?”您可以使用来评估代码的设计design50
    • 最后,风格是指“代码的美观度和一致性如何?”您可以使用来评估代码的风格style50

马里奥


  • 我们今天讨论的所有内容都集中在您作为新兴计算机科学家的工作的各个组成部分上。以下内容将帮助您解决此类课程的一般问题集:如何处理与计算机科学相关的问题?

  • 想象一下,我们想要模拟游戏超级马里奥兄弟的视觉效果。考虑到图中的四个问题块,我们如何创建大致代表这四个水平块的代码?

    在这里插入图片描述

    • 在终端窗口中,输入code mario.c并编码如下:

      /* 如何使用循环打印一行4个问号砖块 */
      
      #include <stdio.h>
      
      int main(void)
      {
          for (int i = 0; i < 4; i++)
          {
              printf("?");
          }
          printf("\n");
      }
      
  • 类似地,我们可以应用相同的逻辑来创建三个垂直块。

    在这里插入图片描述

    /* 如何使用循环打印三块垂直砖块 */
    
    #include <stdio.h>
    
    int main(void)
    {
        for (int i = 0; i < 3; i++)
        {
            printf("#\n");
        }
    }
    
  • 如果我们想结合这些想法来创建一个三乘三的块组怎么办?

    在这里插入图片描述

    我们可以按照上面的逻辑,结合同样的想法。修改代码如下:

    /* 使用嵌套循环打印一个 3 行 3 列的砖块网格 */
    
    #include <stdio.h>
    
    int main(void)
    {
        for (int row = 0; row < 3; row++)
        {
            for (int column = 0; column < 3; column++)
            {
                printf("#");
            }
            printf("\n");
        }
    }
    

    注意,一个循环嵌套在另一个循环中。第一个循环定义要打印的垂直行(row)。每行打印三列。每行结束后,打印一行。

  • 如果我们想确保区块数量恒定,即不可更改,该怎么办?修改代码如下:

    /* 使用常量通过嵌套循环打印一个 3×3 的砖块网格 */
    
    #include <stdio.h>
    
    int main(void)
    {
        const int n = 3;
        for (int i = 0; i < n; i++)
        {
            for (int j = 0; j < n; j++)
            {
                printf("#");
            }
            printf("\n");
        }
    }
    

    注意,n现在是一个常量。它永远不能改变。

    • 常量 constants
      • 如果变量的值永远不会改变, 则可以使用常量.
  • 正如本讲座前面所讲的,我们可以功能抽象成函数。考虑以下代码:

/* 请注意如何通过新函数完成一行的打印 */

#include <stdio.h>

void print_row(int width);          /* 创建一个没有输出的函数, 副作用是表示其存在 */
  
int main(void)
{
    const int n = 3;
    for (int i = 0; i < n; i++)
    {
        print_row(n);
    }
}

void print_row(int width)
{
    for (int i = 0; i < width; i++)
    {
        printf("#");
    }
    printf("\n");
}

comment


  • 注释是计算机程序的基本部分,您可以在其中为自己以及可能与您合作编写代码的其他人留下解释性说明。

  • ⚠️ 您为本课程创建的所有代码都必须包含详细的注释。

  • 通常,每条注释只有几句话或更多,帮助读者了解特定代码块中发生的事情。此外,这些注释还可以在您需要修改代码时起到提醒作用。

  • 注释是指先将注释添加//到代码中,然后再添加注释。请按如下方式修改代码以集成注释:

    // Helper function
    
    #include <stdio.h>
    
    void print_row(int width);
      
    int main(void)
    {
        const int n = 3;
    
        // Print n rows
        for (int i = 0; i < n; i++)
        {
            print_row(n);
        }
    }
    
    void print_row(int width)
    {
        for (int i = 0; i < width; i++)
        {
            printf("#");
        }
        printf("\n");
    }
    

    请注意, 每条评论都是以 开头的//

关于运算符的更多信息


  • 您可以用 C 语言实现一个计算器。在您的终端中,键入code calculator.c并编写如下代码:

    // Addition with int
    
    #include <cs50.h>
    #include <stdio.h>
    
    int main(void)
    {
        // Prompt user for x
        int x = get_int("x: ");
    
        // Prompt user for y
        int y = get_int("y: ");
    
        // Add numbers
        int z = x + y;
    
        // Perform addition
        printf("%i\n", z);
    }
    

    请注意该函数是如何get_int两次从用户那里获取整数的。一个整数存储在int名为x 的变量中。另一个整数存储在int名为y 的变量中。总和存储在z 中。然后,该printf函数打印z 的值,由符号%i 指定。

  • 我们还可以将数字加倍:

    // int
    
    #include <cs50.h>
    #include <stdio.h>
    
    int main(void)
    {
        int dollars = 1;
        while (true)
        {
            char c = get_char("Here's $%i. Double it and give to next person? ", dollars);
            if (c == 'y')
            {
                dollars *= 2;
            }
            else
            {
                break;
            }
        }
        printf("Here's $%i.\n", dollars);
    }
    

    运行这个程序,dollars出现了一些看似错误的地方。这是为什么呢?

    • C 语言的缺点之一是它管理内存过于简单。虽然 C 语言提供了对内存使用方式的强大控制力,但程序员必须非常警惕内存管理的潜在陷阱。

    • 类型是指变量中可以存储的数据。例如, char被设计为容纳单个字符,例如a2

    • 类型非常重要,因为每种类型都有特定的限制。

      • 例如,由于内存限制,一个变量的最大值int可以是4294967295。如果你尝试计算一个int更大的值,就会导致整数溢出integer overflow,导致该变量存储错误的值。
      • 计算机、电话、其他任何电子设备的内存量是有限的, int 通常使用32位.

      在这里插入图片描述

    • 位数限制了我们可以数的高低。

    • 这可能会对现实世界产生灾难性的影响。

  • 我们可以通过使用一种称为long的数据类型来纠正这个问题。

// long: 运行此代码将允许非常高的金额。

#include <cs50.h>
#include <stdio.h>

int main(void)
{
    long dollars = 1;
    while (true)
    {
        char c = get_char("Here's $%li. Double it and give to next person? ", dollars);
        if (c == 'y')
        {
            dollars *= 2;
        }
        else
        {
            break;
        }
    }
    printf("Here's $%li.\n", dollars);
}

  • 您在本课程中可能接触到的数据类型包括:
bool            /* 布尔值表达式: T || F */
char           /* 单个的字符, 而不是完整的短语或句子 eg: y || n; a || c*/
              ⚠️  在C语言中, 当使用单个字符的时候用‘ ’单引号      
double        /* 比浮点数位数更多的浮点值 */

float         /* 带有小数点的实数, 等同于分数 */
int           /* 整数, 达到一定大小或位数的整数, 通常是32位 */
long          /* int的加长版本,具有64位的整数,因此它们的计数可以高于 int*/
string        /* 一串字符 */
...

截断 截词检索 Truncation


  • 使用数据类型时可能出现的另一个问题是截断。

    // Division with ints, demonstrating truncation
    
    #include <cs50.h>
    #include <stdio.h>
    
    int main(void)
    {
        // Prompt user for x
        int x = get_int("x: ");
    
        // Prompt user for y
        int y = get_int("y: ");
    
        // Divide x by y
        printf("%i\n", x / y);
    }
    

    在 C 语言中,整数除以整数总是会得到整数。因此,上述代码通常会导致小数点后的任何数字都被丢弃。

  • 可以通过以下方法解决float

    // Floats
    
    #include <cs50.h>
    #include <stdio.h>
    
    int main(void)
    {
        // Prompt user for x
        float x = get_float("x: ");
    
        // Prompt user for y
        float y = get_float("y: ");
    
        // Divide x by y
        printf("%.50f\n", x / y);
    }
    

    请注意,这解决了我们的一些问题。然而,我们可能会注意到程序提供的答案不够精确。

  • 浮点不精度说明计算机计算数字的精度是有限的。

  • 在编码时,要特别注意所使用的变量类型,以避免代码中出现问题。

总结


在本课中,你学习了如何将 Scratch 中学习到的基础知识应用到 C 编程语言中。你学习了……

  • 如何用 C 创建您的第一个程序。
  • 关于 C 语言本身预定义的函数。
  • 如何使用变量、条件和循环。
  • 如何创建自己的函数来简化和改进您的代码。
  • 如何从三个方面评估您的代码:正确性、设计和风格。
  • 如何将注释集成到您的代码中。
  • 如何利用类型和运算符以及您的选择的含义。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值