当前位置: 首页 > article >正文

C语言(一)——初识C语言

目录

简单认识一段代码

数据类型

变量和常量

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

常量

字符串

转义字符

注释

函数

数组

操作符

关键字

结构体

结构的声明

结构成员的类型

结构体变量的初始化

结构体传参


简单认识一段代码

main()函数是程序的入口,所以要有主函数mian(),必须且唯一, int表示整型,“()”中为函数的参数,return 表示返回,0表示整数,为什么返回 0 ,而不返回其他整数,在共识中,认为 0 表示正常返回,约定俗成。

printf为打印,打印的内容用双引号打印,语句结束要用英文分号 “;” 结尾。

【此外:scanf为输入函数 scanf("%d %d", &a, &b) ,其中输入两个数a, b,并用空格分开,“&”表示取地址,如果输入的数据 x 是个数组,就不需要加地址符号“&”, 因为数组名本身就是地址。使用 scanf时添加 #define _CRT_SECURE_NO_WARNINGS,仅限于vs软件编辑。scanf_s是vs平台自有的函数】

printf为库函数,要是用库函数需要引入头文件 # include<stdio.h>

#include<stdio.h>
int main(){
	printf("hello");
    return 0;
}

数据类型

char        //字符串数据类型        用单引号引起

short        //短整型

int        //整型

long         //长整型

long long        //更长的整型

float        //单精度浮点数

double        //双精度浮点数

bool        // 布尔类型        大小是 1

注意:C语言中没有 字符串 类型

每一种类型的大小是多少?

int main() {
	printf("%d\n", 100);	// %d 表示打印整型  \n 表示回车
	printf("%d\n", sizeof(char));	//sizeof 表示某一类型的数据在内存中所占空间的大小
	printf("%zu\n", sizeof(int));	// zu 表示打印一个 sizeof 返回的无符号整型
	printf("%zu\n", sizeof(long));
	printf("%zu\n", sizeof(long long));
	printf("%zu\n", sizeof(float));
	printf("%zu\n", sizeof(double));
	return 0;
}

运行结果:返回的的单位是字节(byte)

计算机中的单位

计算机中的最小单位是比特位(bit)

bit——比特位

byte——字节

kb

mb

gb

pb

计算机中存储方式是二进制,存储 0 或者 1 的大小就是一个比特位的大小, 8个比特位的大小是一个字节

1byte = 8bit        1kb = 1024byte        1mb = 1024kb        ...

C语言规定:

sizeof(long)>=sizeof(int)

例子:类型 int 向内存申请4字节的空间,来存放变量 age。 

int main() {
	int age = 20;
	float price = 66.6;
	return 0;
}

变量和常量

常量是不可变的,如π;变量是可变的,如身高、体重。

在定义变量时要赋值,“初始化”,不然报错“未引用的局部变量”。不进行初始化时,变量中存储的是一个随机值。 

int main() {
	short age = 20;	//年龄
	int height = 180;	//身高
	float weight = 60.5;	//体重
	return 0;
}

变量分为局部变量全局变量

main是一个函数,函数内部定义的变量是局部变量,函数外定义的变量是全局变量。 

int a = 20;
int main() {
	short age = 20;	//年龄
	int height = 180;	//身高
	float weight = 60.5;	//体重
	int b = 20;
	return 0;
}

报错:在同一个范围内,变量不能被重复定义


int main() {
	short age = 20;	//年龄
	int height = 180;	//身高
	float weight = 60.5;	//体重
	int b = 20;
    int b = 200;
	return 0;
}

在函数内部打印变量值时, 如果全局变量和局部变量的名字冲突,则局部变量优先。

建议全局和局部变量的命名不要冲突。

int b = 200;
int main() {
	short age = 20;	//年龄
	int height = 180;	//身高
	float weight = 60.5;	//体重
	int b = 20;
    print("%d", a);
	return 0;
}

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

变量的作用域:变量在哪里可用,哪里就是变量的作用域。

局部变量的作用域是变量所在的局部范围

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

局部变量作用域:

报错:a未定义,a定义在“{}”内,无法在“{}”外直接使用

int main() {
	{
		int a = 10;
		//printf("%d\n", a);
	}	

	printf("%d\n", a);
	return 0;
}

全局变量作用域:

可以应用于整个工程,同一工程下的不同文件同样适用

在同一工程下的 extern.c文件中定义变量

#include<stdio.h>
#define _CRT_SECURE_NO_WARNINGS

int a = 10;

在class_1.c文件中调用

若想使用外部变量,需要使用“extern”声明,“extern”是用来声明一个符号的,“include”是声明一个文件。

extern a;
int main() {
	{
		//int a = 10;
		//printf("%d\n", a);
	}	

	printf("%d\n", a);
	return 0;
}

 运行结果

变量的生命周期:

局部变量的生命周期:进入作用域声明周期开始,出作用域声明周期结束

全局变量的声明周期:整个程序的声明周期

常量

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

  • 字面常量
  • const 修饰的常变量
  • #define定义的标识符常量
  • 枚举常量

字面常量

int main() {
	32;
	3.14;
	'a';	//字符
	"abcde";	//字符串

	return 0;
}

const修饰的常变量

被const修饰的变量不能被修改 。本质是变量,但是不能被修改,有常量的属性。

int main() {

	const int a = 10;
	a = 20;
	return 0;
}

define定义的标识符常量

# define MAX 100
# define STR "abcde"
int main() {

	printf("%d\n", MAX);
	int a = MAX;
	printf("%d\n", a);
	printf("%s", STR);
	return 0;
}

枚举常量

enum 是定义枚举的关键字,枚举的常量一般大写,“{}”中是“Color”的可能取值。

取值是从 0 开始的整型。

enum Color {//枚举类型
	//枚举常量
	RED,
	BLUE,
	GREEN	
};
int main() {
	//使用
	enum Color c = RED;	//申请存储空间
	printf("%d", c);
	return 0;
}

字符串

由双引号引起来的一串字符成为字符串字面值,或者简称为字符串。

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

int main() {

	char ch = 'a';	//单引号引起的是字符
	char arr[] = "cabdef";	//双引号引起的是字符串  '[]'中不写数值时,空间根据内容自动分配

	return 0;
}

两种存放字符串的方式:

int main() {

	char ch = 'a';	//单引号引起的是字符
	char arr[] = "cabdef";	//双引号引起的是字符串  '[]'中不写数值时,空间根据内容自动分配
	char arr2[] = { 'a', 'b', 'c', 'd', 'e', 'f' };
	printf("%s\n", arr);
	printf("%s", arr2);
	return 0;
}

单个字符存储的的arr2没有 “\0” 

打印输出:

为什么使用单个字符存储的方式会输出这样的结果呢?

因为字符串的结束标志是 “\0”, 当打印到“\0”时就不再打印了。

而 arr2 中没有 “\0”,就会一直打印。

如果在 arr2 中主动在最后添加一个元素 “\0”, 那字符串就可以被正常打印。

计算字符串的长度

加头文件 “#include<string.h>”

“\0”不计入字符串长度。

转义字符

“ \ ” 转变原来的意思。

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

        ??)  → ]

        ??(  → [

        现在的编译器已不使用三字母词

\'  :用于表示字符常量  ',防止被解析为引号

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

\\  :用于表示一个反斜杠, 防止他被解释为一个转义字符。常用于路径打印

\a :警告字符,蜂鸣

\b :退格符, 不咋用

\f :进纸符, 不咋用

\n :换行

\r  :回车

\t :水平制表符

\v :垂直制表符

\0 :字符串的结束标志

\ddd :ddd表示1-3个八进制的数字, 如:\130  →  X

        八进制的 130 对应十进制的 88 ,88对应asc码是 “X”

        asc码对应的十进制范围是 0 ~ 127

\xdd :dd表示2个十六进制的数字,如:\x30 → 0

注释

// :单行注释, 多行注释快捷键 ctrl + kc, 取消注释 ctrl + ku  , C++注释,互通

/* :多行注释开始    ,C语言注释,互通

*/ :   多行注释结束 , 缺点:不能嵌套注释

 

函数

定义函数: 

func_name(type param , type  param , ..){

        函数体

        return  返回值

}

调用函数:

type result = func_name(param1, param2);

其中 type表示数据类型如int, float;param表示变量名如x, y。

数组

创建数组

type arr[n] = {...}

根据数组的索引来获取对应元素,索引从 0 开始

不写 n  的值,则根据大括号中的元素个数自动分配空间

打印所有元素:通过所有下标访问所有元素

例子:为什么函数中的输出是 8 ?

因为数组传参的时候传递的是数组首元素的地址,接收地址的变量应该是指针变量。指针变量在64位系统中的大小是 8, 在32位系统中的大小的 4。

 

操作符

算术操作符

+  -  *  /  %    // "/"两端都为整数时, 则只输出整数部分,如 7/2=3  ;“%”两端必须是整数。

移位操作符

>>  <<         // 二进制操作

位操作符

&(与)  ^(异或)  |(或)       //二进制操作

赋值操作符

=    +=   -=   *=   /=   &=   ^=   |=   >>=   <<=      // “a+=b”等同于 a = a + b  

单目操作符:即只对一个元素进行操作  ,如符号两边都有元素则是双目操作符

!   逻辑反操作

-     取负值

+    取正值

&    取地址

sizeof()   操作数的类型长度(以字节为单位)       

        可以计算类型sizeof(int),也可以计算变量的长度;计算变量可以省略括号 即:sizeof x

        如计算数组,则计算的是整个数组的大小,即使数组中只有一个元素,单位是字节。

~    对一个数的二进制按位取反

--    前置、后置--         // 前置的使用规则是先 -- , 后使用

++  前置、后置++        // 后置的使用规则是先使用,后 ++

*     间接访问操作符(解引用操作符)

(类型)    强制类型转换

关系操作符

>

>=

<

<=

!=         用于测试不相等

==        用于测试相等

逻辑操作符

&&        逻辑与

||           逻辑或

条件操作符(三目操作符)

exp1?exp2 : exp3

exp1为真,则执行exp2, 为假则执行exp3

逗号表达式

exp1, exp2, exp3, ... , expn

// 逗号表达式就是由逗号隔开的一系列表达式

// 逗号表达式的特点是 :从左到右依次计算, 整个表达式的结果是最后一个表达式的结果。

下标引用、函数调用和结构成员

[]        ()        .          ->       

关键字

关键字是C语言自带的,不能自己定义

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

auto : 一般省略,所有的局部变量前都有auto

break : 跳出整个循环

const : 修饰常变量

continue : 跳出本次循环

default : switch 的默认值

enum : 枚举

struct : 结构体

union : 联合体

extern : 声明外部符号

goto : 跳转语句

register : 寄存器, 限制变量存到寄存器

signed : 有符号的

unsigned : 无符号的

static : 静态的,修饰函数和变量,限制变量存到静态区

typedef : 类型重命名

void : 函数无返回值

变量的命名:

有意义

名字必须由字母、数字、下划线组成

不能以数字开头

变量名不能是关键字

typedef:将使用不方便,名字过长的类型进行重命名, 将其简化。 注意,只能对类型重命名。

// 将 unsigned int 重新命名为 uint
typedef unsigned int uint;

// 定义一个结构体 struct Node
struct Node {
	int data;
	struct Node* next;
};

// 将 struct Node 重新命名为 Node
typedef struct Node {
	int data;
	struct Node* next;
}Node;

int main() {

	unsigned int num = 0;
	uint num2 = 10;
	struct Node n;
	Node n2;
	return 0;
}

static

static是用来修饰变量和函数的

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

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

        修饰函数-称为静态函数

(1)修饰局部变量

不使用静态局部变量时,每次调用 test()函数,变量 a 都会被重新赋值为 1,每次输出的结果都是 在 1 的基础上 加一。

使用static修饰局部变量后,每次调用test() 时,变量a不会被重新赋值,因为 static 将变量 a 存到了静态区,不会随着 test() 的结束而释放。而 变量 a 已存在于静态区,则 static int a = 1; 就没有意义了。

static修饰的变量的生命周期是整个程序运行过程,不会自动释放。

总结:

static修饰局部变量的时候,局部变量出了作用域,不销毁的。

本质上,static修饰局部变量的时候,改变了变量的存储位置。

存储位置的改变,影响了变量的声明周期

题外话:

内存分为 栈区, 堆区静态区

        栈区是用来存放局部变量等,栈区的特点是,进入作用域创建,出作用域销毁。

        被static修饰后的变量会存放至静态区。存放在静态区的变量出作用域后不会被销毁,程序声明周期结束后,静态区的变量才会随之释放。

(2)修饰全局变量

全局变量具有外部链接属性,即该文件中定义的变量, 可以被该项目下其他文件链接使用。

在一个文件中定义了全局变量 g_val = 100; 在另一个文件中使用 extern 外部变量声明即可使用。输出 g_val 的值。

static修饰全局变量时, 全局变量的外部链接属性就变为了内部链接属性,其他源文件(.c)就不能再使用该全局变量。

被 static 修饰的全局变量,作用域变小。避免被多次使用,修改,保障变量的安全性。

(3)static修饰函数

在同一个源文件中,可以自由调用函数

函数也具有外部链接属性

使用 extern 声明函数,即可调用其他源文件中的 函数。 

static修饰函数时, 函数的外部链接属性就变为了内部链接属性,其他源文件(.c)就不能再使用该函数。同全局变量。

register - 寄存器

电脑上的存储设备有哪些?

寄存器(集成到CPU上)

高速缓存(cache)

内存

硬盘

寄存器读写速度更快,空间更小,造价更高。

现在的编译器会自动将变量放到寄存器中,提高处理速度,前提是寄存器有空间。 

define定义常量和宏

定义常量

定义宏,有点 类似于 lamda

宏的定义

ADD(param, param2)  express

ADD是宏名(可大写可小写,一般大写便于区分), paramn是无类型参数, express是宏体,类似于函数体

结构体

结构体是一些值的集合,这些值称为成员变量,结构的每个成员可以是不同类型的变量。 

自定义类型的功能

结构体是把一些单一类型组合在一起。可以用来描述复杂对象。 

结构的声明

// 结构类型 结构名
struct Stu{
	// 成员
	char name[20];
	int age;
	char sex[10];
	char tel[20];
} p1, p2;  // p1 p2 是通过结构体类型创建的两个变量(全局变量),可以省略

结构成员的类型

结构的成员可以是标量、数组、指针,也可以是其他结构体变量。

struct Stu {
	// 成员
	char name[20];
	int age;
	char sex[10];
	char tel[20];
} 

struct Peo {
	struct Stu p;
	int num;
	float f;
};

结构体变量的初始化

// 结构类型 结构名
struct Stu {
	// 成员
	char name[20];
	int age;
	char sex[10];
	char tel[20];
};

struct Peo
{
	struct Stu s;
	float hight;
	float weight;
};

int main() {

	struct Stu p1 = {"Billie", 18, "woman", "12342385"};	// 结构体变量的创建及初始化
	struct Peo p2 = { {"Billie", 18, "woman", "12342385"}, 165.5f, 52.2f };

	printf("%s %d %s %s\n", p1.name, p1.age, p1.sex, p1.tel);
	printf("%s %d %s %s %f %f\n", p2.s.name, p2.s.age, p2.s.sex, p2.s.tel, p2.hight, p2.weight);
	return 0;
}

结构体传参

传地址优于传对象

传对象作为形参时会单独创建额外的空间 

函数传参的时候,参数是需要压栈的。

如果传递一个结构体对象的时候,结构体过大,参数压栈的系统开销比较大, 所以会导致性能的下降。  

// 结构类型 结构名
struct Stu {
	// 成员
	char name[20];
	int age;
	char sex[10];
	char tel[20];
};

struct Peo
{
	struct Stu s;
	float hight;
	float weight;
};

void print1(struct Peo* p){
	printf("%s %d %s %s %f %f\n",  p->s.name, p->s.age, p->s.sex, p->s.tel, p->hight, p->weight);
}

void print2(struct Peo p) {
	printf("%s %d %s %s %f %f\n", p.s.name, p.s.age, p.s.sex, p.s.tel, p.hight, p.weight);
}

int main() {

	struct Stu p1 = {"Billie", 18, "woman", "12342385"};	// 结构体变量的创建及初始化
	struct Peo p2 = { {"Billie", 18, "woman", "12342385"}, 165.5f, 52.2f };

	printf("%s %d %s %s\n", p1.name, p1.age, p1.sex, p1.tel);
	printf("%s %d %s %s %f %f\n", p2.s.name, p2.s.age, p2.s.sex, p2.s.tel, p2.hight, p2.weight);
	print1(&p2);
	print2(p2);
	return 0;
}


http://www.kler.cn/a/448953.html

相关文章:

  • jsp | servlet | spring forEach读取不了对象List
  • OpenHarmony的分布式服务框架介绍与实现解析
  • R 语言 | 绘图的文字格式(绘制上标、下标、斜体、文字标注等)
  • leetcode-128.最长连续序列-day14
  • TCP与UDP的端口连通性
  • 基于微信小程序的乡村旅游系统
  • Django 视图中使用 Redis 缓存优化查询性能
  • 初识C语言之二维数组(下)
  • npm install vue-router失败解决办法
  • 4.2V单节锂电池充电电路(TP4056)、USB与锂电池切换电路分享
  • Github优质项目推荐(第九期)
  • QT_Demo(1)之实现多线程实现简单的电脑摄像头视频流开关
  • 叉车作业如何确认安全距离——UWB测距防撞系统的应用
  • Kubernetes APF(API 优先级和公平调度)简介
  • guava本地缓存+自定义线程工厂和线程池
  • Day 15:Spring 框架基础
  • Sass变量的妙用:提升CSS开发效率与可维护性
  • Web安全攻防入门教程——hvv行动详解
  • 深入理解 OpenCV 的距离变换(cv2.distanceTransform)及其应用
  • 生鲜电商新篇章:在线销售系统的创新设计
  • 二叉树总结
  • 【IMU:视觉惯性SLAM系统】
  • Redis分布式锁释放锁是否必须用lua脚本?
  • 聊一聊性能测试是如何开展的?
  • Unittest框架及自动化测试实现流程
  • Blender 中投影仪的配置与使用