C语言知识点

第一部分:C语言知识点

1. C语言的官方标准

  • ANSI C / C89标准:1989年,美国国家标准协会(ANSI)发布了第一个官方标准(简称 C89标准 或 ANSI C)。
  • C99标准:1999年,国际标准化组织(ISO)和国际电工委员会(IEC)发布了C语言的新标准。
  • C11标准:2011年12月8日,国际标准化组织(ISO)和国际电工委员会(IEC)再次发布了C语言的新标准。

2. C语言程序的运行过程

  • 编译:编译是由编译器来执行的,主要做的是语法检查工作;将C源程序翻译成计算机能识别的0和1;编译会把.c后缀的文件生成.o后缀的目标文件。
  • 链接:将编译好的.o目标文件和C程序库函数组合在一起,生成可执行文件(即.exe后缀的文件)。
  • 运行:直接双击打开.exe文件

3. 变量

概念:是内存中的一片空间,用来存放经常变化的数据。

  • 代码示例1:
#include <stdio.h>

int main() {
    // 1.定义变量(即在内存中开辟一块空间,空间的大小跟定义的类型有关,空间的名字就是变量名)
    int age;// 这一行代码就在内存中开辟一块4个字节的存储区域,它名字叫age;这块存储区域是用来存放int类型的数据的
    // 2.初始化:变量第一次赋值称为初始化。
    age = 22; //这行代码是把22,放到名字为age的这块存储区域中
    return 0;
}
  • 代码示例2:
#include <stdio.h>

int main() {
    int a; // 定义一个变量:a是变量名,int是变量的类型
    // 定义一个变量,未初始化;a的值的可能性:1) 系统的数据;2) 上一个程序遗留的数据;3) 垃圾数。
    printf("a=%d\n", a); // a=1606422582,垃圾数据。
    // 初始化:就是清空(赋初值,0/NULL)的意思,清理一些垃圾数据。
    a = 10; // 将10保存到a中,第一次赋值相当于初始化
    a = 20; // 将20保存到a中,以后就叫给变量赋值
    int b = 30; // 定义变量的同时初始化
    printf("b=%d\n", b);
    return 0;
}
  • 变量类型:分为字符型char、整数型int、浮点型float/double、指针、结构、联合等类型。
  • 变量的作用域
    局部变量(内部变量):在函数的内部或者代码块的内部定义的变量。
  • 代码示例:
#include <stdio.h>

int main() {
    int age = 20;
    //代码块代表一个空间,与age的空间并列
    {//代码块开始
        int a = 5;
        printf("a=%d\n", a); //a=5
        int age = 25; //在代码块内部可以定义和代码块外部同名的变量
        printf("age=%d\n",age); //age=25;
    }//代码块结束(此时代码块内部所有的空间会释放)
    printf("age=%d\n", age);//age=20;
    return 0;
}
  • 变量分析题:(注意变量的作用域)


  • 变量的命名:命名需要符合标识符语法要求。
    ① 必须以 字母下划线 开头(注意:不能以数字开头)
    ② 包含 字母下划线数字
    ③ 大小写敏感的
    ④ 不能与 关键字 冲突
    ⑤ 标识符理论上讲,长度无限制,但太长了会被编译器截断

  • 变量的存储:
    ① 变量所占的存储空间(字节数):跟变量的类型和编译器环境有关。
    ② 变量存储单元的第一个字节的地址就是该变量的地址(详细地址/首地址)
    ③ 任何变量在内存中都是以二进制的形式存储:一个负数的二进制形式,其实就是对它的正数的二进制形式进行取反再加1。



  • 【了解】变量在内存中怎么储存?(变量为什么要有类型)
    ① 只要定义变量,系统就会开辟一块存储空间给我们的变量存储数据
    ② 越先定义的变量,内存地址越大(从字节地址最大的开始找)
    ③ 内存寻址是从大到小,高位放在高字节上,低位放在低字节上
    ④ 变量的地址就是变量所占的存储空间最小的字节地址(即首地址:&变量名称)
     计算机中最小储存单元是字节,每个字节都有一个地址。


4. 常量

  • "量"表示数据。常量,则表示一些固定的数据,也就是不能改变的数据。
  • 定义常量的方法:const int a=100;
  • 易错示例:
10.1;// 双精度 double
5.2f; //单精度 float(注意:与double类型进行区分,小数点后面有 f 才表示是 float 类型,否则是 double 类型)

// 字符型常量(易考点:要注意下面几种写法)
'a'; // 正确写法:占用一个字符
'ab'; // 错误写法:不是单个字符
'李'; // 错误写法:因为一个汉字占2个字符
'\n'; // 正确写法:因为转义字符,表示单个字符

// 字符串常量(注意:字符串常量结尾默认都有一个'\0')
"a"; // 占用两个字符,结尾有一个'\0';
"中国"; // 占用 4 + 1 = 5 个字符;一个汉字占用两个字符,'\0'占用一个字符

【掌握】常用ASCII值: 'A'== 65 、 'a' == 97 、 '0' == 48

5. printf 函数

  • printf函数称为格式输出函数,其关键字最末一个字母f即为“格式”(format)之意
  • 代码示例:
#include <stdio.h>

int main() {
    int hour = 2, minute = 6;
    printf("%d:%d\n", hour, minute); // 2:6
    // %02d 表示输出的数字宽度为2,如果宽度不够就用0补齐左边
    printf("%02d:%02d\n", hour, minute); // 02:06

    float value = 3.14f;
    // %f 默认会保留6位小数
    printf("%f\n", value);//3.140000
    // 指定保留多少位小数: %.nf, 其中n就是需要保留多少位小数
    printf("%.2f\n", value);//3.14
    return 0;

    /*
      知识点1:指定位宽
        %0nd:在%与d之间,0n,n表示输出的数字的宽度,如果不够就用0补齐左边【重点】
        %nd:在%与d之间n,n表示输出的数字的宽度,如果不够就用空格补齐左边
        %-nd:在%与d之间 -n,n表示输出的数字的宽度,如果不够就用空格补齐右边
    
      知识点2:指定位数
       %m.nf:在%与f之间,可以有m.n,m表示输出数字所占的宽度,m表示小数点后面的位数,如果不够会用空格补齐左边
   */
}
  • 格式控制符:


  • 其它知识点:

//  printf函数打印 % 字符要用 %% 才能打印
printf("5%%2=%d\n",5%2);//结果为:5%2=1

&是C语言中的一个地址运算符,可以用来获取变量的地址
&可以获取变量的地址,例如:&num
*可以根据地址数据找到变量,例如:*(&num)

6. scanf 函数

scanf函数是一个阻塞式函数,程序会停在scanf函数出现的地方,直到接收到数据才会执行后面的代码。

//  使用scanf接收用户从键盘上输入
scanf("%d", &a);//注意: 必须告诉scanf函数变量的详细地址, 才能存储用户输入的数据
//  %与d之间可以有数字n,这个n表示接受数据的宽度
scanf("%2d",&a);
  • scanf 函数要点:
    ① 键盘输入的数据与格式化字符串中的要匹配, 不匹配时scanf函数就会自动终止。
    ② scanf接收多个数据时,为了防止出错一般加一个分隔符(例如:逗号或空格)
    (空格、回车、Tab可以做%c除外的分隔符,因为空格、回车、Tab是字符)
    ③ 不能在scanf的格式化字符串末尾写上\n。
    比如:scanf("%d\n", &a); 这将导致scanf函数无法结束。


7. 运算符

  • 算术运算符:+、-、*、/、%
    【掌握】% 取模(取余)运算符的注意事项:
    ① 取模运算符的操作数只能是整数(5%3=2;)
    ② 余数的符号与最前面的被除数一致(-5%3=-2; 5%-3=2; -5%-3=-2)
    ③ 如果取模运算的左边小于右边, 那么结果就是左边(2%9=2;)
  • 自增自减写在前面和后面的区别:
    ① 如果++写在变量的前面, 那么会先将变量自增再用自增之后的结果参与运算
    ② 如果++写在变量的后面, 那么会先将变量的值参与运算再将变量自增
    ③ 总结一句话: ++在前, 先自增再运算, ++在后, 先运算再自增
 int b = ++a;  //等价于 a=a+1;  b=a;
 int b = a++; //等价于 b=a;  a=a+1;
//【掌握】运算规则:先左++,再赋值,最后右++。
  • sizeof()运算符:sizeof可以用来计算 一个变量一个常量 、或 一种数据类型 所占的内存字节数。
  • 代码示例:
#include <stdio.h>

int main() {
    char c='a';
    printf("%d, %d\n", sizeof(10), sizeof(c)); //4, 1
    printf("%d, %d\n", sizeof 10, sizeof c); //4, 1
    printf("%d\n", sizeof(int)); //4
    return 0;
}
  • 逻辑运算符:&& 逻辑与 、|| 逻辑或 、! 逻辑非
    【掌握】&& 和 || 都具有短路特征:如果前一个表达式能决定最终结果则不会计算后一个表达式。
  • 代码示例:
#include <stdio.h>

int main() {
    // 逻辑运算符 && 和 || 的短路特征
    int a=3,b=4,c=5,r;
    r=(a>b)&&(++b>c); // 因为 (a>b) 为假;所以 && 后面的表达式不管是真还是假,最终结果也一定是假。根据短路特征,&& 后面的表达式会自动忽略不参与计算。
    printf("%d,%d,%d,%d\n", a, b, c, r); //3, 4, 5, 0
    r=(a<b++)||(b<c++);
    printf("%d,%d,%d,%d\n", a, b, c, r); //3, 5, 5, 1

    // 非短路的逻辑运算符 & 和 |
    a=3;b=4;c=5;
    r=(a>b)&(b>++c);
    printf("%d,%d,%d,%d\n", a, b, c, r); //3, 4, 6, 0
    r=(a<b)|(b<c++);
    printf("%d,%d,%d,%d\n", a, b, c, r); //3, 4, 7, 1
    return 0;
}

8. 进制

  • 进制:是一种计数的方式,数值的表示形式
    ① 十进制:逢十进一 (如:13 == 1 * 10 + 3)
    ② 八进制:逢八进一 (如:15 == 1 * 8 + 5)
    ③ 二进制:逢二进一 (如:1101 == 1 * 2 * 2 * 2 + 1 * 2 * 2 + 0 * 2+ 1)
    ④ 十六进制:逢十六进一 (0 ~ 9 A ~ F d == 13)
  • 常见的进制转换
    10进制 转 2进制:除2取余法,把10进制数除以2,然后取得余数的序列,再倒序。
    例如:将十进制(97)转换为二进制数(1100001)

    2进制 转 10进制:所有位的位权相加:101=120+021+1*22
    2进制 转 16进制:4合1法。把一个二进制数,整数部分从右向左(小数部分从左向右)4位结合成1位,不足部分补0。

    16进制 转 2进制:1拆4法,16进制的1位拆成二进制的4位。

    2进制 转 8进制:3合1

第二部分:C语言编程练习

1. 加减乘除计算器

/**  加减乘除计算器 (提示:录入1+2输出1+2=3)*/
int test() {   
    int num1,num2; //定义两个变量,表示操作数
    char operator; //定义一个char类型变量,表示要进行操作
    printf("请按照如下格式录入(1 + 1)\n"); //提示用录入
    scanf("%d %c %d", &num1, &operator, &num2);
    int result;
    switch (operator) {
        case '+':
            result = num1 + num2;
            break;
        case '-':
            result = num1 - num2;
            break;
        case '*':
            result = num1 * num2;
            break;
        case '/':
            if (num2 == 0) {
                printf("除数不能为零\n");
                return 0;
            }
            result = num1 / num2;
            break;

        default:
            printf("你录入格式错误\n");
            break;
    }
    printf("%d %c %d = %d\n", num1, operator, num2, result);
    return 0;
}

2. 编写程序,要求从键盘键入n, 求 1/3+2/4+3/5+...+n-2/n的值

#include<stdio.h>

void main() 
{
    int n = 0;
    double sum = 0;
    scanf("%d", &n);

    for (int i = 3; i <= n; i++)
    {
        sum += (double)(i - 2) / i;
    }

    printf("%lf\n", sum);
}

3. 输入一个年份,判断该年是否为闰年,若为闰年则输出“yes”,否则输出“no”。

#include<stdio.h>

void main() 
{
    int year = 0;
    printf("请输入一个年份:");
    scanf("%d", &year);
    // 能被4整除,且不能被100整除;或者能被400整除
     if((year % 4 == 0 && year % 100 != 0) || year % 400 == 0){
        printf("yes\n");
    } else {
        printf("no\n");
    }
}

4. 从键盘输入3个数,将其从小到大排序后输出

#include<stdio.h>
#define ARR_LEN 3 // 数组长度为3

void main() 
{
    int arr[ARR_LEN] = { 0 };
    int temp = 0;

    // 读入三个数
    for (int i = 0; i < ARR_LEN; i++)
    {
        printf("请输入第%d个数的值:", i + 1);
        scanf("%d", &arr[i]);
    }

    // 排序
    for (int i = 0; i < ARR_LEN - 1; i++)
    {
        for (int j = 0; j < ARR_LEN - 1 - i; j++)
        {
            if (arr[j] > arr[j + 1])
            {
                temp = arr[j];
                arr[j] = arr[j + 1];
                arr[j + 1] = temp;
            }
        }
    }

    // 输出结果
    for (int i = 0; i < ARR_LEN; i++)
    {
        printf("arr[%d] = %d\n", i, arr[i]);
    }
}

5. 从键盘输入两个数,交换两个数的值,再输出至屏幕

#include<stdio.h>

void main() 
{
    int a = 0;
    int b = 0;
    int temp = 0;

    printf("请输入两个整数:");
    scanf("%d%d", &a, &b);

    printf("交换之前的值是:a=%d, b=%d\n", a, b);

    temp = a;
    a = b;
    b = temp;

    printf("交换后的值是:a=%d, b=%d\n", a, b);
}

6. 编写一个函数,通过指针实现两个数的交换

#include<stdio.h>

void swap(int *pa, int *pb)
{
    int temp = 0;
    temp = *pa;
    *pa = *pb;
    *pb = temp;
}

int main()
{
    int a = 3;
    int b = 5;
    int *pa = &a;
    int *pb = &b;
    void(*pswap)() = swap;

    // 交换之前
    printf("交换之前 a=%d, b=%d\n", a, b);

    // 交换
    pswap(pa, pb);

    // 交换之后
    printf("交换之后 a=%d, b=%d\n", a, b);

    return 0;
}

7. 输入一串字符,统计其中的字母、空格、数字及其他字符的个数

#include<stdio.h>
#define STR_LEN 100

int main()
{
    char str[STR_LEN] = { '\0' };
    int alpha = 0;
    int blank = 0;
    int digit = 0;
    int other = 0;

    // 输入一串字符
    printf("请输入一个字符串:\n");
    gets_s(str, STR_LEN);

    // 计算每种类型的字符的个数
    for (int i = 0; i < STR_LEN && str[i] != '\0'; i++)
    {
        if (('a' <= str[i] && str[i] <= 'z') || ('A' <= str[i] && str[i] <= 'Z'))
        {
            alpha++;
        }
        else if ('0' <= str[i] && str[i] <= '9')
        {
            digit++;
        }
        else if (str[i] == ' ')
        {
            blank++;
        }
        else
        {
            other++;
        }
    }

    // 输出统计的结果
    printf("字母有 %d 个\n空格有 %d 个\n数字有 %d 个\n其他有 %d 个\n", alpha, blank, digit, other);
    return 0;
}

8. 求最大公约数

/** 1.【掌握】直接遍历法 */
int maxCommonDivisor(int a, int b) {
    int max = 0;
    for (int i = 1; i <=b; i++) {
        if (a % i == 0 && b % i == 0) {
            max = i;
        }
    }
    return max;
}
/** 2.辗转相除法 */
int maxCommonDivisor(int a, int b) {
    int r;
    while(a % b > 0) {
        r = a % b;
        a = b;
        b = r;
    }
    return b;
}

// 扩展:如何求最小公倍数
// 最小公倍数 = (a * b)/最大公约数

9. 冒泡排序

冒泡排序是从小到大排序,可以形象的理解为:水中的气泡从下往上冒出,越往上气泡越大,即冒泡排序是从小到大排序。

/** 
 *   【冒泡排序】:相邻元素两两比较,比较完一趟,最值出现在末尾
 *   第1趟:依次比较相邻的两个数,不断交换(小数放前,大数放后)逐个推进,最值最后出现在第n个元素位置
 *   第2趟:依次比较相邻的两个数,不断交换(小数放前,大数放后)逐个推进,最值最后出现在第n-1个元素位置
 *    ……   ……
 *   第n-1趟:依次比较相邻的两个数,不断交换(小数放前,大数放后)逐个推进,最值最后出现在第2个元素位置 
 */
void bublleSort(int *arr, int length) {
    for(int i = 0; i < length - 1; i++) { //趟数
        for(int j = 0; j < length - i - 1; j++) { //比较次数
            if(arr[j] > arr[j+1]) {
                int temp = arr[j];
                arr[j] = arr[j+1];
                arr[j+1] = temp;
            }
        } 
    }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,980评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,178评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,868评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,498评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,492评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,521评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,910评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,569评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,793评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,559评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,639评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,342评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,931评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,904评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,144评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,833评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,350评论 2 342