C语言_自用笔记

目录

1. 基本数据类型

基本数据类型的使用方法

2. 常量和变量其生命周期和作用域

常量

变量

生命周期和作用域

3. 字符串和转义字符

字符串

strlen()函数

转义字符

4. 选择语句

if语句

switch语句

​编辑

5. 循环语句

while循环

For循环

do while循环

循环语句的重要关键字

6. 函数

函数是什么

自定义一个函数

函数的形参和实参

​编辑

嵌套和链式调用

函数的声明和定义

标准化的函数使用

​编辑

7. 数组

数组的定义

8. 操作符

算数操作符

移位操作符

位操作符

赋值操作符

单目操作符

关系操作符

逻辑操作符

三目运算符

逗号表达式

9. 常量和宏

10.指针

基础的使用

指针类型的大小

11. struct结构体

创建一个结构体类型

创建结构体类型的变量

调用结构体类型变量的成员方法

Struct类型的大小


1. 基本数据类型

  1. char_字符型
  2. short_短整型
  3. int _整型
  4. long_长整型
  5. long long_更长整型
  6. float_单精度浮点型
  7. double_双精度浮点型

其中整型 提供了四种不同的数据类型,在使用时可以按照需求来选择合适的类型

基本数据类型的使用方法

1. 先定义后初始化

	int age,number;
	age = 0;
	number = 15;

2.定义并初始化

int date = 6;

C语言中提供了 sizeof()函数可以用来查看该数据类型所占空间的大小

#include <stdio.h>

int main()
{
	printf("%d",sizeof(int));

	return 0;
}

2. 常量和变量其生命周期和作用域

常量

常量是指一旦定义就无法修改的值,一旦出现修改操作,程序运行会报错

定义的常量的方法

        1. 字面常量(使用较少)

int main()
{
	30; //整型的字面常量
	'w';//字符型的字面常量
	15.5;//浮点型的字面常量

	return 0;
}

        2.const修饰的常变量(用const修饰的变量是无法被修改的,不过这个常变量本身还是一个变量)

const int age = 10;

        3.#define 定义的标识符常量

#include <stdio.h>

#define MAX 1000 //标识符常量 

int main()
{
	return 0;
}

        4.枚举常量(固定的一个或者多个值)

enum SEX  //枚举类型的常量
{
	MALE,
	FEMALE,
	SECRECY
};

int main()
{
	SEX sex;//定义一个枚举类型的变量
	sex = MALE; //变量的赋值仅可以是该枚举中定义的几个选择

	return 0;
}

变量

在需要时可以随时被修改的数据的称为变量

	int age = 18;//定义一个变量

	age = 20;//修改该变量的值

变量又分为全局变量和局部变量,全局变量和局部变量可以重名但是不推荐,在重名的情况下访问变量,遵循就近原则!

int age = 20;//定义一个全局变量

int main()
{
	int age = 18;//定义一个变量

	return 0;
}

生命周期和作用域

生命周期

局部变量的生命周期在进入该代码块时变量生效,该代码块结束后变量销毁

全局变量的生命周期在程序开始时生效,程序结束后销毁

作用域

局部变量仅在代码块中生效,出了代码块后无法调用

全局变量在整个工程中的各个位置都可以调用(有时候需要声明)

3. 字符串和转义字符

字符串

C语言的中的字符串需要使用字符数组来存储且需要以\0 来结尾表示字符串结束

int main()
{
	char arr1[] = "MAX";  //默认存在\0
	char arr2[] = { 'M','A','X' }; //没有\0

	printf("arr1:%s \n", arr1);
	printf("arr2:%s \n", arr2);

	return 0;
}

  输出结果

char arr2[] = { 'M','A','X' }; 这种定义方式需要手动添加'\0'结尾表示结束,否则就会如图所示会一直往后输出知道内存中出现对应\0的数值才停止

strlen()函数

C语言中提供了strlen()函数 可以判断字符串的长度 返回值为int

转义字符

转义字符   释义
\? 在书写连续多个问号时使用,防止他们被解析成三字母词
\` 用于表示字符常量`
\" 用于表示一个字符产内部的双引号
\\   用于表示一个反斜杠,防止它被解释为一个转义序列符
\a 警告字符,蜂鸣
\b退格符
\f  进纸符
\n 换行
\r回车
\t 水平制表符
\v垂直制表符
\dddddd表示1~3个八进制的数字。如:\130X
\xdddd表示2个十六进制数字。如:\x30 0

4. 选择语句

选择语句即字面意思:代码可以根据某种条件判断,来选择接下来要执行哪段代码,程序设计语言默认都是从上而下依次执行代码指令的(顺序结构),但是仅仅顺序结构是无法满足代码需求

if语句

	if (条件判断) 
	{
		//条件为真进入该代码块执行代码,条件为假,则跳过这个代码块
	}
	else if (条件判断) {
		//条件为真进入该代码块执行代码,条件为假,则跳过这个代码块
	}
	else {
		//上面所有的条件判断为假,则执行该段代码块
	}

如果条件判断后面只有一条语句可以不写大括号(注意:else只和离他最近的if做绑定)

	if (age >= 18) 
		printf("老板晚上好!欢迎进入***会所!");
	else
		printf("给你一块钱,去坐摇摇车!");

可以嵌套使用,可以有多个else if分支判断

switch语句

和if一样作用只是写法不同 if是条件判断,switch是直接提供选择项

#include <stdio.h>
#include <string.h>



int main()
{
	int day = 118;

	switch (day) {//传入选项的序号 1,2,3,4.....
	case 1://选择项1
		printf("周一");
		break;
	case 2://选择项2
		printf("周一");
		break;
	case 3://选择项3
		printf("周一");
		break;
	case 4:
		printf("周一");
		break;
	case 5:
		printf("周一");
		break;
	case 6:
		printf("周一");
		break;
	case 7:
		printf("周一");
		break;

	default:
		printf("输入的值只能是1~7的范围! \n");

	}


	return 0;
}

注意:

传入Switch()的变量必须是一个整型,不能是其他类型,选择项也一样必须是整数类型的字面量 : case 1  case 2 case 3 .....................   否则报错

每个选项项都要以break结尾,否则该选择项执行完后,会继续向下执行知道执行完后面的所有选择项或者遇到break才会停止

defuault 关键字 用来收尾,当用户输入的数值非选择项中提供的数值就会执行defualt下的代码,当defualt放在最后的时候可以不写break;

5. 循环语句

和打游戏一样,先重复的刷怪升级,吸取经验,直到要求的等级条件满足后,开启新的副本,进入新的区域

while循环

	int i = 0;
	while (i <= 10)//条件判断 是否为真 真则进入,假则跳过
	{
		//循环执行的代码
		printf("欢迎光临!");
		i++;
	}

i++ 用于改变条件判断的值,如果i 不做调整 则 i <=10 为真恒成立,会进入到一个死循环

For循环

	for (int i = 0 ; i<=10 ; i++) 
	{
		//要循环的内容
	}

For循环中条件的 判断,定义,调整 都在小括号中

For循环写死循环的方法

	for (;;) {
		//要循环的内容
	}

do while循环

Do while 是先执行一次循环体内的代码在进行条件判断的

	int i = 0; //定义的一个用来判断的变量
	do {

		//要循环的内容
		i++; //对用的判断的变量做调整

	} while (i < 100);

循环语句的重要关键字

Break;

直接结束循环跳出该循环执行后面的代码

continue;

结束当前循环,开始下一次的循环

6. 函数

高级程序设计语言中,都提供有官方收录或编写的库函数,可以帮助开发者完成一些特定功能 C语言中的main() printf() scanf()这些新手必会的 都是函数, 我们不需要知道prntf()是怎么实现将字符输出到屏幕上的,只需要知道 printf()如何使用就可以将输入的内容输出到屏幕,

 

当然我们也可以自定义一个函数,来实现我们想要完成的功能

函数是什么

维基百科中函数的定义是:子程序
是一个大型工程中的一小部分代码,子程序相对独立,可以独自完成一些特定的工作
子程序的特点: ①有返回值    ②可以传入参数    ③ 处理方式是隐藏起来的对外不可见(封装)

自定义一个函数

自定义函数和官方函数库中函数,一样的编写方式也是一样的调用

                                格式: 返回类型 函数名 (形参){

                                         函数体(该函数要实现的具体功能)

                                         }

//函数说明: 传入两个整数,返回值为这两个整数的和  返回类型int
int sum(int a, int b) {

	return a + b;
}
int main()
{

	int number = sum(15, 20); //调用函数传入实参,并将函数返回值赋值给变量number

	printf("结果为:%d", number);//输出 结果为:35

	return 0;
}

函数的形参和实参

定义函数时里小括号里面的是形参

调用函数时,小括号中填写的参数就是实参

而参数的传递有两类 一种是传值  一种是传值,根据要处理的问题情况选择即可

举例 : 实现两个数值的交换

要实现这个功能 使用传值操作是无法实现的!这里涉及到存储地址的问题,虽然实参是 a,b 函数中也是a,b 但是这两组ab指向的地址是不同的,可以理解成,调用的函数中的ab 是实参ab的一个复制品,该函数也确实实现了 两个变量交换值,但是交换的是复制品的那一组a,b, 函数外部的ab始终没变

#include <stdio.h>
#include <string.h>


//函数说明: 传入两个整数,实现交换的功能,无返回值
void flips(int a, int b) {

	int temp = 0; //创建一个临时变量来辅助完整交换工作

	temp = a;//三步完成交换 不需要返回值
	a = b;
	b = temp;
}


int main()
{
	int a = 5;
	int b = 15;
	flips(a, b);

	printf("a的值为 : %d  b的值为 : %d \n");

	return 0;
}

所以这种情况下需要传地址 才可以对同一地址下的内容进行修改

#include <stdio.h>
#include <string.h>


//函数说明: 传入两个整数,实现交换的功能,无返回值
void flips(int * pa, int* pb) {

	int temp = 0; //创建一个临时变量来辅助完整交换工作

	temp = *pa;//三步完成交换 不需要返回值
	*pa = *pb;
	*pb = temp;
}


int main()
{
	int a = 5;
	int b = 15;
	flips(&a, &b);

	printf("a的值为 : %d  b的值为 : %d \n", a ,b);

	return 0;
}

嵌套和链式调用

函数时一段相对独立的代码,他不可以嵌套定义,比如在一个函数中定义另一个函数,这是绝对不允许的,但是函数时可以嵌套调用的,例如 A函数中调用B函数,B函数中调用C函数

链式调用:将函数的返回值作为另一个函数的实参

printf("%d", printf("%d", printf("%d",42)));

prinft()函数官方文档中说明 返回的是字符的个数  所以最后输出结果为: 4221

函数的声明和定义

如果调用函数在函数定义之前,需要在调用前声明函数,因为程序是自上而下执行的,编译器在执行到调用函数这一段代码时,并没有发现函数的定义,会报错,所以提前声明的目的是为了告诉编译器,我们有这个函数,不用报错提醒

标准化的函数使用

正经编写程序时,使用的都是模块化管理,函数的声明在头文件中,编写在c文件中,调用在主函数中 
举例:如果在交易中不想出售源码 就是打包代码成静态库,只提供静态库文件和头文件即可,买家通过头文件查看函数如何使用即可,而函数打包成静态库后 是无法查看c文件的

头文件中声明

c文件中编写函数的功能

主函数中调用 要先导入头文件才可以使用

函数的递归

使用递归必须要有一个限制调用的条件
每次调用后两件个条件的判断会越来越接近,直到不满足

 逻辑图表示(内存布局暂时略过)

编写一个可以计算字符串长度的函数,使用递归解决

#include <stdio.h>
#include <string.h>


int strleng(char str[]) {

	int i = 0;

	if (*str != '\0') {
		 i = strleng(str + 1) + 1;
	}

	return i;
}


int main()
{
	char str[] = "open";//字符长度为4
	//系统库的sizeof()提供了判断类型大小的方法,刚好和字符串char[]一个字节一个字符
	//printf("%d", sizeof(str));

	//使用递归来解决
	strleng(str);//数组名就是该数组的首地址所以这是一个传地址操作
	printf("长度为: %d", strleng(str));
	return 0;
}


逻辑示意图

或者更简洁一点

int strleng(char str[]) {

	if (*str != '\0')
		return strleng(str + 1) + 1;
	else
		return 0;
}

递归虽然好用,但是逻辑复杂了,解决问题的时候很难想到,先能做到看懂别人写的就行了,慢慢来

7. 数组

一组相同数据类型的元素的集合

数组的定义

	int arr[10] = { 0 };//定义一个数组大小为10个int 并初始化全部为0

	int arr1[10] = { 1,2,3,4,5,6 };//定义一个数组大小为10个int 并初始化部分空间

	int arr2[10];//定义了一个数组没有初始化
	arr2[3] = 8;//将下标为3的位置初始化为8  默认下标从0开始

	int arr3[] = { 1,2,3,4,5,6 };//定义一个数组并初始化,数组大小由初始化的数量决定

8. 操作符

算数操作符

操作符  说明

+

加法
-减法
*乘法
/除法
%取余

移位操作符

操作符说明
>>右移运算符
<<左移运算符
	int i = 1;
	int j =  i>>1 ;//往右移 1 位

	//  1 内存中表示 00000000 00000000 00000000 00000001
	//	右移 1 位后  00000000 00000000 00000000 00000000
	//所以输出结果为 0 
	printf("%d", j);
	int i = 1;
	int j =  i<<1 ;//往左移 1 位

	//  1 内存中表示 00000000 00000000 00000000 00000001
	//	左移 1 位后  00000000 00000000 00000000 00000010  低位默认补零
	//  输出结果为 2 
	printf("%d", j);

位操作符

操作符 说明
&按位与(两个二进制数做比较 : 两个都为真结果为真)
|按位或(两个二进制数做比较 : 一个为真结果就为真)
^按位异或(单个二进制数 : 真变假,假变真)

赋值操作符

操作符说明
=赋值

+=

相加后赋值    a += 1  等价于  a = a+1
-=相减后赋值
*=相乘后赋值
/=相除后赋值
^=按位异或后赋值
|=按位或后赋值
>>=右位移后赋值  a >>=1 等价于 a = a>>1
<<=左位移后赋值

单目操作符

操作符说明
!逻辑取反(真变假,假变真)
-负号
+正号
&取地址符
sizeof()求长度符
~一个数的二进制按位取反
--自减
++自增
*间接访问操作符
(类型)强制转换类型

关系操作符

操作符说明
>大于
<小于
>=大于等于
<=小于等于
==全等于
!=不等于

逻辑操作符

操作符说明
&&并  两个都为真即为真
||或  一个为真即为真

三目运算符

条件 ?:

printf("%s", 5 > 10 ? "正确!" : "错误!");//条件判断为真即返回正确 假返回错误

逗号表达式

并不常见;

	int a = 1;
	int b = 3;
	int c = 3;
	int d = (++a, b + a, c + b);//逗号表达式会从左往右运算,直到求出最后一个结果后在赋值
	printf("%d", d); // c+b = 6 即输出值为6


9. 常量和宏

已知常量可以通过 #define 来定义,但是其不仅可以定义常量还可以定义宏

宏定义又称为宏替换是一种预处理指令

#include <stdio.h>
#include <string.h>

#define AGE "今晚打老虎" //定义了一个宏 也可以理解成定义了一个常量 按需使用
#define ADD(x,y) x+y

int main()
{
	char motto[] = AGE; //默认将全局的AGE替换字符串:"今晚打老虎" 不过字符串中不生效
	printf("motto : %s  \n", motto);

	int i = ADD(15, 20); //等价于 int i = 15 + 20  看着像调用函数,但根本不是,只是做了ADD关键字的替换
	printf("i=%d  \n",i);//输出35

    //证明是替换
	i = 2 * ADD(15, 20); //等价于 i = 2 * 15 + 20 输出50 而非 70
	printf("i=%d  \n", i);

	return 0;
}

注意事项:


        宏名一般用大写

        宏定义末尾不加分号;

        可以用#undef命令终止宏定义的作用域

        宏定义可以嵌套

        字符串“”中永远不包含宏

还有一些偏门用法不用记

10.指针

指针是编程语言中的一个对象,存放一个地址在他的内存空间,可以通过这个地址直接访问到计算机存储器中某个地址的值

基础的使用

1. 首先定义一个普通变量

nt a = 10;

2. 在定义一个指针变量  *说明这是一个指针   int说明该指针是要指向int类型的地址的  p就是是变量名

int* p;

3. &取地址符  将变量a的地址存放到 指针变量p中

p = &a;

4. * 是单目操作符 作用是解引用     *p 解析p中存放的地址并进行访问  *p == a  

printf("%d  \n",*p); 

5. 所以直接对*p赋值的话 a也会随之改变

*p = 15;
printf("*p: %d a: %d \n", *p,a);// 都输出15

6. 同理修改a也是一样的

a = 20;
printf("*p: %d a: %d \n", *p, a);

#include <stdio.h>
#include <string.h>


int main()
{

	int a = 10;//定义了一个变量

	//定义了一个指针   *说明这是一个指针   int说明该指针是要指向int类型的地址的  p就是是变量名
	int* p;
	//* 是单目操作符 作用是解引用

	p = &a;//&取地址符  将变量a的地址存放到 指针变量p中

	//*p 解析p中存放的地址并进行访问  *p == a    
	printf("%d  \n",*p); 
	//所以直接对*p赋值的话 a也会随之改变
	*p = 15;
	printf("*p: %d a: %d \n", *p,a);
	//修改a也是一样的
	a = 20;
	printf("*p: %d a: %d \n", *p, a);


	return 0;
}

指针类型的大小

指针类型的大小由计算机的寻址能力来决定,因为指针类型存放的就是地址,所以只需要满足该计算机的最大寻址范围即可,32位的计算机地址总线为32位,即最大寻址范围为4个字节 所以32为计算机上sizeof返回的结果是 4字节  同理64位的就是8个字节

为什么要指定指针类型

指针的大小由计算机的寻址能力决定,同一台计算机中,他们的大小一样,存储的值也是一样都是地址,那为什么要区分指针的类型,为什么没有通用的类型

指定指针的类型是为了告诉指针该如何访问内存单元,例如 int 4个内存单元   char 1个内存单元
当我们使用char 类型的指针 访问 int 类型的指针时, 他会以为该地址存放的就是一个char类型的数据,所以只访问一个内存单元就会结束, 而用int 类型的指针,访问 char类型的地址时,指针会认为这里存放的是一个int类型的数据,访问四个内存单元,这就是指定指针类型的用处

现在编译器会直接爆红,不用刻意关注

指针的运算

指针可以进行 加 或 减的运算

指针的运算,关键在于指针的类型, int类型举例 int类型的指针 +1即向后偏移4个字节

arr的地址               : 0x000000811b0ffc88
指针 p +1后地址为 : 0x000000811b0ffc8c

指针的运算,需要是同一空间的中的指针, 指针 - 指针是求这两个指针的元素个数

#include <stdio.h>
#include <string.h>


int main()
{
	
	int arr[] = {1,2,3,4,5,6,7,8,9};
	int* p = arr; //数组名就是数组第一个元素的地址 即下标为0 的元素

	printf("%d \n", *(p + 8) - *p); //输出8
	printf("%d \n", *(p+8) - *(p+1)); //输出7

	return 0;
}

11. struct结构体

在C语言中算是比较重要的一个知识点,类似于高级语言的类和对象

创建一个结构体类型

Struct结构体可以用来定义一个复杂的类型
例如要创建一个学生类型
学生应该包含 年龄 性别 成绩这些属性 统称成员变量

struct Student //定义了一个学生类型的结构体
{
	//学生类型包含的属性例如: 年龄 性别 成绩 这个三个统称成员变量 在结构体中定义

	int age;
	char sex;
	double grades;

};

创建结构体类型的变量

使用一个创建好的结构体类型,和我们使用普通数据类型一样,通过结构体类型创建变量并初始化即可

struct Student one = { 18,'N',95.5 };//创建一个学生类型的变量,并初始化它的成员变量

也可以逐个初始化

	struct Student one;//创建一个学生类型的变量
	one.age = 18;
	one.grades = 95;
	one.sex = 'N';

区别在于一个需要按照顺序初始化,一个不需要

调用结构体类型变量的成员方法

 . 操作符
 

printf("one:%d_%c_%lf \n", one.age, one.sex, one.grades);

2  -> 操作符  需要配合指针类型使用

struct Student* p;//创建一个Student类型的指针
p = &one; //指针指向同类类型的变量one

printf("one:%d_%c_%lf \n", p->age,p->sex,p->grades);

3  *解引用操作符(不推荐_麻烦)

printf("one:%d_%c_%lf \n", (*p).age, (*p).sex, (*p).grades);

#include <stdio.h>
#include <string.h>


struct Student //定义了一个学生类型的结构体
{
	//学生类型的复杂对象应该包含的属性例如: 年龄 性别 成绩 这个三个统称成员变量 在结构体中定义

	int age;
	char sex;
	double grades;

};

int main()
{
	//结构体构建完成后就可以使用创建的结构体类型来定义变量了

	struct Student one;//创建一个学生类型的变量,并初始化它的成员变量
	one.age = 18;
	one.grades = 95;
	one.sex = 'N';


	//调用成员变量的方法
	//1   .操作符
	printf("one:%d_%c_%lf \n", one.age, one.sex, one.grades);

	//2   ->操作符 需要配合指针类型使用
	struct Student* p;//创建一个Student类型的指针
	p = &one; //指针指向同类类型的变量one

	printf("one:%d_%c_%lf \n", p->age,p->sex,p->grades);

	//3  *解引用操作符(不推荐_麻烦)
	printf("one:%d_%c_%lf \n", (*p).age, (*p).sex, (*p).grades);

}

Struct类型的大小

struct Student //定义了一个学生类型的结构体
{
	int age;
	char sex;
	double grades;
};

sizeof()函数求大小

printf("Student类型的大小: %d 字节", sizeof(Student)); 

认为 Student =  sizeof(int) + sizeof(char) + sizeof(double) = 13字节 那就错了!

Struct的大小是如何计算的

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值