C Note 20210622

extern

  • 让编译器不将声明提升为定义。

const

  • 常量声明

volatile

  • 防止编译器优化代码。单片机可能会比较常用。

register

  • 寄存器变量,将变量直接存储到寄存器中,有存储失败的可能。
  • 寄存器变量没有地址。
  • 在极端需要效率的情况下使用。应用开发使用频率低。

字符串

  • “字符串都用双引号,并会在末尾加上一个\0。”
  • ‘A’ <- 字符(char)都用单引号。
  • ‘a’ != “a”
  • printf()通过'\0’来识别输入结束的位置。
  • char str[20] = “Hello World”; //会自动补充一个\0。
  • char str[20] = {‘H’, ‘e’, ‘l’, ‘l’, ‘o’}; //后面不会补充\0,printf()可能会打印出意想不到的东西。 //不准确,参考0629的笔记

scanf()

  • scanf("%d %d %d", &a, &b, &c); //输入1 2 3将会分别存入a b c变量中,格式化用户的输入。
    #include <stdio.h>

    int main(void)
    {
            //char a, b, c;
            //scanf("%c %c %c", &a, &b, &c);
            //printf("a = %c\n b = %c\n c = %c\n", a, b, c);
            char a[5];
            scanf("%s", a);
            printf("a = %s\n", a);
            return 0;
    }

虽然printf能打印出超过数组长度的内容,但会引发安全问题。

aaaaaaaaa
a = aaaaaaaaa
*** stack smashing detected ***: terminated
fish: './scanf.out' terminated by signal SIGABRT (Abort)

scanf() 需要传入地址,对于普通变量需要使用取地址符。然而数组名本身就代表其地址。
scanf() 碰到 空格换行 会自动终止。

自增/自减

++a  //先自增,再取值。  
a++ //先取值。再自增。

具体的区别应该在汇编层面有更清晰的体现。
参考: 从汇编的角度看前自增和后自增的区别
不应在编程中体现这种特性。

类型转换

隐式类型转换

  • 占用内存小的类型,向占用内存大的类型转换。
  • 由赋值产生的转换
 int r = 3;
 float s = 3.14 * r * r; 

eg:

  • (3.14 * r * r)double 类型,通过赋值给一个 float 类型的变量,被转换为 float 类型。

强制类型转换

float a = 3.6;
int b = 4;
int c = (int)a;
c = (int)(a * b);

函数调用期间,传值使用。

int * p = (int *)malloc(100);

分配100字节的内存,强制转换为(int *)类型,赋值给 *p。

其他

  • char * 是一种数据类型。
  • 高-> 10101010 <- 低
  • whiledo while 的区别是,do while无论如何都会先执行一次循环体。
do {
    循环体 //无论如何都会先被执行一次。
} while(循环条件);
Avatar photo 心有所向,日复一日,必有精进。 Twitter Tweet