很粗的C语言

初始C语言

1、什么是C语言?

C语言是一门通用计算机编程语言,广泛应用于底层开发(应用软件之下都属于底层开发)。C语言的设计目标是提供一种能以简易的方式编译、处理低级存储器、产生少量的机器码以及不需要任何运行环境支持便能运行的编程语言。

看到这里,很多小伙伴就要问了,什么是计算机编程语言?

问的好,就像我们日常生活当中所说的话一样,汉语、英语、阿拉伯语等,或者说我们的方言普通话、河南话、粤语、四川话、东北话等等,是人与人之间交流的一种形式,我们通过语言来交流。而计算机编程语言就是人和计算机之间的交流,一个人要命令计算机去帮我们做一些事情,你该怎么告诉它呢?毕竟计算机是个铁疙瘩,总不能我们去拿着锤子来一场钢铁碰撞吧?计算机编程语言就是建立我们人和计算机之间的交流联系的桥梁。

尽管C语言提供了许多低级处理的功能,但仍然保持着良好跨平台的特性,以一个标准规格写出的C语言程序可在许多电脑平台上进行编译,甚至包含一些嵌入式处理器(单片机或称MCU)以及超级电脑等作业平台。

二十世纪八十年代,为了避免各开发厂商用的C语言语法产生差异,由美国国家标准局为C语言制定了一套完整的美国国家标准语法,称为ANSIC,作为C语言最初的标准。目前2011年12月8日,国际标准化组织(ISO)国际电工委员会(IEC)发布的C11标准是C语言的第三个官方标准,也是C语言的最新标准,该标准更好的支持了汉字函数名和汉字标识符,一定程度上实现了汉字编程。

C语言是一门面向过程的计算机编程语言,与C++,Java等面向对象的编程语言有所不同。其编译器主要有Clang、GCC、WIN-TC、SUBLIME、MSVC、Turbo C等。

2、C程序

在我们日常写代码的时候通常会有两种格式的文件:

  • xxx.h - 头文件

  • xxx.c - 源文件(xxx.cpp - 是C++的源文件)

我们的C程序是放在.c后缀的文件中的


//stdio - std input  output
//.h - header
//标准输入输出
#include <stdio.h>
//如果想在屏幕上打印数据,可以使用printf这个库函数
//printf是一个C语言编译器提供的库函数
//库函数的使用,要包含头文件
int main()
//int是函数的返回类型
//解释:
//main函数是程序的入口
//一个工程中main函数有且仅有一个
{
    printf("hello world\n");
    printf("he he\n");
    return 0;
    //C语言有一个约定;
  //返回0表示正常返回
  //返回的是非0,表示异常返回
}

//有时候我们会遇见这些写法
//
// 写法一:比较古老的写法 
void main()
{
    return 0;
}
//写法二:不标准的写法
main()
{

}
//写法三:
int main(void)//这里的void表是main函数不需要参数
{
    return 0;
}

注意:一个工程当中可以有多个.c文件,但是多个.c文件当中只能有一个main函数。

3、数据类型

类型

大小(字节)

char

字符型

1

short

短整型

2

int

整形

4

long

长整型

4

(C语言规定sizeof(long)>= sizeof(int))

long long

更长的整形

8

float

单精度浮点型

4

double

双精度浮点型

8

计算机能够处理的是二进制(由0或1组成),而1个bit(比特位)就是计算机上的最小单位

8bit=1byte(字节)、1024byte=1KB、1024KB=1MB、1024MB=1GB、1024GB=1TB、1024TB=1PB......

为什么会存在这么多的数据类型呢?是为了更加丰富的表达生活中的各种值

#作用:预处理指令,预处理指令的开头就是#(语法规定)

4、变量、常量

变量:可变化的数值(年龄、体重等)

常量:不变的数值(比如圆周率)

4.1、变量的定义方法

数据类型 变量名=赋值;

比如:


    int age = 10;
    float weight = 45.5f;
 double weight = 45.5;

注意:数据后跟上一个f才会被认定为是float类型的,如果数据的后面不跟f,会被编译器自动认定为double类型的

4.2、变量的命名

  • 只能由字母(包括大写和小写)数字和下划线( _ )组成。

  • 不能以数字开头。

  • 长度不能超过63个字符。

  • 变量名中区分大小写的。

  • 变量名不能使用关键字。

4.3、变量的分类

  • 局部变量(定义在函数体内的变量)

  • 全局变量(定义在函数体外的变量)

比如:


#include <stdio.h>

int global = 2019;//全局变量
int main()
{
    int local = 2018;//局部变量
    //下面定义的global会不会有问题?
    int global = 2020;//局部变量
    printf("global = %d\n", global);
    return 0;
}
输出结果:global = 2020

注意:当局部变量和全局变量同名的时候,局部变量优先使用。

在这里遇到了一些问题,因为我用的是VS2019,所以使用scanf的时候报了这样一个错误:

错误 C4996 'scanf': This function or variable may be unsafe. Consider using scanf_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details. C Section one D:\Gittee本地仓库\C-learn\c-learn\C Section one\C Section one\test_2023_03_03.c 87

在VS当中是推荐使用scanf_s的,但是由于该函数,是VS本身的,所以当我们使用scanf_s的时候,代码在别的平台就会丧失了它本身的跨平台性,于是需要在源文件第一行加一个

#define _CRT_SECURE_NO_WARNINGS1 来让我们的scanf函数不会报错,以为scanf函数本身是存在一些问题的。

其次,在此介绍一下:

  • scanf的使用方式:


scanf("%d %d",&num1,&num2);
双引号里面的内容是输入的格式%d代表以十进制方式输入
格式与各个变量之间需要通过,隔开而变量之前需要加一个&(取地址)
意思是取出num1的地址来放置格式化的数据
  • printf的使用方式:


printf("%d",num);
在这里变量之前不需要&而是直接输入变量的数据,但是依然要定义数据的输出格式

4.4、变量的作用域和生命周期

  • 作用域:

作用域(scope)是程序设计概念,通常来说,一段程序代码中所用到的名字并不总是有效/可用的而限定这个名字的可用性的代码范围就是这个名字的作用域
  • 局部变量的作用域是变量所在的局部范围。


int main()
{
    int a = 10;
    {
        //作用域开始
        int b = 20;
        printf("a = %d,b = %d\n",a,b);
        //变量b只能在该作用域当中使用
        //作用域结束
    }
    printf("a = %d\n",a);
    //printf("b = %d\n",b);
    //报错,因为变量b作用域已经结束了
    return 0;

}
  • 全局变量的作用域是整个工程。


int a = 5;

void test()
{
    printf("%d\n",a);
    //全局变量a可以在该作用域使用
}
int main()
{
    printf("%d\n",a);
    //全局变量a可以在该作用域使用
    test();
    return 0;
}

甚至,全局变量可以跨文件使用:

可以发现,当The文件的变量在test文件当中声明过后,可以在test当中使用

extern是专门用来声明外部符号的

注意:全局变量使用不安全,因为当全局变量可以在全局当中都使用都可以修改的时候,会变得及其的不安全,所以应该尽量避免使用全局变量,即使使用也要格外的注意。

  • 生命周期:

变量的生命周期指的是变量的创建到变量的销毁之间的一个时间段
  • 局部变量的生命周期是:进入作用域生命周期开始,出作用域生命周期结束。


//变量的声明周期
//局部变量
int main()
{
    int a = 10;
    {
        //作用域开始,变量b的生命周期开始
        int b = 20;
        printf("a = %d,b = %d\n", a, b);
        //变量b只能在该作用域当中使用
        //作用域结束,变量b的生命周期结束
    }
    printf("a = %d\n",a);
    //printf("b = %d\n",b);
    //报错,因为变量b 生命周期已经结束了
    return 0;
}
  • 全局变量的生命周期是:整个程序的生命周期。

总结:其实作用域相当于是变量的空间范围,而生命周期相当于是时间范围,其实都是指的相同的变量的使用范围,一个是空间层面的一个是时间范围。

4.5、常量

C语言中的常量分为以下以下几种:

  • 字面常量


int main()
{
    //1.字面常量
    100;
    3.14;
    //字面上的数值不可被修改
    3.14 = 2;
//err  E0137    表达式必须是可修改的左值

    return 0;
}
  • const 修饰的常变量


int main()
{
//2.const修饰的常变量
        int a = 5;
    a = 10;
        printf("a = %d\n",a);//输出a = 10
    //在这里变量a的数值可以更改原本是5后被改为10
    //说明变量a是一个变量
        const int num = 8;
    //当变量num被const修饰时具有了常量的不可被修改属性
    //但是它本质上还是个变量
int arr1[5] = { 0 };
int arr2[num] = { 0 };//err  E0028    表达式必须含有常量值   C2057    应输入常量表达式
return 0;
}//const修饰的常变量,只是在语法层面限制了变量不能被修改,但本质上还是一个变量,所以叫常变量
  • #define 定义的标识符常量


#define MAX 100
int main()
{
    printf("MAX = %d\n",MAX);//输出为MAX = 100
    //MAX = 20;//err   E0137    表达式必须是可修改的左值
    //说明MAX是不可被修改的,所以MAX也是常量
    int arr[MAX] = { 0 };//未报错
    return 0;
}
  • 枚举常量


//枚举常量 一一列举
enum Sex
{
    MALE,
    FEMALE,
    SECRET
};
int main()
{
    enum Sex s = MALE;
    printf("%d\n",MALE);//0
    printf("%d\n",FEMALE);//1
    printf("%d\n",SECRET);//2

    int arr[FEMALE] = {0};//可以正常运行
    //MALE = 20;//E0137    表达式必须是可修改的左值
    //说明MALE是一个常量不可被修改

    return 0;
}

5、C中的字符(串)

5.1、字符串

由双引号(Double Quote)引起来的一串字符称为字符串字面值(String Literal),或者简称字符串。

注:字符串的结束标志是一个 \0 的转义字符。在计算字符串长度的时候 \0 是结束标志,不算作字符串内容

其实用双引号引起来的字符串末尾隐藏了一个\0的转义字符作为结束标志

%s是打印字符串,遇到 \0 打印自然结束,在arr1当中因为末尾隐藏了转义字符 \0 所以打印的时候就只是abc的字符,而arr2当中因为没有转义字符 \0 那么编译器就会继续向后读取打印,直到遇见转义字符 \0 才停止,所以是abc。。。等一些随机值。

注意:单引号引起来的叫字符,双引号引起来的叫字符串。

5.2、转义字符

转义字符

释义

\?

在书写连续多个问号时使用,防止他们被解析成三字母词

\'

用于表示字符常量 '

\"

用于表示一个字符串内部的双引号

\\

用于表示一个反斜杠,防止它被解释为一个转义序列符

\a

警告字符,蜂鸣

\b

退格符

\f

进止符

\n

换行

\r

回车

\t

水平制表符

\v

垂直制表符

\ddd

ddd表示1~3个八进制数字(ddd里面数字只能是0~7)

\xdd

dd表示2个十六进制数字(dd里面的数字是0~9+abcdef)

6、注释

  • 代码中有不需要的代码可以直接删除,也可以注释掉

  • 代码中有些代码比较难懂,可以加一下注释文字

注释其实就是为了让别人读懂你写的代码,解释说明作用

注释有两种风格:

  • C语言风格的注释 /*xxxxxx*/ 缺陷:不能嵌套注释(配套最近第一个注释标识)

  • C++风格的注释 //xxxxxxxx 可以注释一行也可以注释多行

7、选择(分支)语句

通过不同的条件来触发并判断不同选择下的逻辑

有两种:

  • if-else语句

  • swlitch语句

8、循环语句

通过满足什么样的条件来实现结束某个固定的逻辑,从而去继续循环之后的逻辑

有三种:

  • for循环

  • while循环

  • do while循环

9、函数

其实就是,跟main函数相同性质,但是因为一个工程里面有且只能有一个main函数,但是有些逻辑为了共用、使代码清晰等,实现的跟mian相同的作用但是优先级没有main高的逻辑单元,不仅可以让项目的逻辑更清晰,同时通过代码化和模块化的形式来进行对项目工程更好、更清晰、更方便的一种通用重要形式。

10、数组

数组的定义:一组相同类型元素的集合

为了方便我们使用把相同类型的元素进行了集群化,于是就有了数组的定义


int main()
{
    //不完全初始化,剩余的数值为0
    int arr1[10] = { 0 };
    int arr2[10] = { 1,2,3 };
    //完全初始化
    int arr3[5] = { 1,2,3,4,5 };

    //还有一种叫做变长数组(使用变量来指定数组的大小但是不能初始化),c99的语法
    //int n = 3;
    //int arr4[n];

    return 0;
}

数组的每个元素都有一个下标,下标是从0开始的。数组可以通过下标来访问的

数组的下标是从0开始的以此递增1,访问的时候要注意


int main()
{
    int arr1[5] = {1,2,3,4,5};

    printf("%d\n",arr1[3]);
    return 0;
}

11、操作符

  • 算术操作符

+ - * / %

说一下 / 除号


int main()
{
    printf("%d\n", 8 / 2);
    printf("%d\n", 7 / 2);
//正常情况下,除号的除法运算结果
//如果是没有小数的时候即为商
//如果结果是小数的话,结果是取整数部分,不会通过小数来进位
//也就是说只取整数部分的结果
    printf("%lf\n", 7.0 / 2);
    printf("%lf\n", 7 / 2.0);
    printf("%lf\n", 7.0 / 2.0);
    //要使结果为小数,那么需要除号两边至少有一个数据是小数
    return 0;
}

取模(取余)% :取余就是取两个数经过除法运算后的余数


int main()
{
    printf("%d\n", 8 % 2);
    printf("%d\n", 7 % 2);
    //取余就是取两个数经过除法运算后的余数
    return 0;
}
  • 移位(二进制位)操作符

>> <<

相当于除2和乘2操作

  • 位(二进制位)操作符

& ^ |

类似逻辑与或非

  • 赋值操作符

= += -= *= /= &= ^= |= >>= <<=

作用相当于是简化代码


int main()
{
    //+=
    int a = 0;
    a = a + 2;
    a += 2;
    //-=
    int b = 0; 
    b = b - 2;
    b -= 2; 
    //*=
    int c = 0;
    c = c * 2; 
    c *= 2;//相当于上面的c = c * 2; 
    //......其他的复合操作符类比上面
    return 0;
}
  • 单目操作符(只有一个操作数的操作符)

! 逻辑反操作
- 负值
+ 正值
& 取地址
sizeof 操作数的类型长度(以字节为单位)
~ 对一个数的二进制按位取反
-- 前置、后置--(先使用数值后自增、自减)
++ 前置、后置++(先自增、自减后使用数值)
* 间接访问操作符(解引用操作符)
(类型) 强制类型转换

在C语言当中,0表示假,非0表示真


int main()
{
    int a = 20;int arr1[] = {1,2,3,4,5};
    printf("%d\n",sizeof(a));
    printf("%d\n",sizeof a);
    //sizeof是一个操作符,所以求变量的大小的时候他的括号可以去掉
    printf("%d\n",sizeof(int));
    //也可以求类型所占空间大小
    //printf("%d\n",sizeof int);//语法错误
    //但是不能去掉括号
    printf("%d\n",sizeof(arr1));
    //所求的是数组的总大小
    printf("%d\n", sizeof(arr1[0]));
    //所求的是数组下标为0的元素的大小
    printf("%d\n", sizeof(arr1)/sizeof(arr1[0]));
    //求的是数组里面的元素个数
    return 0;
}

注意:

  • strlen是库函数

strlen是求字符串长度的,关注的是字符串中是否有 \0 ,统计 \0 之前出现的字符的个数 。

  • sizeof是操作符

sizeof只关注占据了多大的内存空间,不关注内存中存放的数据

  • 关系操作符

>
>=
<
<=
!= 用于测试“不相等”
== 用于测试“相等”

注意:一个=是赋值,两个=(==)是判断

  • 逻辑操作符

&& 逻辑与(并且)
|| 逻辑或(或者)
  • 条件操作符(三目操作符)

exp1 ? exp2 : exp3

int main()
{
    //求俩个数字的最大值
    int a = 1;
    int b = 2;
    //exp1 ? exp2 : exp3
    int m = (a > b ? a : b);
    //这个操作符的作用就是,exp1的判断是真,那么exp2的结果就是整个表达式的结果
    //否则(也就是exp1是假),exp3的结果是整个表达式的结果
    printf("%d\n",m);
    return 0;
}
  • 逗号表达式

exp1, exp2, exp3, …expN

int main()
{
    int a = 2;
    int b = 3;
    int c = 0;
    int x = (a = b - c, b = c + a, c = a + b, a = a + b + c);
    //            a=3            b=3        c=6            a=12
    //exp1, exp2, exp3, …expN
    //逗号表达式:
    //表达式从左到右以此计算,但是最后一个表达式的结果是整个表达式的结果
    printf("%d\n",x);
    return 0;
}
  • 下标引用、函数调用和结构成员

[] () . ->

int Add(int x,int y)
{
    return x + y;
}

int main()
{
    int arr1[] = {1,2,3,4,5};//这里面的arr1[]的[]就是下标引用操作符
    printf("%d\n",Add(arr1[0], arr1[2]));//这里面的Add()当中的()就是
    //函数调用操作符
    return 0;
}

12、常见关键字

auto break case char const continue default do double else enum extern float for goto if int long register return short signed sizeof static struct switch typedef union unsigned void volatile while

C语言提供了丰富的关键字,这些关键字都是语言本身预先设定好的,用户自己是不能创造关键字的。

12.1、关键字typedef

typedef 是类型定义(类型重命名)


typedef unsigned int uint;
int main()
{
    uint a = 9;
    //这里的uint就是unsigned int 的简化
    //在上方我们给其简化(重命名为uint)
    printf("%d\n",a);
    
    return 0;
}

12.2、关键字static

在C语言中:static是用来修饰变量和函数的

  • 修饰局部变量-称为静态局部变量

static修饰改变了局部变量的存储类型,使局部变量出了作用域不会被销毁依然存在,延长了变量的生命周期。程序结束的时候,静态变量才会被回收。

  • 修饰全局变量-称为静态全局变量

全局变量是具有外部链接属性的,当static修饰全局变量的时候 全局变量就丧失了它的外部链接属性,不可以被其他源文件所链接使用。

  • 修饰函数-称为静态函数

函数也是具有外部链接属性的,当它被static修饰的时候它的外部连接属性就会变为内部链接属性,跟全局变量被static修饰一样,不能够跨文件使用。

13、#define定义常量和宏

13.1、#define定义的常量

#define定义的常量一般是为了便于程序的修改



//#define定义的常量
#define MAX 100
//#define定义的是常量
int main()
{
    printf("%d\n",MAX);
    //可以直接打印出来
    int arr[MAX] = {0};
    //可以用做数组的定义
    return 0;
}

13.2、#define定义的宏

#define定义的宏使用方法跟函数有点类似


//#define定义的宏
#define ADD(X,Y) ((X)+(Y))

//Add函数
int Add(int x,int y)
{
    return x + y;
}
int main()
{
    int a = 2;
    int b = 4;
    int sum1 = Add(a,b);
    printf("%d\n",sum1);
    //使用定义的宏
    int sum2 = ADD(a, b);
    printf("%d\n",sum2);
    return 0;
}

14、指针

要说指针那就离不开地址

14.1、地址

内存是电脑上特别重要的存储器,计算机中程序的运行都是在内存中进行的 。所以为了有效的使用内存,就把内存划分成一个个小的内存单元,每个内存单元的大小是1个字节。为了能够有效的访问到内存的每个单元,就给内存单元进行了编号,这些编号被称为该内存单元的地址。以32位系统为例,它有32根地址线,每根线有两种变化代表二进制位里面的0或者1,按照2的32次方的排列组合所表示的数字就是地址。变量是创建内存中的(在内存中分配空间的),每个内存单元都有地址,所以变量也是有地址的。


int main()
{
    int a = 10;
    //int类型的内存大小是四个字节
    printf("%p\n",&a);
    //& - 是取地址,意思是去除后面变量的地址
    // 而取地址取出的是变量a的第一个字节空间的地址
    //%p是以16进制的形式格式化输出
    return 0;
}

14.2、指针变量

地址在C语言里面我们称它为指针(本质就是地址),而存储指针的变量就是指针变量。


int main()
{
    int a = 10;
    int* p = &a;//int*当中*说明变量p是一个指针,而int说明该指针指向的
    //对象是int类型的
    //取出变量a的地址存放在指针变量p当中
    printf("%d\n", *p);

    printf("%p\n", p);
    *p = 20;
    //*p中的*是解引用操作符,意思是将p地址里的内容取出来输出
    printf("%d\n",*p);
    return 0;
}

& - 取地址操作符

* - 解引用操作符

上方两个操作符是一对,取地址操作符是把变量的地址取出来,当然地址需要指针变量来存储 ,而此时存储地址的指针变量存储的内容是一个地址,解引用操作符作用就是根据指针变量所存储的地址找到该地址里面存储的内容。

14.3、指针变量的大小

指针变量存储的是地址,而地址的存储需要多大空间,那么指针变量就是这么大的空间

指针变量在32位机器上存储需要32个比特位,所以它的大小是四个字节

指针变量在64位机器上存储需要64个比特位,所以它的大小是八个字节

15、结构体

结构体一般是用来描述复杂对象的

语法:


struct Stu
//struct是结构体的关键字,Stu是结构体名字
{
    //里面放结构体变量,一般是描述对象的相关属性
};//大括号后面要加;

结构体的创建相当于是建筑时候的图纸,而实例化则是实际按照图纸施工建造出来的房屋

15.1、结构体对象的实例化

结构体的访问有两种方式:

  • .结构成员访问操作符(是对成员属性直接进行访问),用法:结构体变量.结构体成员

  • ->结构成员访问操作符(是通过指针变量的方式对成员属性访问),用法:结构体指针->结构体成员


struct Stu
{
    char name[20];//名字
    int age;//年龄
    char sex[5];//性别
    char id[15];//学号
};

int main()
{
    struct Stu s = {"张三",19 ,"man","11232324"};
    //对象s的实例化,按照上方结构体的创建输入相对应的属性
    printf("%s %d %s %s\n",s.name,s.age,s.sex,s.id);
    //结构体的打印(访问)需要通过结构体变量名.成员属性
    struct Stu* ps = &s;
    printf("name = %s age = %d sex = %s id = %s\n", ps->name, ps->age, ps->sex, ps -> id);
//结构体的访问通过->操作符是通过指针变量进行访问
    return 0;
}

在我们平时的写代码过程中

平时见到的0 - 就是数字0

这种被单引号引起来的 ‘ 0 ’ - 字符0

被单引号引起来的\0:‘ \0 ’ - 转义字符,是字符串的结束标志,ASCII码值是0

EOF - 是end of file多大缩写,也是文件的结束标志

NULL - 是空指针,本质上是0

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我可是万西西呀

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值