C语言学习笔记(1)

在学习前,需要有一定的C语言基础。不必很深入,只需要知道函数,头文件,指针,数组等的概念就可以,但并非0基础笔记。

由于写到后面,不好编辑了,决定分成多篇写,请按编号学习,或者直接看目录先。将会包括,c,c++,linunx_C系列

其他内容将放在入门到精通专栏里面

说明:该文章来自本人学习时的笔记,使用的编译器是Visual Studio,如有错误,可以在评论区或者私信我纠正,谢谢 

1.前提知识

1.1项目结构

1.2 visual Studio导出模板

1.3预处理

预处理指令:以#开头的

转移符:\r

#include <stdio.h>	//预处理

int main (void){	//C语言里面,标准必须加void表示不定形参,c++空括号不加表示void
	printf("hello world\r");	//  \反斜杠   /斜杆  \r转义序列
	return 0;
}

预处理:

预处理:把头文件复制到文件里面

# include<stdio.h>	//把头文件复制过去

宏定义:

# define N 5 //代码里面N会在预处理的时候被直接替换为5

宏函数

# define FOO(x)  (1+(x)*(x))  //在预处理的时候会直接把宏函数内容替换
							//整个表达式要用括号括起来,第一个左括号要贴紧宏函数,参数要用括号括起来
							//调用宏函数没有调用函数的开销,可以避免简单重复的函数调用
							//提供了一定的宏编程

多行宏函数:用\换行

#define SWAP(a,b){\
		int t=a;\
		a=b;\
		b=t;\
	}

1.4编译和链接

预处理、编译、汇编、链接

1.5进程的虚拟内存空间

内核  	//和内核交互
栈		//管理函数调用
()
堆		//存放动态数据
数据段	   //
代码段

1.6 注释

只在必要的时候写注释

2.变量

三要素:变量名、类型、值

2.1标识符

2.2关键字

在C语言里面有特殊含义的标识符

3.输入输出模型

3类资源:CPU、内存、外存

3.1 printf 格式化输出

%m.px    //最少占有m个位置,在前面补空格   |   最少显示p个数字,不足的前面补0    |  x表示输出格式
%-m.px	//在后面补空格

3.2 scanf 格式化输入

%d	//忽略前置空白字符,匹配一个十进制整数
%f  //忽略前置空白字符,匹配一个浮点数
格式串  //精确匹配
空白字符 //匹配任意个空白字符

3.3scanf忽略空白字符

scanf("%c %c");//跳过空白字符匹配下一个非空白字符

3.4 putchar与getchar的使用 

char c='A';
putchar(c);//输出c的字符
c=getchar();//用于输入一个字符


//惯用法
while(getchar=!='\n'){//跳过换行符后的剩余的字符
};

4.一些基本算法

4.1不分类
4.1.1求最大公约数

#求最大公约数
int gcd(int a, int b) {
	if (a < b) {
		SWAP(a, b);
	}
	while (b != 0) {
		int r = a % b;
		a = b;
		b = r;
	}
	return a;
}

4.1.1判断是否为素数

函数的功能应该越单一越好,既然要判断一个数是不是素数,实现的功能只需要返回是或者不是,不要加其他多余的东西提高代码的复用率。

bool is_Prime(int n){
	int rt = sqrt(n);
	for(int i=2;i<=rt;i++){
		if(n%i==0){
			return false;
		}
	}
	return true;
}

4.2位运算

4.2.1交换两个数的值(不用中间变量)

可以这么做,但不建议,代码可读性很差

//交换方法1:可能出现溢出问题
a=a+b;
b=a-b;
a=a-b;
//交换方法2:可读性很差
a=a^b;
b=a^b;
a=a^b;

 4.2.2找数组中唯一的单独的一个数

Q:数组中有一个元素出现过一次,其余元素出现过两次,找这个单独的元素

int findSingleNum(int nums[],int n){
	int singleNum=0;
	for(int i=0;i<n;i++){
		singleNum^=nums[i];//相同的数异或两次同一个数会变回原来的,
                            //唯一的单独数异或以后会存在singleNum中
	}
	return singleNum;
}

4.2.3找两个元素

Q:数组中有两个元素出现过一次,其余两个元素都出现过两次,找这两个单独出现的元素,可以按任意顺序返回答案

思路:

先求xor=a^b

xor正数与xor负数的补码表示上,在最低有效位上相差1

lsb即xor^(-xor)的值为xor的最低有效位为1,其他位为0的结果

a和b在这一位上一个为1一个为0

分类以后回归到2.2的题目

void findTwoNums(int nums[], int n) {
	int Xor = 0;
	for (int i = 0; i < n; i++) {
		Xor ^= nums[i];//xor=a^b
	}
	int lsb = Xor ^ (-Xor); //a和b在这一位上不同
	//根据这一位将所有元素分类
	int a = 0, b = 0;
	for (int i = 0; i < n; i++) {
		if (nums[i]&lsb) {
			a ^= nums[i];//相同的数一定会两次都和a或b相与,结果不变
		} else {
			b^=nums[i];
		}
	}
	printf("两个数分别是 %d 和 %d \n",a,b);
}

5.编码

无符号整数(二进制编码)

有符号整数(补码)

Q:为什么用补码做有符号整数编码?

A:因为可以用加法达到减法的效果。

 5.1 ASCII字符编码

5.1.1编码表

5.1.2大小写字母转换

int c=0x70;//P的编码
int tolower(int c);//把P转化为p
int toupper(int c);//把P转化为p

5.2字符转义序列

5.3数字转义序列

八进制(最多3位数字):‘\000’

十六进制转义序列:'\x000'

查看手册网址:C reference - cppreference.com

6.类型转换

6.1隐式转换

不同类型运算隐式转换,编译器会帮你自动转化为下一个等级

6.1.1整数提升

int -> long  ->  long long  ->  float  ->  double  ->  long double

6.1.2同一整数等级的转换

signed  ->  unsigned

提示:千万不要把无符号整数与有符号整数混合运算

6.2显示转换(强制转化)

int a=10;
float f;
f=(float)a;

6.3定义别名

Q的作用等价于int,重命名的目的是提高代码可读性

typedef的可移植性强,可以在前面定义别名的使用,只需要改变一次

比如int在桌面端占用4个字节,在嵌入式的时候可能就只有两个字节,只需要把重命名的前面的类型改变,比如嵌入式中int占用2字节,long占用4字节,只需要把int改为long就可以恢复桌面端占用4字节int的效果。

typedef int Q;//把int重命名为Q
Q a=0;//a是int类型

6.4sizeof计算长度

计算类型的时候sizeof时需要加上括号,本质上sizeof不是函数而是运算符。直接每次都加括号就好

int len=sizeof(int);//可以
printf("%d",len);

7.运算符

7.1赋值表达式

发生的过程为

i=3.14;//i被赋值为3

f=i;//f被赋值为3.00

int i;
float f;
f=i=3.14;//f的值为3.00,i的值为3

7.2自增

i++与++i

不必理会先自增还是后自增

把其理会为i=1,执行完语句以后副作用是会自增1

7.3位运算

7.3.1移位运算符

左移 <<,右移>>

在没有溢出的前提下,相当于左乘2,右除2

最好只对无符号整数进行移位运算

7.3.2按位运算符

~按位取反

&按位与,全1才1

|按位或,有1就1

^按位异或,同0异1

7.3.3位运算的性质

1.只能用于整数运算

2.有交换律和结合率

3.除了取反运算符都可以和等号结合变成复合运算符

        i^=j等价于 i=i^1

7.4算术运算符

8.调试

8.1三种错误

1.编译错误:

C***:语法错误

2.链接错误:

LNK***:缺少头文件/函数名写错了

3.运行时错误:

运行时错误往往是逻辑错误,也就是需要调试,也就是常说的bug

8.2调试方式

1.打断点

2.调试在这边,左边的红色圆点是断点

3.开始调试以后,会直接运行到第一个断点,并把断点的上一行运行完,断点这行还没有运行

4.继续运行

点击继续会运行到下一个断点

5.逐语句运行

顾名思义,就是一条一条语句往下执行,点一下运行一条,遇到函数会跳到被调函数里面

6.逐过程运行

遇到函数会直接完成函数的过程直到下一个断点,不会跳到函数里面一行一行运行,而是直接完成函数的整个过程。

点击逐过程会直接完成Foo函数的运行,到下一个断点

7.跳出

在调试的过程中,发现函数没有问题,直接完成函数的运行跳出被调函数,回到主调函数里面

9.语句

9.1语句分类

表达式语句

选择语句:if     switch

循环语句 :while     do...while    for

跳转语句:continue ,break , goto  ,return

空语句:     ;

复合语句:{   }

9.2 switch语句

解决的问题:效率低,可读性差,运行效率比if-else高

限制条件:

1.switch后面的表达式是必须是整型(char,枚举)

2.switch后面的表达式与标签case是用==比较的

switch (a) {
	case 1:
		//TODO
		break;
	case 2:
		//TODO
		break;
	default:
		//TODO
		break;
}

注意事项:

1.可以多个case公用一组语句

2.会出现case穿透现象(在利用的时候,在下面要加上break through的注释,表示特意要让他穿透的)

switch (a) {
	case 1:case 2://1和2都运行下面这个TODO
		//TODO
		break;
	default:
		//TODO
		break;
}

10.数组

数组的单元叫元素,结构体的单元叫成员

10.1数组的内存模型

连续的一片的内存空间,有随机访问的性质。

数组的索引不是代表第几个元素,而是代表与第一个元素的偏移量

刻板印象:数组效率>链表效率

        1.空间利用率

        2.计算机按块读,数组的空间局部性好

  

10.2数组的定义

int arr[4];//声明一个数组
//变量名为arr
//类型为int[4]

10.3常数

const

11.随机

srand(time(null)):随机种子,一般只需要生成一次,一般这个数非常大,往往需要取余

rand:随机生成一个伪随机数

time:1970.1.1.00:00到现在的时间,要包括time.h

12.函数

12.1与数学函数的比较

数学:有返回值,没有副作用

C语言:可以没有返回值,可以有副作用

12.2准则

1.函数的功能应该越单一越好,函数的实现应该越高效越好

2.函数是c语言的基本构建组件,c语言的本质就是函数之间的调用,做开发的时候,要聚焦于函数,而不是细节

12.3函数相关概念

函数定义:void foo(int a){...}

函数声明:void foo(int a);

函数调用:foo(3);

函数指针:foo     ,&foo

12.4值传递

栈帧中存入函数的参数,局部变量,返回地址

在值传递的时候,被调函数是无法修改主调函数的值,但是可以用指针解决

但不是所有值传递的时候,被调函数都无法修改主调函数的值,如果传递的值是数组,就可以修改

数组在参数传递的时候,会自我退化为一个指针,指向数组的第一个元素的指针,传递的第一个元素的地址,操作的还是原来的那个数组。

数组作为参数传递的时候,必须把长度传递过来,也不能使用SIZE宏来计算传递数组的长度。

Q:为什么说是数组退化为指针?

A:因为数组退化为指针以后,数组丢失了长度信息

Q:为什么这样设计?

A:1.避免大量数据的复制

       2.被调函数可以操作主调函数的数组

       3.让函数的调用更加灵活,比如传递一个长度为10的数组,直接对前面5个元素清零

12.5存储期限

存储期限:在运行时起作用,表示这个变量绑定的值在可以被引用的时间长度

静态存储期限:内存中,数据段与代码段的部分,类似c++的生命周期,在进程启动时开始,在进程退出时消亡

自动存储期限:栈帧入栈时开始,栈帧出栈时消亡

动态存储期限:由程序员自己管理,malloc开始,free消亡

12.6局部变量与外部变量

局部变量:定义在函数里面的变量,只能在函数里面使用的变量

        作用域:变量可以被引用的范围,或者说是在{...}块内的范围,(在运行时起作用)

        块:简单说就是大括号{...}里面的全部叫一个块

        存储期限:默认为自动存储期限(在栈里面),加上static会变成静态存储期限(在数据段里面),加了static初始化只执行一次。

外部变量:定义在函数外部的变量,也叫全局变量,但并非全局都可以使用。、

                作用域:在外部变量的定义开始到这个文件的末尾,也可以叫文件作用域

                存储周期:静态存储期限

静态存储期限的局部变量和外部变量的区别是作用域不同

Q:静态存储期限的局部变量有什么用?

A:存储上一次函数调用的状态

 eg:使用静态存储期限的局部变量打印一个斐波那契

long long next_fib() {
	static long long a = 0;
	static long long b = 1;
	long long t = a + b;
	a = b;
	b = t;
	return a;
}
int main() {

	printf("next_fib() = %lld\n", next_fib());
	printf("next_fib() = %lld\n", next_fib());
	printf("next_fib() = %lld\n", next_fib());
	return 0;
}

12.7递归 recursion

12.7.1递归

递:将大问题分解为若干个子问题

       子问题和大问题的求解方式一样,只是问题的规模不一样

归:将子问题合并为大问题的解

以斐波那契为例子,递归是指数增长级别的,求解方式的效率很低,会纯在大量重复的计算

long long fib(int n){
	if (n==0||n==1){
		return n;
	}
	return fib(n-1)+fib(n-2);
}

12.7.2动态规划

具有递归结构的问题不一定要用递归求解,可能纯在大量重复计算的问题,不一定要自下而上的求解,可以使用动态规划的方式去优化避免重复计算

继续以斐波那契为例子,使用动态规划

long long fib_dp(int n){
	long long a=0;
	long long b=1;
	//循环不变式:每次进入循环体之前都成立的条件
	for (int i =2;i<=n;i++){
		long long t=a+b;
		a=b;
		b=t;
	}
	return b;
}

12.7.3循环不变式

循环不变式:每次进入循环体之前都成立的条件,要找到退出点,可以一直维持到循环语句的结束

可以用小的规模去计算得到正确的结果

控制表达式:上面i<=n那句叫控制表达式,要关注要不要写等号

12.7.4递归关键

递归公式:只考虑这一层与下一层的条件(使用数学归纳法)

边界条件:最后得到答案的条件

这个只能靠自己多刷题。

12.7.5要不要用递归——递归两问

1.找到问题的递归结构

2.要不要使用递归结构:存在重复结构(不用),问题缩减幅度很小(不用)

999.常见面试题

999.1题目清单

  1. 位运算
    1. 如何判断一个数是奇数
    2. 为什么数组的索引一般是从0开始的?

999.2位运算

1.如何判断一个数是奇数

错误做法:

        i%2==1

        当i为负数的时候,i的结果为-1,C语言的%和数学的mod是不一样的

        C语言%运算的时候,余数的符号与被除数是一致的

可行做法:

        i%2!=0

        提示:取余,乘法,除法的运算符都是比较麻烦的,计算机操作的数都是二进制

 正确做法:

        i & 0x1==1;

        建议使用16进制数,使用16进制表示关注的是二进制,而不是数本身

2.为什么数组的索引一般是从0开始的?

数组元素的地址计算公式为:i_addr  = base_adddr + sizeof(elem_type)*(i-1)

数组的索引不是代表第几个元素,而是代表与第一个元素的偏移量

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/945715.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

使用uWSGI将Flask应用部署到生产环境

使用uWSGI将Flask应用部署到生产环境&#xff1a; 1、安装uWSGI conda install -c conda-forge uwsgi&#xff08;pip install uwsgi会报错&#xff09; 2、配置uWSGI 在python程序的同一文件夹下创建 uwsgi.ini文件&#xff0c;文件内容如下表。 需要按照实际情况修改文件名称…

集成方案 | Docusign + 蓝凌 EKP,打造一站式合同管理平台,实现无缝协作!

本文将详细介绍 Docusign 与蓝凌 EKP 的集成步骤及其效果&#xff0c;并通过实际应用场景来展示 Docusign 的强大集成能力&#xff0c;以证明 Docusign 集成功能的高效性和实用性。 在当今数字化办公环境中&#xff0c;企业对于提高工作效率和提升用户体验的需求日益迫切。蓝凌…

CMS漏洞靶场攻略

DeDeCMS 环境搭建 傻瓜式安装 漏洞一&#xff1a;通过文件管理器上传WebShel 步骤⼀:访问目标靶场其思路为 dedecms 后台可以直接上传任意文件&#xff0c;可以通过⽂件管理器上传php文件获取webshell 登陆网站后台 步骤二&#xff1a;登陆到后台点击 【核心】 --》 【文件式…

1、Jmeter、jdk下载与安装

1、访问官网&#xff0c;点击下载Jmeter http://jmeter.apache.org/ 2、在等待期间&#xff0c;下载对应的Java https://www.oracle.com/cn/java/technologies/downloads/#jdk23-windows 3、全部下载好&#xff0c;先安装JDK ![在这里插入图片描述](https://i-blog.csdnimg…

【文献精读笔记】Explainability for Large Language Models: A Survey (大语言模型的可解释性综述)(二)

****非斜体正文为原文献内容&#xff08;也包含笔者的补充&#xff09;&#xff0c;灰色块中是对文章细节的进一步详细解释&#xff01; 3.1.2 基于注意力的解释&#xff08;Attention-Based Explanation&#xff09; 注意力机制可以揭示输入数据中各个部分之间的关系&#…

【大模型实战篇】Mac本地部署RAGFlow的踩坑史

1. 题外话 最近一篇文章还是在11月30日写的&#xff0c;好长时间没有打卡了。最近工作上的事情特别多&#xff0c;主要聚焦在大模型的预训练、微调和RAG两个方面。主要用到的框架是Megatron-DeepSpeed&#xff0c;后续会带来一些分享。今天的文章主要聚焦在RAG。 近期调研了一系…

使用rknn进行yoloV8部署(C++)

文章目录 RKNN导出ONNX导出RKNNC++部署环境配置参考RKNN RKNN(Rockchip Neural Network)是由 Rockchip(瑞芯微电子)公司开发的深度学习框架,旨在提供高效、优化的神经网络推理(inference)能力,支持各种类型的神经网络模型的加速运行,特别是针对 Rockchip 的 ARM 处理…

linux安装nginxs报错:openssl not found

系统&#xff1a; linux 版本&#xff1a;centOS7 nginx版本&#xff1a;nginx-1.20.2 linux安装nginx时 执行下面命令时报错&#xff1a; ./configure --with-http_stub_status_module --with-http_ssl_module --prefix/usr/local/nginxchecking for OpenSSL library ... not …

AI安全的挑战:如何让人工智能变得更加可信

引言 随着人工智能&#xff08;AI&#xff09;技术在各个领域的广泛应用&#xff0c;尤其是在医疗、金融、自动驾驶和智能制造等行业&#xff0c;AI正在重塑我们的工作和生活方式。从提高生产效率到实现个性化服务&#xff0c;AI带来了前所未有的便利。然而&#xff0c;在享受这…

项目开发实践——基于SpringBoot+Vue3实现的在线考试系统(四)

文章目录 一、管理员角色功能实现1、添加教师功能实现1.1 页面设计1.2 前端功能实现1.3 后端功能实现1.4 效果展示2、教师管理功能实现2.1 页面设计2.2 前端功能实现2.3 后端功能实现2.3.1 后端查询接口实现2.3.2 后端编辑接口实现2.3.3 后端删除接口实现2.4 效果展示二、代码下…

医疗设备专网防火墙逻辑编程:构建医疗网络安全防线

一、引言 1.1 医疗设备网络化背景 随着信息技术的飞速发展&#xff0c;医疗设备的智能化与网络化已成为不可阻挡的趋势。从医院内部的信息管理系统&#xff08;HIS&#xff09;、影像归档和通信系统&#xff08;PACS&#xff09;&#xff0c;到临床检验系统&#xff08;LIS&…

金蝶V10中间件的使用

目录 环境准备搭建过程配置修改应用部署 环境准备 Linux内核服务器JDK1.8安装包&#xff1a;AAS-V10.zip程序包&#xff1a;***.war 搭建过程 将安装包上传至服务器opt目录下&#xff0c;官方给定的默认服务主目录为“/opt/AAS-V10/ApusicAS/aas/”&#xff1b;解压安装包(解…

AutoDL服务器深度学习使用过程

前期准备 Xshell,Xftp,Pycharm专业版 step 1:实例开机&#xff08;无卡or有卡&#xff09;&#xff0c;Xshell连接 新建xshell会话&#xff1a; 登录指令格式为&#xff1a; ssh -p 38076 rootregion-1.autodl.com 在ssh -p 38076 rootregion-1.autodl.com命令中&#xff0…

MySQLOCP考试过了,题库很稳,经验分享。

前几天&#xff0c;本人参加了Oracle认证 MySQLOCP工程师认证考试 &#xff0c;先说下考这个证书的初衷&#xff1a; 1、首先本人是从事数据库运维的&#xff0c;今年开始单位逐步要求DBA持证上岗。 2、本人的工作是涉及数据库维护&#xff0c;对这块的内容比较熟悉&#xff…

虚拟机Centos下安装Mysql完整过程(图文详解)

目录 一. 准备工作 1. 设置虚拟机静态IP 2. 卸载Mysql 3. 给CentOS添加rpm源 二. 安装MySQL 1. 安装mysql服务 2. 启动mysql服务 3. 开启MySQL开机自启动 4. 查看mysql服务状态 5. 查看mysql初始密码 6. 登录mysql &#xff0c;修改密码 7. 允许外部访问MySQL数据库…

Git Flow 工作流:保障修改不破坏主功能的完整指南20241230

Git Flow 工作流&#xff1a;保障修改不破坏主功能的完整指南 引言 在团队协作和个人项目中&#xff0c;Git Flow 是一种可靠的分支管理策略。通过清晰的分工和规范的流程&#xff0c;它能有效保障代码改动的安全性&#xff0c;避免修改破坏主功能&#xff0c;同时提高开发效…

数据库基础知识---以MySQL为例

一、什么是MySQL 数据保存在不同的表中&#xff0c;而不是将所有数据放在一个大仓库内 二、特点 开源--免费下载跨平台--可以在多个操作系统进行运行性能好--可以出来大量数据简单--安装配置简单支持多种编程语言--可以与多种编程语言进行无缝集成 三、分类 DDL--数据定义…

【漫话机器学习系列】028.CP

Mallows’ Cp&#xff1a;标准化公式解析与应用 Mallows’ Cp 是一种常用的模型选择工具&#xff0c;用于在一系列候选模型中权衡拟合度和复杂性&#xff0c;帮助我们选择性能最优的模型。本文将基于其标准化公式展开详细解析&#xff0c;并探讨其应用场景、实现方法、优点与局…

pyqt5 设计pdf 和word文件互相转换小程序

给自己编写一个免费简单的设计pdf 和word文件互相转换小程序&#xff0c;使用pyqt5 做ui设计。 代码如下&#xff1a; # 导入必要的库和模块 from PyQt5 import QtCore, QtWidgets from PyQt5.QtWidgets import QMainWindow, QApplication, QFileDialog from pdf2docx import …

SQL 实战:基于经纬度的距离计算与位置查询

在位置服务&#xff08;LBS&#xff09;系统中&#xff0c;基于地理位置查询和距离计算是核心功能之一。例如&#xff1a; 查找附近的商铺、加油站或医院。计算两点之间的实际直线距离。筛选出指定范围内的用户或设备位置。 MySQL 提供了多种方式实现地理位置查询&#xff0c…