C语言学习(一) C语言概述

一、 计算机基础知识

1. 文件

1.1 可执行文件

在windows系统中,扩展名为:*.exe,*.bat,*.com等文件是可执行文件;其由指令和数据构成。

1.2 不可执行文件

其内容是由数据构成的

 

如:在C/C++语言中*.c/*.cpp源文件(文本),*.h头文件(文本),*.i预编译文件(文本),*.s汇编文件,*.o/*.obj二进制目标文件,*.exe可执行文件

1.3 C语言的编译链接过程

 

2. 进制及其转换

计算机常用的进制有二进制、八进制、十六进制

二进制转换为八进制  三位一合

二进制转换为十六进制 四位一合

 

举个例子,这里面为啥要三位一合呢?

因为对于八进制其每一位无非就是8种情况,0~7,将这一范围用二进制表示出来就是000~111一共7种情况

 

二、什么是C语言

C语言的标准有C89、C99、C11、C17

C源程序的特点:

一个C语言源程序可以由一个或者多个源程序组成

每个源文件可以由一个或者多个函数组成

一个源程序不论由多少个文件组成,都有一个且只能有一个main函数,即主函数

三、数据类型

C语言中的重中之重就是数据类型

主要分为以下几种数据类型

char、short、int、long int、long long 这些可以归结为整型,至于这里面的char为什么归到整型里面,因为字符都是以ASCII码值存在计算机里面的,所以它也被归结到整型里面

float、double、long double 这些可以归结为浮点型

bool是布尔类型

void为空类型,可以表示任何东西

 

那么在C语言中这些数据类型分别占多少个字节呢

我们可以通过下面的代码来观察其各自所占的字节空间

int main() {
	//整型
	printf("char size:			%d\n", sizeof(char));
	printf("short size:			%d\n", sizeof(short));
	printf("int size:			%d\n", sizeof(int));
	printf("long int size:		%d\n", sizeof(long int));
	printf("long long size:		%d\n", sizeof(long long));
	//浮点
	printf("float size:			%d\n", sizeof(float));
	printf("double size:		%d\n", sizeof(double));
	printf("long double size:	%d\n", sizeof(long double));
	//布尔
	printf("bool size:			%d\n", sizeof(bool));
	return 0;

}

其运行结果为:

 

四、 变量、常量,标识符

变量和常量

变量是以某标识符为名字  起名规则  值可以改变 可读可写
常量其值不可改变  只可读不可写

 

定义和声明

定义就是为这个变量分配一块内存并且给它取上一个名字,这个名字就是我们经常所说的变量名,注意不能重复定义同一变量或者对象

声明有两重含义:

第一重:这个名字已经匹配到一块内存上了

第二重:名字已经先预定,其他地方不能用它重复定义

 

声明和定义最重要的区别

定义创建了对象并为这个对象一块内存,而声明的时候是没有分配内存空间的

 

变量分为

局部变量:在函数中定义的变量

全局变量:在函数外定义的变量

 

常量分为

字面常量、用#define定义的宏常量、用const关键字修饰的变量(称为常变量)、枚举常量、字符常量和字符串常量

这里面注意枚举常量是有限制的整型常量

 

单引号和双引号

单引号是字符的定界符

双引号是字符串的定界符

 

记住一些常见的ASCII码值

'a' 97  'A' 65  '0' 48

空格 38 换行 10  回车 13

 

注意转义字符  \ 

有两层含义:

第一,将一个字母转化为一个特殊含义,如\n、\t

第二,将 ' 、\ 字符转化为其本来的字符含义,如'    \'  '  ——>   ',又如'  \\ '  ——>   \

使用转义字符时需要注意以下问题:

  1. 转义字符只能使用小写字母,否则会失效
  2. 在双引号里面使用单引号不需要转义字符
  3. \?就是指的是?  没有其他意思

总结:

  1. 转义字符既可以用于单个字符,也可以用于字符串,并且一个字符串中可以同时使用八进制和十六进制形式
  2. 转义字符取值有限,\ddd最大取值是\177,表示8进制,\xdd最大取值是\x7f,表示十六进制
  3. 单引号、双引号、反斜杠这些特殊字符如果想要表示其本来含义,需要转移字符

字符常量、字符串常量

单引号是字符的定界符

双引号是字符串的定界符

 

五、顺序语句、选择语句、循环语句

5.1 选择语句

    //单选泽语句
	if () {

	}
	else {

	}
    
    //复选择语句
	if () {

	}
	else if () {

	}
	...

	else {
	
	}

    //多分支选择语句
	switch (int_condition) {
	case int_num1:
		break;
	case int_num2:
		break;
	...

	default:
		...
	}

这里面注意switch选择语句中的判断条件变量必须是整型,一定要记住这一点,否则会错误

5.2 循环语句

    //while循环
	while () {
	
	}

	//for循环
	for (初始条件; 跳出条件; 每次循环完所做动作) {

	}

	//do while循环
	do {

	}while(跳出条件)

对于死循环可以有以下几种实现方式

    //while循环
	while (1) {

	}

	//for循环
	for (初始条件; ; 每次循环完所做动作) {

	}

	//do while循环
	do {

	} while (1)

六、函数

函数就是一个个小功能单元,有返回类型、有参数、有函数名称

6.1 可见性和生存期

6.1.1 可见性

指的是某一标识符所能够被使用的范围;只有在作用域内标识符才能使用

按照我的理解,作用域是一个非常重要的概念,因为很多时候需要考虑到这一点,否则就会出错。

作用域这一个概念,针对C语言程序三大过程的编译连接过程,在编译链接的时候,需要考虑到变量的作用域,需要给他们分别链接相应的值

根据上面的变量概念,变量其可以分为全局变量和局部变量

6.1.2 生存期

生存期指的是变量的生存周期,其针对的是程序的执行过程

对于局部变量,其存储在.stack区域,在函数执行开始时,分配空间,到函数结束,释放函数栈空间,所以对于有些在函数体中定义的变量,如果在函数外要对其操作,比如指针指向函数体中的一个数组,那么在函数执行的时候,可以对这个数组赋值,但是在函数执行完毕的时候,数组空间就被释放,其中的值变成随机值,这是一个特别重要的点,在一般的笔试题中都有涉及。

7. 数组

数组是在内存中连续存储的一系列空间,其具有三大特征:数组名、数组元素个数、数组类型

注意数组元素的类型一样,另外我们对于一个数组的解释时,需要从右向左解释,比如下面这个

int (s*)[3];

其代表的是指向一个大小为3个整型元素的数组的指针

而下面这个

int* s[3]

其代表的是大小为3个整型指针的数组

7.1 运算符

一般运算符具有优先级,对于一些笔试中也少不了对优先级的考察,比如下面这个

int* p;

int x = *++p;

int y = *p++;

对于x代表的是先对p指针后移一位,再取其值

对于y代表的是先取p的值,然后对指针p后移一位

上面这个例子就极大地代表了优先级的重要性,如果还不能理解,那就看下面这个例子,这个是对于string.h中的strcat函数的实现

char* my_strcat(char* dist, char const* src)
{
	
	char* p = dist;
	while (*++dist) {
		//dist++;
	}
	while (*dist++ = *src++);
	*dist = '\0';
	return p;
}

可以对这个进行运行测试,发现对于dist和src都非空的情况下,都可以成功链接,但是对于dist是空字符串的时候就不能够实现,其原因其实也很好理解,其原因就是字符串都是以 ' \0 ' 结尾的,第一个循环,如果dist是空字符串的时候,自动跳到下一个空间,这样其第一个空间存储的是\0 ,这样就算下面的链接循环成功链接,但是由于其dist第一个空间为 \0  ,就算对dist进行打印,其也是空字符串,因为字符串都是以 '\0'结尾,所以优先级是一个特别重要的点,利用好了可以简化代码,利用不好会带来不必要的错误。

7.2 运算符举例

  1. 取模、取整
  2. *=,-=,+=
  3. 三目运算符
  4. 前置++,和后置++

7.2.1 余数

int x = y % 2;

cpp中对于余数是通过运算符%实现的,上面这行代码是求y对2的余数,将其值赋值给x

7.2.2 三目运算符

条件表达式 ? 表达式1:表达式2;

其代表意思就是,如果条件表达式成立,那么就是表达式1执行,否则就是表达式2执行

如在求两个数的最大值的时候,为了简洁就用到了这个表达式

int max(int x, int y) {
	return x > y ? x : y;
}

可以看到拿三目运算符实现可以让这些条件判断语句简单很多

7.2.3 前置++和后置++

这是个特别重要的概念,正如上面在函数生存期里面提到的那个例子一样,对于这两个运算符,需要仔细思考其运算过程,弄清楚到底是怎么走的

    int a = 0, b = 0, c = 0;
	c = a++;

	c = ++b;

对于下面这个程序,我们如果观察其低端汇编语言就会发现,这两个符号都做了哪些工作

从上面汇编语言可以看出,首先将a中的值取出放到eax寄存器中,然后将eax寄存器中存储的值赋值给c,然后将a中的值取出放到寄存器ecx中,然后对ecx中的值执行加1操作,然后将ecx中的值放到a中,从这一过程可以很清楚看到后置++就是先取值,然后再++,前置++也非常容易分析,这里面就不分析啦。

 

8. 指针

8.1 指针是什么

在计算机内存中存储地址的变量叫做指针变量。在C语言中指针就是地址

8.2 指针的大小

指针的大小对于不同位数的操作系统是不一样的,对于x86即32位系统其大小为4,对于x64系统即64位系统,其大小为8

因为指针指向一个变量地址,那么在计算机操作系统中给变量地址分配的位数,即系统最大支持字长,这也就是为什么指针在不同操作系统中其size不一样的原因

9. 结构体

在数据库中一个一个的表,表中有一条一条的记录,在C语言中就拿结构体来封装一条记录,结构体设计对于一个比较大的项目来说是十分重要的,其在设计阶段的重要性是举足亲重。

9.1 结构体是什么

在C语言中结构体是一种数据类型,是由程序员自己设计的一种数据类型

比如下面这个结构体就是代表一条学生的记录:

struct Student {
	char s_id[10];
	char s_name[10];
	char s_sex[5];
	int s_age;

};



int main() {
	struct Student stud = { "20200201","shshf","m",21 };

	printf("id: %s", stud.s_id);

	return 0;
}

 

对于上面这个结构体,对于其初始化直接按照顺序给结构体中每一个变量进行赋值,取值直接结构体变量名.结构体中变量名

10. 文件

10.1 数据流 DataStream

程序与数据之间的交流并不是像我们理解的那样,直接就能识别数据,然后将数据精准拿到,程序与数据之间的交互是以流的形式进行的

比如在进行C语言文件的存储时,都会先进行“打开文件操作”,此时就会打开数据流,将数据先写到数据流之中,这一数据流与文件对接,写入文件当中,当“关闭文件”时就会关闭数据流

10.2 缓冲区 BufferSpace

比如cpu和键盘的速度根本就不在同一水平线上,这个时候就可以借用缓冲区的作用,用户从键盘输入的数据,存放在缓冲区内,当CPU时间戳跑到这个缓冲区的时候就从缓冲区内读取一个字符,直到读取完毕为止

10.2.1 什么是缓冲区

缓冲区就是在程序执行的时候,在内存中所提供的一块存储空间,可用来暂时存放准备执行的数据,其设置提高了存取效率,因为解决了速度不匹配问题

C语言的文件处理功能最好是使用缓冲区来实现,当时用标准I/O函数,其在stdio.h库中,系统就会自动设置缓冲区,并且通过数据流来读写文件。当进行文件读取时,不会直接对磁盘进行读取,而是先打开数据流,将磁盘上的文件信息拷贝到缓冲区中,然后程序再从缓冲区中读取所需数据

10.3 文件类型

分为文本文件和二进制文件

文本文件是以字符编码的方式进行保存的。二进制文件将内存中数据原封不动存放到文件中,适用于非字符为主的数据。如果以记事本打开,只会看到一堆乱码

除了文本文件,所有的文件都可以进行二进制存储。二进制文件的有点在于存储速度快,占用空间小,以及可以随机存取

 

11. 关键字

C语言的关键字共有32个,根据关键字的作用,可分为数据类型关键字,控制语句关键字

11.1 数据类型关键字

void      char        short    int long    float       double

signed    unsigned    truct   union       enum        auto

static    register

//比较重要的关键字
typedef    sizeof    extern    const    volatile

11.2 流程控制关键字

if        else        switch       case    default    for    do    while
return    continue    break        goto

11.3 sizeof

计算类型的大小或者变量的大小,也就是字节个数

比如以下的sizeof的使用

    int ar[3] = { 1,2,3 };
	int size_ofAr = sizeof(ar);//这里面的ar不是代表指向数组首元素的指针,在这里面指的是数组ar的大小
	//结果为3*4=12
	//如果想要计算数组元素个数,需要下面这样计算
	int num_ofAr = sizeof(ar) / sizeof(ar[0]);
	//结果为3
	char br[4] = { "wew" };
	int size_ofBr = sizeof(br);
	//结果为4

11.4 typedef关键字

其使用规则如下

typedef    存在的数据类型        自定义的数据类型名字

例如下面几句代码

typedef unsigned char unint_8;
typedef unsigned short unint_16;
typedef unint_16 size_t;

从上面这几条代码中,我们将无符号char定义为unit_8

我们将定义的unit_16定义为size_t,从这里可以看出已经被typedef定义过的新称号,还能被再次定义为另一个新称号

11.5 extern关键字

引用别处定义的函数声明或者全局变量

11.6 static关键字

修饰分以下几种情况:

11.6.1 局部变量

下面的例子可以很好说明:

void fun() {

	//静态局部变量
	static int a = 0;
	//局部变量
	int b = 0;
	a += 1;
	b += 1;
	printf("a = %d b = %d\n", a, b);


}

int main() {
	
	int i = 0;
	while (i < 5) {
		fun();
		++i;
	}

	return 0;


}

 

对于上面这段代码其运行结果为

a = 1 b = 1;
a = 2 b = 1;
a = 3 b = 1;
a = 4 b = 1;
a = 5 b = 1;

因为每次调用调用fun函数的时候局部变量和静态局部变量是不一样的,对于静态局部变量,其存放在.data区域,其只能初始化一次,也就是说第一次的时候被初始化为0,后面就不会再对其初始化了,而对于b由于其是局部变量,所以对于其的初始化每次都可以进行,也就是每次都赋值为0,然后+1操作,而对于a,由于第一次初始化为0成功,后面逐渐对其累加,所以每次打印结果都比上一次+1

11.6.2 全局变量 和 函数

对于两个.c文件,假设是A.c和B.c两个文件,在A.c文件中定义了一个静态全局变量,在A.c中定义了一个静态函数,在B.c中调用extern关键字,想要把A.c中定义的这些静态变量获取到B.c中,这是不能实现的,在编译链接过程中会报错:无法识别的外部符号xxxx。

上面这种情况的代码如下:

test1.cpp

#include<stdio.h>

//全局变量
int g_max = 10;

//静态全局变量
static int g_min = 0;

//函数
void fun() {
	
}
//静态函数
static void print() {

}

test_extern.cpp

#include<stdio.h>

extern int g_max;
extern int g_min;

extern void fun();

extern void print();

int main() {


	fun();
	print();
}

其运行结果如下图: 

 

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值