
环境配置:mingw64,wsl2,vscode插件设置c/cwslcode runner//全文为方便书写手敲的代码是用中文的格式直接复制会出问题一.第一个C语言程序HELLO,WORLD一个c语言程序需要包含最基本的内容1.头文件includestdio.h (必须//其实并非必须的但使用printf等很基本的功能需要这个头文件常常都需要这个头文件所以写一个必需可通自己的需要的功能填写多个头文件 如string.h等2.int mainmain函数是程序入口不可或缺3.main函数返回0代表程序正常退出返回非0值用来向操作系统传递异常编号不一定只能用1可以是任意非0整数二.1.printf的用法:(1)单纯输出一段文本内容printf(填写输出的内容);(2)要输出一段文本同时也要包含变量所代表的值例:此时输出为:a的值b (\n代表的是换行的意思)%c可以理解为被a取代,这里由于a是char类型的数据,且我们要输出的是a,所以采用%c ,同时也有其他数据类型的格式,如下:int型为%d(代表10进制,也有其他进制,但我们常用10进制,这里不多赘述)%p专门用来打印指针float为%f,double为%lf字符串为%s(c语言中字符串由char类型的数组表示,与java有所不同)2.scanf的用法一个程序中通常要用到输入各种类型的数据,从而获得变量的值使程序进行运行,scanf就是为此准备的scanf格式:scanf(%数据类型,地址);我们定义了整型变量a,所以填写%d代表的是取址,取a的地址,所以在这里地址里填写a但如果是char 类型的数组也就是字符串,如arr,可省略(后续我们会提到),那么就是:scanf(%s,arr);第一行为我们的输入,第二行为我们的输出scanf的易错点:(1)scanf 不会读取输入的回车,换行,空格等符号所以当你按下回车键时,回车保存在缓冲区内,如果下一行也是scanf而且输入的数据格式为char类型,那么这个scanf会直接读取缓冲区的回车键,直接结束读取.%d%s等格式符会自动跳过开头空白字符 (空格、回车、Tab)唯独%c不会跳过空白字符才会读取遗留回车。你的原文没有区分这点新手容易误解所有格式都会读取回车。例:解决方法:在scanf后面一行加入getchar(),清除缓冲区的换行键.(2)scanf读取字符串时,遇到带空格的字符串时,会在空格出直接结束读取,会导致无法输入想要的字符串.这里我我们可以采用fgets进行读取字符串,fgets(数组,数组大小,stdin),fgets可读取空格键和和换行符和特殊符号,在读取字符串时可替代scanf. fgets在遇到回车键时停止读取(如果上一行用完scanf后,没用getchar()清除缓冲区,会导致fgets也读取不到输入,建议每一行scanf后面都清理一下缓冲区)fgets和scanf的区别:fgets只能读取字符串,而scanf可以读取多种类型的数据,但scanf读取带空格等特殊符号的字符串时会表现不当.但fgets有一个点要注意fgets 会把按下回车产生的\n存入数组里面后续处理字符串通常需要手动把末尾的\n替换成\0不然字符串长度会包含换行符3.for,while,break,switch,if1.for循环格式:for(表达式1; 表达式2; 表达式3){ 循环体语句; }表达式1:用来定义一个只在for循环里面生效的局部变量,如int i0;表达上2:用来表示循环结束条件,如i5,表示当i5时循环结束表达式3:表示每次循环结束一次后所需要做的事情,比如i表达式1,3可以不写,但;不能省,表达式2不写的话代表的是无限循环但也不能省例:输出结果为0123456789;2.while和for一样都是用于循环,但格式有所不同格式:while(表达式){循环体语句;}这里的表达式代表的是循环结束的条件,类似for循环的表达式2.这里的表达式可以为0或1,计算机中0代表假,1代表真,所以while(1)代表一直循环,while(0)代表不进行循环,同时这里也可以填写true和falsewhile比for循环更加简单,但也缺失了部分功能,在不麻烦的循环中可以使用.同时while还有do while的用法,这里不多赘述自行了解.3.break代表停止的意思,广泛用于for,while,switch.在for和while内部配合if使用可达到,满足条件立即停止循环的功能.4.if格式:if(条件语句){满足条件运行的语句;}条件语句格式与循环的有所不同,等于用表示,大于用,小于用,大于等于用,小于等于用,或用||,和用等,同时条件语句也可直接为0或1else if(条件语句){语句;}else if和if表达的意思一样,只是判断条件不一样,因为有些时候我们需要多个判断条件,else if就是解决这个的. else if可存在多个,但不能脱离if单独存在else 代表的是esle if语句和if语句都不满足时所执行的语句else{运行语句;}例三.1.指针指针是C语言中最难也是最灵魂的一部分本人也许讲解的不是很好或有错误的地方望理解(1)基础指针定义:指针是存储内存地址的变量。一个程序运行当定义一个变量时内存会自动随机分给这个变量一个地址不可改变只有程序运行结束后内存被还给系统此时地址地址被收回等待下一次程序运行时被分配地址例这里我们定义了一个变量b那么系统就分配了它一个地址并且我们赋值为3这里的int *a就是我们所说的定义一个指针a所存放的就是地址是取地址的意思那么这里a存放的就是b的地址我们输出打印一下可以得到b的地址我们多次运行程序可以看到每次打印的地址都不一样佐证了我先前说的话。定义完后*a代表的是b的值而非地址*叫做解引用可以理解为对这个地址进行解析得出它所存入的值不要与定义中的*a弄混淆*a等价于b因为此时指针a和b的地址b一样可以理解为a和b代表的是同一个地址只不过这个地址是内存分配给b的b的地址不可改变a是可以随你的需求改变地址的只不过那时候更改了地址就不代表b了这个类似于一个“经纪人”我们这里多加一行代码printf“\n%d”*a就可以看到我们多了一个输出3const和指针const可以理解为固定的含义但我们定义指针时可以这样const int *p\\ 等价于int const *p 这代表*p不能变p可以变就是*p所指向的值不可以改变是固定的了但地址p可以改变int *const p\\这个就显而易见了这个是地址不能改变*p可以改变const int *const p \\这个就是两者都不能改变2数组与指针我们定义数组时通常如下定义数据类型数组名[空间大小]。看似和指针扯不上关系但事实并非如此。例如int a[100]这里a本质是这个数组的数组名但在大部分场景退化为首元素地址所以有时候常常混淆我们可以看到这个输出是一个地址当我们将p改为d时就会出现如下报错表示a是int *这里我估计有人疑惑了感觉和记忆里面的出现偏差了比如如下代码看第一张图片这里的输出怎么不报错a不是地址吗这是因为%s本身读取的就是地址而且s会以一个字节逐步读取char 类型就是一个字节到\0不读取用其他类型的话会读取不完整。如果把int数组直接传入%sint 占 4 字节存储格式和字符完全不一样并且数组没有\0结束标志不仅类型不匹配还会发生内存越界。函数strlen求字符串长度的原理就是这样这就是为什么strlen只能求字符串长度的原因我这里把数组名在各个情况所表达的列出来在 C 语言里数组名只有两种情况下才代表整个数组其余所有情况数组名都退化成指针或首地址。情况 1sizeof(a)情况 2a对数组名取地址除此之外全部发生数组退化数组名变成首元素地址在传入函数中作为参数时更是退化成指针此时记得不能用sizeof3函数与指针当我们写一个函数时,有时我们想传入的参t数是一整个数组时我们会这样定义例这里的int *a就代表传入数组的地址等价于int a[]但int *a也可以作为一个指针所以更推荐用这一种这里我们可以看到这个函数的参数类型是void我们也可以设置其他类型的比如intchar等但我们也有return地址的例如这里我们定义的函数是t我们可以这样理解int *tt是函数名返回类型是int *然后再函数中定义了一个数组b用malloc给了空间然后用memcpy把a的值全部复制过去然后修改了一下返回了b的地址。main里面我们用b接受函数返回的地址后续我们输出打印就得出结果143。这里由于是演示我使用了malloc并没有free它但语法规范是要free的。这里我们用了一些库函数我没有详细讲解大家仔细去搜索一下它的用法这里或许有人对这个sizeof有疑问说malloc中可以这样int *mallocsizeofa吗在函数传参中这个a已经退化为指针了如果sizeofa的话这是求这个指针a的长度而非数组a的长度但在main中用sizeofa的话就没什么问题。这里我们的t叫做指针函数 我们还有一种函数指针是这样的格式int*t形参列表这个的*在括号里修饰的是t和int *t不一样这个修饰的是int。//这里补充一点非常重要但很多人会犯的错误。例如我这个函数里面不用malloc而是这样int *t(int *a){int b[3].....最后return b};//这个是定义的局部数组存是存放在栈区函数执行结束栈空间释放b的内存被回收后续main函数使用这个地址会产生野指针未定义行为。所以在这里我们使用malloc但使用malloc时必须free不然会产生内存泄漏这我会在下一篇进行讲解函数指针int *aint xafunc \\这个案例并不符合格式我只粗略写一下这个func是我们定义的函数具体内容我就不写了假设funcint x把func的地址赋值给a但有一点我们要记住afunc也是没问题的这是我们把*隐藏了是等价于afunc的只不过那个是省略形式。调用*a3这个就是调用func但这个和a3也是等价的理由和上面一样。这个具体有些抽象看不懂的可以结合一个回调函数看一下函数指针最典型用途就是实现回调函数。。四.结语这是我第一次写博客有的地方也许写的不太好或有错误欢迎指正我这篇c语言的跨度有些大并没有面面俱到对0基础的人并不是非常友好但可以学的时候看一下应该还是有帮助的。后续malloc算法等进阶内容我会在下一篇博客进行讲解感谢大家的阅读。