从1960年的ALGOL 60 到1970年的BCPL再到1971年的B语言,编程也从计算机设计者的个人工作逐渐转变到专门的一项工作,C语言的发展,无疑给这个行业注入了核心,至此,C语言作为一门可以从底层控制用到用户界面的编程语言得到了广大编程工作者的支持。C语言作为计算机编程的核心语言,经历岁月洗礼,但其地位仍旧不可撼动。

从stm32单片机的控制到人工智能大模型的运行,C语言在其中发挥着不可或缺的作用,无数的高级语言也从C语言的肩膀上站起来。C语言,依旧是我们值得学习的编程语言。

一、关于数据

(一) 计算机存储的数据是怎么样的?

大部分人都知道,通用计算机都是基于二进制设计的(据说苏联曾经有三级制的),在二进制中,存在原码、反码、补码三种形式(这里不展开细节部分),而常见的英文、数字等就是通过ASCII码转换为数字存储在计算机中的。

(二) C语言的数据类型有哪些?

在C语言中,基本的有整型、浮点型、字符型三种类型,这三种分别可分为有符号和无符号两种,而整型还可分为长整型、短整型、双长整型,浮点型可分为单精度浮点型、双精度浮点型。而在C语言中,还有数组、指针等高级类型,数组是将一组基本类型相同的值放在一块连续的空间构成的,可以有多个维度(参考表格),而指针是一种指向数据地址的值,即指针就是数据的地址(参考按针眼穿针)。

(三) C语言中的量有哪些?

在C语言中,分为变量和常量,其中还有多种分类,如一次定义就不可改变的const常量,定义后空间不进行收回的static变量等

二、关于运算符

在C语言中,含有多种运算符,如下:

(一) 算术运算符(A=1,B=2)

运算符 描述 实例
+ 把两个操作数相加 A + B 将得到 3
- 从第一个操作数中减去第二个操作数 A - B 将得到 -1
* 把两个操作数相乘 A * B 将得到 2
/ 分子除以分母 B / A 将得到 2
% 取模运算符,整除后的余数 B % A 将得到 0
++ 自增运算符,整数值增加 1 A++ 将得到 2
自减运算符,整数值减少 1 A-- 将得到 0

(二) 关系运算符

运算符 描述 实例
== 检查两个操作数的值是否相等,如果相等则条件为真。 (A == B) 为假。
!= 检查两个操作数的值是否相等,如果不相等则条件为真。 (A != B) 为真。
> 检查左操作数的值是否大于右操作数的值,如果是则条件为真。 (A > B) 为假。
< 检查左操作数的值是否小于右操作数的值,如果是则条件为真。 (A < B) 为真。
>= 检查左操作数的值是否大于或等于右操作数的值,如果是则条件为真。 (A >= B) 为假。
<= 检查左操作数的值是否小于或等于右操作数的值,如果是则条件为真。 (A <= B) 为真。

(三) 逻辑运算符

运算符 描述 实例
&& 称为逻辑与运算符。如果两个操作数都非零,则条件为真。 (A && B) 为假。
| 称为逻辑或运算符。如果两个操作数中有任意一个非零,则条件为真。 (A | B) 为真。
! 称为逻辑非运算符。用来逆转操作数的逻辑状态。如果条件为真则逻辑非运算符将使其为假。 !(A && B) 为真。

(四) 位运算符(按二进制的位)(A=10,B=20)

运算符 描述 实例
& 对两个操作数的每一位执行逻辑与操作,如果两个相应的位都为 1,则结果为 1,否则为 0。按位与操作,按二进制位进行"与"运算。运算规则:

0&0=0;
0&1=0;
1&0=0;
1&1=1;
(A & B) 将得到 0,即为 0000 0000
| 对两个操作数的每一位执行逻辑或操作,如果两个相应的位都为 0,则结果为 0,否则为 1。按位或运算符,按二进制位进行"或"运算。运算规则:

0|0=0;
0|1=1;
1|0=1;
1|1=1;
(A | B) 将得到 30,即为 0001 1110
^ 对两个操作数的每一位执行逻辑异或操作,如果两个相应的位值相同,则结果为 0,否则为 1。异或运算符,按二进制位进行"异或"运算。运算规则:

0^0=0;
0^1=1;
1^0=1;
1^1=0;
(A ^ B) 将得到 30,即为 0001 1110
~ 对操作数的每一位执行逻辑取反操作,即将每一位的 0 变为 1,1 变为 0。取反运算符,按二进制位进行"取反"运算。运算规则:

~1=-2;
~0=-1;
(~A ) 将得到 -10,即为 1111 0110,一个有符号二进制数的补码形式。
<< 将操作数的所有位向左移动指定的位数。左移 n 位相当于乘以 2 的 n 次方。二进制左移运算符。将一个运算对象的各二进制位全部左移若干位(左边的二进制位丢弃,右边补0)。 A << 2 将得到 40,即为 0010 1000
>> 将操作数的所有位向右移动指定的位数。右移n位相当于除以 2 的 n 次方。二进制右移运算符。将一个数的各二进制位全部右移若干位,正数左补 0,负数左补 1,右边丢弃。 A >> 3 将得到 1,即为 0000 0001

(五)赋值运算符

运算符 描述 实例
= 简单的赋值运算符,把右边操作数的值赋给左边操作数 C = A + B 将把 A + B 的值赋给 C
+= 加且赋值运算符,把右边操作数加上左边操作数的结果赋值给左边操作数 C += A 相当于 C = C + A
-= 减且赋值运算符,把左边操作数减去右边操作数的结果赋值给左边操作数 C -= A 相当于 C = C - A
*= 乘且赋值运算符,把右边操作数乘以左边操作数的结果赋值给左边操作数 C *= A 相当于 C = C * A
/= 除且赋值运算符,把左边操作数除以右边操作数的结果赋值给左边操作数 C /= A 相当于 C = C / A
%= 求模且赋值运算符,求两个操作数的模赋值给左边操作数 C %= A 相当于 C = C % A
<<= 左移且赋值运算符 C <<= 2 等同于 C = C << 2
>>= 右移且赋值运算符 C >>= 2 等同于 C = C >> 2
&= 按位与且赋值运算符 C &= 2 等同于 C = C & 2
^= 按位异或且赋值运算符 C ^= 2 等同于 C = C ^ 2
|= 按位或且赋值运算符 C |= 2 等同于 C = C | 2

(六) 其他运算符

运算符 描述 实例
sizeof() 返回变量的大小。 int a;sizeof(a) 将返回 4,其中 a 是整数。
& 返回变量的地址。 &a; 将给出变量的实际地址。
* 指向一个变量。 *a; 将指向一个变量。
? : 条件表达式 如果条件为真 ? 则值为 X : 否则值为 Y

三、关于基本结构

在C语言中,有三大基本结构,这些结构保证了C语言的规范工整、程序的易读性:

(一)顺序结构

顺序结构是最为基础的结构,根据名字我们就可以知道就是按顺序执行就可以了。

#include <stdio.h> //这是编译预处理指令  
int main ()        //定义主函数  
{                 //函数开始的标志  
    printf_s("Hello World!1\n");   //输出所指定的一行信息  
    printf_s("Hello World!2\n");   //输出所指定的一行信息  
    printf_s("Hello World!3\n");   //输出所指定的一行信息  
    printf_s("Hello World!4\n");   //输出所指定的一行信息  
    return 0;     //函数执行完毕时返回函数值0  
}                 //函数结束的标志

上面的程序就是一个标准的顺序结构的程序,读者可以输入到IDE中进行调试验证,程序按照顺序分别执行输出。

(二) 选择结构

选择结构通过一个判断语句来判断应该执行的代码块,一般用if…else…语句来执行

#include <stdio.h>  
int main()  
{  
    int a=10,b=0;  
    if(a==10){  
        a=a+1;b=b+1;}  
    else  
        {a=a+4;b=b+4;}  
    printf_s("%d,%d\n",a,b);  
    return 0;  
    }

通过修改a的值,我们发现程序执行了不同的代码块,让程序的执行更加灵活多变,当然我们也可以多分支判断,当然我们可以在else中再次使用if…else…语句块,然而,我们有更优雅的实现:

#include <stdio.h>  
#include <math.h>  
int main()  
{  
    double a,b,c,disc,p,q;  
    printf_s("\n请输入一元二次方程的系数(空格间隔)");  
    scanf_s("%lf%lf%lf",&a,&b,&c);  
        p=-b/(2.0*a);  
    disc=b*b-4*a*c;  
    q=(disc>=0?sqrt(disc):sqrt(-disc))/(2.0*a);  
        if(disc<0)  
        printf_s("\n方程有两个虚根:x1=%7.2f+%7.2fi,x2=%7.2f-%7.2fi",p,q,p,q);  
    else if(0==disc)  
        printf_s("方程有两个相等实根:\nx=%7.2f",p);  
    else  
        printf_s("方有两个不相等程实根:\nx1=%7.2f\nx2=%7.2f\n",p+q,p-q);  
    return 0;  
}

通过else if我们实现更加整齐的代码书写,便于阅读,但如果分支多起来,这个方案显然不是特别合适,当然,我们有更好的switch…case…语句来实现:

#include <stdio.h>  
#include<ctype.h>  
#include <math.h>  
int main()  
{  
    char gradeChar='\0';  
    float hundredScore=0;  
        printf_s("\n请输入五级成绩等级(A|B|C|D|E):");  
    gradeChar=islower(gradeChar=getchar())?gradeChar-32:gradeChar;  
        switch (gradeChar)     {  
    case 'A':  
        hundredScore=90;  
        break;  
    case 'B':  
        hundredScore=85;  
        break;  
    case 'C':  
        hundredScore=75;  
        break;  
    case 'D':  
        hundredScore=65;  
        break;  
    case 'E':  
        hundredScore=50;  
        break;  
    default:  
        hundredScore=0;  
        break;  
    }  
        if(fabs(hundredScore)<1e-10)  
        printf_s("\n输入数据错误!");  
    else  
        printf_s("\n百分制成绩:%.2f",hundredScore);  
        return 0;  
}

这样的代码如果用if…else…来书写的话就非常麻烦,而如果使用switch语句来书写,显然提高了编码效率,也便于理解。

(三) 循环结构

在C语言中,为了减少内存的占用并且提高编程的效率,我们一般使用循环结构来重复处理相似的任务:

#include <stdio.h>  
int main()  
{  
    int sum=0,i=1,n=0;  
    printf_s("请输入n的值:");  
    scanf_s("%d",&n);  
    while(i<n){  
        if(i%3==0){  
            sum=sum+i;  
            i++;  
        }  
        else  
            i++;  
    }  
    printf_s("\n和是:%d",sum);  
    return 0;  
}

通常我们使用while循环来实现先判断后执行的简单代码,但注意不要编码出死循环的程序!

当然我们也有更好的循环结构:

#include <stdio.h>  
int main()  
{  
    int sum=0,i=1;  
    int n=0;  
    printf_s("请输入n的值:");  
    scanf_s("%d",&n);  
    for(int i=1;i<=n;i++)  
        sum=sum+i;  
    printf_s("%d!的值是%d。",n,sum);  
    return 0;  
}

使用for循环将初始化语句和相同的变量语句放入括号内,使代码更加简洁,更易于阅读和修改,当然我们还有一种循环结构:

#include <stdio.h>  
int main()  
{  
    int sum=0,i=1;  
    int n=0;  
    printf_s("请输入n的值:");  
    scanf_s("%d",&n);  
    do{  
        sum=sum+i;  
        i++;  
    }while(i<=n);  
    printf_s("%d!的值是%d。",n,sum);  
    return 0;  
}

do…while…循环的好处在于保证代码块至少执行一次,其他与while几乎没有区别。

四、关于函数

在C语言中,用户可以自定义函数来简化流程,方便使用:

#include <stdio.h>  
int aaa(char *s)  
{  
    char *t = s;  
    while (*t++);  
    t--;  
    return (t - s);  
}  
int main()  
{  
    char s[10] = "abcdefghi";  
    printf("%d", aaa(s));  
    return 0;  
}

我们定义的aaa函数如果写在main函数的后面,要先在main函数前面声明,不然会报错的!

(关于指针等内容由于繁多,不在本篇展开)

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐