C基础1

news/2025/3/4 23:18:29/文章来源:https://www.cnblogs.com/PeachyGalaxy/p/18721117

基础回顾

Hello World到底是什么🤔

//预处理
#include <stdio.h> //include是找的意思,找到stdio这个头文件//.h是头文件的后缀,.c是c语言源文件的后缀,.cpp是c++源文件的后缀//std是standard标准,i是input输入,o是output输出
//程序的主入口
int main( ) //int表示main函数的返回值是整数,main是函数名,括号内是从外界传入的参数
{printf("Hello World"); //printf是stdio.h这个头文件中的库函数retrun 0; //可以不写,有些编译器会自动补全
}

Hello World 欢迎大家进入新的世界

现在大家是否能流畅地敲出Hello World呢,点击下面的链接试试
戳此处开始Hello World

数据类型怎么这么多😭

什么是占位符?

占位符 就是像 %d, %lf....这些,存在于输入和输出函数中,在输入和输出时会替换为一个特定的值

举个例子

//我想要输入输出一个整数int a; //定义一个整型变量a, 没有赋初始值就是没有进行初始化int a = 0;这样才叫进行了初始化
scanf("%d", &a); //键盘录入a的值(自己在键盘上敲一个数)
printf("%d", a); //在控制台上打印出双引号内的内容(注意此处是占位符,会被逗号后的变量值替换)

是否有点小疑惑

  • 为啥 \(scanf\) 里面 \(a\) 的前面有 \(&\) 符号,可是 \(printf\) 中的 \(a\) 前面没有啊
  • \(&\) 这个符号是什么意思啊

(现在不需要彻底理解,涉及到指针的内容,也可以记住就好)

&它有三个名字,取地址符号 , 按位与引用符号。在此处它是取地址符号,在c++中它才会拥有引用的身份


先说说上面的 变量a ,a代表的就是赋予它的值 :

赋值操作的本质是变量的内存地址中的内容发生了变化

一个程序是由一个个函数组成的,运行函数时需要为它分配内存,而定义变量时也需要为它分配内存,改变变量的本质 就是 改变变量的内存地址中的内容,而内存地址本身不会因为赋值操作而修改

(可以通过下面这段代码看看内存地址和地址中的内容的变化情况)

#include <stdio.h>int main()
{int a;printf("%p  %d\n", &a, a); //%p是地址的占位符,输出a的地址和a的值a = 10;printf("%p  %d\n", &a, a);
}

既然赋值是通过改变地址中的内容,那 \(a = 10\) 里根本没有出现取地址符号&,那它怎么进行修改啊

!说到这里,大家是不是理解了为什么scanf中是&a

因为我是想通过scanf进行键盘录入来修改a的值,而修改值是修改地址中的内容,一个孤零零的a代表的仅仅是一个常数值,所以我需要将scanf中录入的数据放到&a即a的地址中,但是printf只是想让你输出a的值即可,所以就是输出a

  1. 若a没有进行初始化,且是局部变量有点忘记了或者不理解?没关系,下面会进行介绍),那么部分编译器会给a一个随机值,部分编译器会直接默认0,部分编译器会报错,所以大家最好定义变量时进行初始化,或者把它定义为全局变量

  2. 若a进行了初始化,或者键盘录入了a,或者对a进行了赋值操作,那么此时a代表的就是我们最后赋予它的那个值

这就像数学中的参数x一样,题目给出x的值了,那么x代表的就是这个值

(这些知识就像一棵树一样,从一个枝丫到另一个枝丫,彼此之间相互连通,草蛇灰线)


全局变量

全局一般来说是函数外面

#include <stdio.h>
int a;int main()
{printf("%d", a);
}

由于它定义在函数外面,在你没有赋值的情况下,系统会默认赋值0,它的生命周期是整个程序,可以在任何一个定义的函数中使用

局部变量

局部一般来说是函数内部

#include <stdio.h>int main()
{int a = 10;printf("%d", a);
}

由于它定义在函数内部,所以它的生命周期是所在的这个函数,这个函数运行结束,它就会被销毁

要是a是一个全局变量,但是我在函数内部给它又赋了一个值,那它该听谁的啊

可以自己通过代码测试一下

#include <stdio.h>
int a = 10;int main()
{a = 20;printf("%d", a);
}

所以,当全局和局部同时出现时,优先考虑局部

说到全局和局部都出现的情况,有两个很典型的不同情况哦
const常变量define宏定义

  • 常变量?一个变量让它拥有了常量的特性,简单来说就是一个值不能改变的变量,并且定义时一定要进行赋值

话不多说,自己用代码测试一下

#include <stdio.h>
const int a = 10;  //const  数据类型  变量名  =  值;int main()
{a = 9; //有的编译器写到这里就会报错printf("%d", a);
}
#include <stdio.h>int main()
{const int a = 10;a = 9; printf("%d", a);
}
  • define宏定义和const常变量的区别是,define只能在全局,且格式不同

写段代码测试一下

#include <stdio.h>
#define a 10   //末尾没有分号!!
//#define  变量名  值int main()
{a = 9; //有些编译器写到这就开始报错printf("%d", a);
}

通过一系列测试,我们知道了const常变量 和 define宏定义的变量值在之后不能进行修改!


(引入完毕,有没有思路变得清晰的感觉)

类型名 字节数 占位符
short 2 %hd
int 4 %d
float 4 %f
double 8 %lf
long 4 %ld
long long 4 %lld
char 1 %c
char [ ] - %s

sizeof这个函数可以用来求字节数,可以试着求一下

//可以这样
int size1 = sizeof(int);//也可以这样
int a = 4;
int size2 = sizeof(a);

整数的类型有 short, int, long, long long
我们通常使用int, 1e9左右的数据都能用int表示
而超过1e9的数据我们会使用long long

小数的类型有 float, double
我们通常使用double, 尽量不要写出 long double的形式

字符的类型是char,这里的字符只能是符号,英文字母, 空格,不能是汉字,因为char只能是一个字节,而汉字有两个字节

字符串又称字符数组, 类型是 char s[ ]; s是字符串的名字
一个字符串可以是有一个字符构成,也可以由很多字符构成

变量的输入输出让人头大😴

换行:在你需要换行的地方写上一个换行符\n

整型

之前我们提到,整型变量最常见的有2种 :int , long long

我们就以这两种为例

#include <stdio.h>int main()
{int n;scanf("%d", &n);printf("%d", n);
}

尝试一下long long 类型,和int差不多,要注意占位符不同

戳这里查看long long
#include <stdio.h>int main()
{long long n;scanf("%lld", &n);printf("%lld", n);
}

字符型

!在输入时一定要注意样例中不同字符可能用空格隔开 而不注意可能直接把空格输入进来,后面的正确字符没有输入进来

scanf里面的输入格式(比如间隔以及其它无用字符)要和样例中一样,才能正确输入

//下面是部分代码(不完整//我同时在一行输入了两个字符,它们中间用空格隔开,我想将它们分两行输出char a1,a2;
scanf("%c  %c", &a1, &a2);  //输入q  w  
//scanf里面必须有空格,必须和你输入的格式一模一样不然a2这个字符接收的就是空格
printf("%c\n%c", a1, a2);

来试试这道题吧
https://www.luogu.com.cn/problem/B2005

字符串型

字符串在c语言中都是用字符数组表示的,而字符数组表示字符串就有一个特点,就是字符数组都以\0结尾

给你一个字符串s = "abcd",用字符数组表示,求一下它有多少个字符

有5个

实际上它在数组中是这么表示的char s[ ] = {'a', 'b', 'c', 'd', '\0'};
可以写一行代码去求 int size = sizeof(s) / sizeof(char);

为什么要这样写?

首先,sizeof求的是字节数,而我们这里要求的是字符数,如何利用sizeof求呢,总的字节数 / 单位字节数 = 字符数,总字节数就是sizeof(s); 单位字节数就是这是个什么类型,sizeof(char)

注意
如果在初始化字符数组s时写的是char s[10];
那么利用sizeof计算的字符数只会是10,你已经将大小确定了,即使char s[10] = "abcd"; 但是会在后面给你自动补0,一直到数组的长度达到10为止

如何以字符串的形式,输入输出“abcd”这个字符串

有两种读取方式

  • 字符串长度已经固定,一个一个字符输入(假设为4)
    //由于最后有一个'\0',所以开数组的时候长度要加一
    char t[5];
    scanf("%c", &t[0]);
    scanf("%c", &t[1]);
    scanf("%c", &t[2]);
    scanf("%c", &t[3]);
    printf("%s", t);
    
  • 直接以一个字符串的形式输入
    char t[];
    scanf("%s", t);
    printf("%s", t);
    

解释

  • 字符数组默认都是从0下标开始,如果你不想用0这个下标,可以向第一种方式一样,指定字符的位置进行输入

  • 为什么第二种的scanf里面没有&?
    (此部分会在数组与指针的章节讲到,现在记住就好)
    由于scanf是想将这个东西放到我指定的变量的内存地址中,一般的变量都是用&来表示内存地址,但是数组(这里是字符数组)不一样!数组的变量名就是数组的地址,所以就不用取地址

假如我只有一个字符需要输入,或者我不想在scanf中保持和样例一样的格式,我该怎么做?

现在就可以用到一个有时候很方便的两个函数,getchar()putchar()

  • getchar( ) 是从键盘录入中接收一个字符,你可以选择要这个字符
char q = getchar(); //是不是比scanf("%c", &q);写起来方便一点
printf("%c", q);

也可以选择不要这个字符,有可能碰到我们需要的字符之间,它多出了空格或者换行符\n,就可用用getchar()接收之后丢掉

//分两行输入
//a
//b
char q, w; //定义一下这两个字符变量
scanf("%c", &q);
getchar(); //接收换行符,如果直接跳到下一步的话,那么w接收的就是换行符,因为换行符也是一个字符
scanf("%c", &w);
  • putchar()是输出一个字符,把想要输出的字符放在( )里面
char q = 'a';
putchar(q); //输出q这个字符变量
putchar('a'); //输出a这个字符,只有变量不用单引号,其它的字符需要单引号,字符串需要双引号

结构体看起来好复杂啊🙁

结构体通常定义在函数外面,即全局,这样就能被所有函数使用

结构体方便之处在于它就是一个集合,比如 学生 这个集合中,包含各种类型的变量,就像身高,体重,年龄,邮箱,地址....并且定义好这个结构体之后,可以被各个学生使用(后面用例子解释)

通过结构体,学生A的所有特性能够方便地进行输入输出,并打包保存在这个结构体中

举个例子

struct student {     //定义了一个student型的结构体int age; //年龄,int型double height; //身高,double型char email[]; //邮箱,字符串型
};//格式
struct 结构体名 {}; //要记得分号!
#include <stdio.h>struct student {int age;double height;char email[];
};int main()
{student a; //student是数据类型,表示学生这个结构体类型//后面的a是学生名,表示a这个学生;这就是上面所说的能被多个学生使用student b; //这样就又定义了一个b学生a.age = 15; //因为我们想把age,height这些数据保存在a这个学生集合中//a.age的意思就是a的age,把‘.’翻译成“的”a.height = 11.98; //a的heightprintf("%d", a.age);
}

算术 && 逻辑 表达式有点高级😊

算术表达式

大部分和数学中的一样,*表示/表示除(如果是整数除以整数就是向下取整),%表示取模,<=表示小于等于 , ++a表示a先自增1再进行运算,a++表示先将这一整行代码执行完,a再自增;\(a += b\) 就是相加的结果赋给前面的变量a等价于 \(a = a + b\),同理 \(a -= b\) 等价于 \(a = a - b\) , \(a *= b\) 等价于 \(a = a * b\) , \(a /= b\) 等价于 \(a = a / b\)

比如

#include <stdio.h>int main()
{int a = 10, b = 0, u = 0;u = a++, b += 2;printf("u = %d, a = %d", u, a); //猜猜最后输出的是什么,这个地方有点小坑
//将代码实现一下,看和猜的是否一样
}

改了一下下,结果会不同吗

#include <stdio.h>int main()
{int a = 10, b = 0, u = 0;u = ++a, b += 2; //这一行不同printf("u = %d, a = %d", u, a);
}

if语句中括号里面有很多判断运算符,它们是关系运算符,通常我们将成立即if能够运行用正数来表示,不成立用非正数表示,0或者负数

[具体的在if里面会讲]

逻辑表达式

&& &&两侧同时成立(即都为正数)才成立
II II两侧只要有一侧成立就成立
就是取反的意思,如果这个原本不成立,取反之后就成立

最易错的就是有的逻辑运算符具有短路效应,这会让我们的计算方便很多

比如0 && 100 这个表达式看到前面有个0就已经不成立了,不用管100,只要有一个不成立,这个表达式就不成立

又比如1 || 0这个表达式看到前面有个1就已经成立了,不用管后面的0,因为在或的表达式里,只要有一个成立就成立了

#include <stdio.h>int main()
{int i = 0, a = 0, b = 2, c = 3, d = 4;i = a++ && ++b && d++;printf("a = %d\n b = %d\n c = %d\n", a, b, c, d);//猜猜最后输出的是什么
}
查看答案和解释

a = 1
b = 2
c = 3
因为i = a++ && ++b && d++这个表达式,在进行第一步a++的时候,此时a没有自增,还是0,已经不成立了,所以后面的都不会进行,所以只有a在执行完之后能自增

一步步执行,执行到a++发现不成立了,就是短路效应

一道有点小坑的经典 A + B 问题

戳此处查看题目

一道有关基本运算以及输出的问题

继续戳

有两个小坑的题目

https://www.acwing.com/problem/content/620/

终于到流程控制语句了😀

if && else if && else

用例子来解释吧

int a = 10;
if(a < 5) { //如果满足a < 5,那么这个表达式就成立,等价于1或者任何正数,这个if语句才能进行;否则根本不会执行大括号内的内容printf("1");
}
else if(a < 10 && a >= 5) { //如果既满足a<10又满足a >= 5这个表达式才成立,才能执行大括号内的内容//注意!!不能写连等,就像5<=a<10是不行的,只能分开写printf("2");
}
else { //如果上面的if或者else if都不满足才会执行else中的语句,如果上面有满足了的,就不会执行elseprintf("3");
}

if结构是从上往下依次执行,有一个执行了,那么下面的else if或者else都不会执行

if语句可以只有if,也可以既有if 又有很多个else if(又很多种情况),也可以有else

!!if和else都只能有一个

有一个小原则else与最近的if配对,有时候我们会将大括号省略,为例方便,这样不容易知道if该和那个else配对

switch选择语句

和if语句差不多,适合选择比较少的时候,逐个列举选项;缺点是不能选择范围,只能是字符或整数

#include <stdio.h>int main()
{int a = 10;switch (a) { //计算结果只能是整数或字符case 1:  //如果a是1printf("1");break; //执行这段语句之后就break直接跳出switch这个大括号case 2:printf("2");break;case 10:printf("10");break;default: //如果没有一个符合,就执行defaultprintf("0");break;}
}

注意

  • if一般是对一个范围进行判断,从上往下依次执行

  • switch不是从上往下依次检索,就是直接匹配,更高效

  • case穿透,如果一个case里面没有break的话,那么执行完这个语句后就不会结束,会一直向下执行,直到碰到break才会停止

#include <stdio.h>int main()
{int a = 10;switch (a) { case 1:  printf("1");break; case 2:printf("2");break;case 10:printf("10"); //少了breakdefault: printf("0");break;}
}

猜猜结果是什么

点击查看结果

结果是100

因为直接检索到的case 10这里,打印了10,但是没有break就不能结束,所以会接着执行default,打印0,直到碰到break,程序结束

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

我的Redission使用初体验

本文记录作者第一次使用Redission实现分布式锁的体验。对于碰到的问题进行了一些总结。当我们实际使用redis手写实现分布式锁时,会产生不可重入、不可重试、超时释放和主从一致的问题,此时redission为我们提供的锁完美达成以上要求,适合我们生产时使用。Redisson的实际使用 …

Power Automate 格式化JSON时字段为空

前言最近,在使用Power Automate处理JSON的时候,碰到一个错误。正文1.处理JSON的过程,一般是这样的,如下图:2.测试一下,这样,我们就很容易操作JSON字符串中的属性了,如下图:3.但是,大家在开发中,碰到过这样的问题没有?4.详细的错误信息,如下图:[{"message&qu…

ChromaDB

ChromaDB是一个开源的嵌入式向量数据库,专为存储和查询高维向量数据而设计,特别适用于与大型语言模型(LLMs)和嵌入模型(Embeddings)相关的应用场景 安装pip install chromadb启动服务chroma run --path ./chroma_data --host 0.0.0.0 --port 8000说明: --path ./chroma_…

如何为 Power Automate 配置 Azure Key Vault 权限

前言最近,在Power Automate中使用Azure Key Vault,然后,就需要配置一下AKV的权限。正文1.我们在Azure Portal里新建一个Key vault,如下图:2.进入Access policies,点击Create,如下图:3.如果只是为Power Automate使用,只需要勾选红框的权限就好,如下图:4.搜索需要的服…

P2671 [NOIP 2015 普及组] 求和

好题,思想很好。 首先看到这个题一个显然的思路是\(O(n^3)\)的暴力,直接枚举三个判断可行性计算贡献。 思考简单的优化,题目条件限制z-y=y-x变形可得\(y=\frac{z-x}{2}\),由于\(y\)一定是正整数,所以\(z\)与\(x\)正负性相同,考虑将原数组拆分为奇数和偶数两个集合,并在两…

web开发 辅助学习管理系统开发日记 day8

今日完成员工上传头像功能,删除员工功能,以及调试阿里云oss服务器。 Q1:如何配置阿里云服务器 1.创建阿里云服务器并且搭建好配置 2.引入依赖 在oss简介首页引入 3.从官网复制粘贴出上传文件这个功能所在工具类 4.在控制层里面进行上传 Q2 批量删除员工功能 1.在controller层…

pycharm添加conda环境的解释器时找不到python.exe

pycharm添加conda环境的解释器时找不到python.exe 先找到 anaconda 安装目录下的 condabin/conda ,然后加载环境, 加载之后下面就有了conda环境,可以进行选择

md5.exe WriteUp

WriteUp 题目信息 名称:md5.exe 分类:Reverse 描述:找到程序的flag题目链接: https://pan.baidu.com/s/1u8bGbKcUF6_gLaw63L3jyA?pwd=h8r5 提取码: h8r5解题思路 首先用DIE查看该文件,发现该文件没有壳,且是32位exe文件。所以可以直接用32位IDA打开该文件,并按F5对main函…

xor.exe WriteUp

WriteUp 题目信息 名称:xor.exe 分类:Reverse 描述:找到程序的flag题目链接: https://pan.baidu.com/s/1u8bGbKcUF6_gLaw63L3jyA?pwd=h8r5 提取码: h8r5解题思路 首先用DIE查看该文件,发现该文件没有壳,且是32位exe文件。所以可以直接用32位IDA打开该文件,并按F5对main函…

原型链图

啥都不说,先上图:上面展示了各个对象之间是怎样通过显式原型(prototype)及隐式原型([[prototype]],通过__proto__访问)来串联起来的。

【C++库函数】C++生成高质量随机数的方法

#include <iostream> #include <random>int main() {// 第一步:初始化真随机种子(使用硬件熵源)std::random_device rd; // 第二步:选择高性能引擎(推荐 mt19937)std::mt19937 gen(rd()); // 用 random_device 的输出来种子初始化引擎// 第三步:定义分布(…

20250305

1 烧碱的C浪回调后 开始布局中线多单。