Interview--C Language

C Language

汇编语言

汇编语言是直接面向处理器的、面向机器的程序设计语言,属于低级语言

不同的处理器有不同的汇编语言语法和编译器,编译的程序无法在不同的处理器上执行,缺乏可移植性

C语言特点

允许直接访问物理地址,能进行位操作,实现汇编语言的大部分功能,可直接对硬件进行操作,兼有高级和低级语言的特点

目标代码质量高,程序执行率高,只比汇编程序生成的目标代码效率低10%-20%

程序可移植性好,基本上不做修改就能用于各种型号的计算机和各种OS

C语言结构

hello.c –> 预处理器cpp –> hello.i –> 编译器ccl –> hello.s(汇编程序 文本) –> 汇编器AS –> hello.o(可重定位目前程序 文本) –> 链接器LD –> 可执行位目标程序 文本

预处理器执行以#开头的命令,类似于编辑器,可以给程序添加和修改内容

常量命名

宏定义

#define 后面无分号

标识符

  • 区分大小写
  • 标识符可以含有字母、数字和下划线,但是必须以字母或者下划线开头

格式化的输入输出

  • 两个%输出一个% – printf("%f%%", 1.) 输出 1.00000%

  • %m.nf m位,n位小数

  • 在寻找数的初始位置时,scanf 函数会忽略空白字符(包括水平符、制表符、换页符和换行符)

    1
    2
    3
    4
    5
    6
    # include <stdio.h>
    void main(){
    int num1, num2;
    scanf("%d%d", &a, &b);
    printf("%d\t%d\n", num1, num2);
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    input:
    12 78
    output:
    12 78
    input:
    12
    78
    output:
    12 78

表达式

  • 当操作数为整数和浮点数混合,结果为浮点数

  • 赋值运算符,向左看齐

    1
    2
    int i;
    i = 72.99f; /*i is now 72*/

运算符

优先次序:算术运算符 > 关系运算符 > 赋值运算符

(由高到低 依次减小)

自增自减 》+ -

一元逻辑 !

乘法类 */%

加法类 + -

关系运算符 > < >= <=

判等运算符 == !=

二元逻辑 && ||

赋值 = *= /= %= += -=

  • C89没有定义布尔值类型

    为了程序便于理解,可以定义宏

    1
    2
    #define TRUE 1
    #define FALSE 0
  • C99提供了_Bool类型

    _Bool flag;

    C99提供了一个新的头文件 <stdbool.h>, 可以写 bool flag;

  • 控制表达式:switch后边的表达式要求是整型,不能用浮点数和字符串

    case 常量表达式

    每个分支标号后可以跟任意数量的语句
    
    语句最后通常是break语句
    

循环

  • break & continue
    • break 语句从循环体跳出,提前结束循环,可以用在switch和循环中
    • continue 跳出本次循环,跳过循环体下面尚未执行的语句,进行下一次是否执行循环的判断,只能用在循环中

基本类型

  • int 32位,short int 16位, long int, long long int

  • 浮点类型:float单精度浮点数 32位,double双精度浮点数 64位,long double扩展精度浮点数

  • 字符型:’a’为97, ‘A’为65, ‘0’为48, ‘ ‘为32

  • char 8位

  • 字符处理函数:

    1
    2
    3
    #include <ctype.h>
    ch = toupper(ch);
    ch = tolower(ch);
  • 读写字符:

    scanf 函数不会跳过空白字符,为了强制scanf 函数在读入字符前跳过空白字符,需要加上一个空格

    1
    scanf(" %c",ch);

    对于单个字符的输入和输出,可以使用getchar()putchar() 函数来代替

    1
    2
    putchar(ch);
    ch = getchar();
  • sizeof 运算符

    确定存储空间类型所需要的空间大小

    sizeof(char) = 1

数组

  • 指定初始化 C99:
1
int a[15] = {[14] = 48, [9] = 7, [2] = 29};
  • 运算符sizeof可以确定数组的大小(字节数)

    Eg: int a[10], sizeof(a) = 40

    可以用sizeof来计算数组元素的大小,比如a[0]

    可以得到数组的长度,sizeof(a)/sizeof(a[0])

函数

  • 函数的定义,形式参数

  • 函数的调用,实际参数,将值复制给形式参数

    在函数执行过程中,对形式参数的改变不会影响实际参数的值,因为形式参数中包含的是实际参数值的副本

  • 可以在调用前先进行,函数声明

指针

指针 – 变量的地址,存放数据的内存地址

指针变量是存放变量地址的变量,用来指向另一个变量,是一种变量,该变量存放的数据就是内存地址

pointer -> 010100011 address of variable i, p指向i, 指向就是将变量的地址存放到指针变量中

* 表示指向关系,称为指针运算符,运算对象为地址

指针变量的定义和初始化
1
2
3
int a, *p1 = &a;
char s[10], *p2 = s; //指向数组首部
char x[5], *p3 = &x[2];

指针赋值,指针p与q指向相同的位置

函数的参数,指针类型作为参数的作用是将一个变量的地址传递给函数进行处理,数组名作为函数参数,传递的是地址而不是数值。

Eg:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
swap(int *q1, int *q2){
int temp;
temp = *q1;
*q1 = *q2;
*q2 = temp;
}
int main(){
int a, b, *p1, *p2;
scanf("%d%d", &a, &b);
p1 = &a, p2 = &b;
if(a < b)
swap(p1, p2);
printf(“\n%d,%d”,*p1,*p2);
}

指针和数组

  • 指针和加法

    p指向a[i],则p+j指向元素a[i+j]

    两个指针相减时,结果为指针之间的距离,以数组元素的个数为度量

    p++ = (p++)

  • 用数组名作为指向数组的第一个元素的指针

    1
    2
    *a = 7;
    *(a+1) = 12;

    a+1 和 &a[i] 等同,均表示指向数组a中元素i的指针

    *(a+1) 和 a[i] 等同,均表示数组a中的元素i自身

    快速处理多维数组,将二维数组初始化0

    1
    2
    for(p = &a[0][0]; p <= &a[ROWS-1][COLS-1]; p++)
    *p = 0;

字符串

  • 字面量的存储:当编译器遇到一个长度为n的字符串字面量时,给该字符串分配n+1个字节的内存空间,外加一个额外的空字符,用于标志字符串的结束,空字符是一个所有比特为0的字节,用转义序列\0 表示

    例如”abc” – “abc\0”

    1
    2
    char *p;
    p = "abc";
  • 字符串字面量 & 字符常量

    “a”是以指针表示的,’a’是以整数表示的

    char date[] = “June 14” – date为数组,存储的字符可以修改

    char *date = “June 14” – date为指针,date所指向的字符串字面量不能修改的

    char *p; 没有为字符串分配空间

  • 字符串输出:printf() ,puts()–会写一个额外的新行符

  • 字符串读取:

    • scanf("%s", str); str是指针,不必在str前面放置&运算符,当遇到scanf()时,该函数跳过空白,然后读入字符并存入str指向的空间,直至遇到一个空白字符
    • scanf()会存放一个空字符在字符串的后面
    • 新行符、空白和tab符,均导致scanf()停止读取
    • 要读取整行输入,可以使用gets()函数,特点:
      • 读取输入不会跳过开始的空白
      • 直到找到新行符才停止读入
      • 不存储新行符,而用空字符代替
  • 使用C字符串库

    #include<string.h>

    strcpy(char *s1, char *s2); copy

    size_t strlen(const char *s);

    strcat(char *s1, char *s2); concatenation

    int strcmp(const char *s1, char *s2); if (strcmp(str1, str2)<0) means str1<str2; (strcmp(str1, str2)<=0) means str1<=str2

  • 复制字符串

1
2
3
4
5
6
7
8
9
10
11
12
char *strcat(char *s1, const char *s2){
char *p = s1;
while(*p != '\0')
p++;
while(*s2 != '\0'){
*p = *s2;
p++;
s2++;
}
*p = '\0';
return s1;
}
  • 字符串数组:

    参差不齐的数据(ragged array),可以有不同长度的行,以便节省空间

    char *planets[] = {“Mercury”, “Venus”, “Earth”, “Mars”, “Jupiter”, “Saturn”, “Uranus”, “Neptune”, “Pluto”}

  • 命令行参数

    argc argument count

    argv argument vector

    argv[0] 指向程序名,argv[1]~argv[argc-1] 指向余下的命令行参数

编写程序

#include

#include \ 查找系统头文件所在的路径

#include “filename” 查找当前路径,然后查找系统头文件所在的路径