优秀的编程知识分享平台

网站首页 > 技术文章 正文

知识分享:C语言语法总结,初学者可收藏

nanyue 2024-09-04 10:05:25 技术文章 5 ℃

C语言编程语法的快速学习(不针对考试)

1 .内存,寄存器等存放的内容断电以后就会丢失,而且新的数据填入内存后,旧的内容就会被覆盖。

2.电脑是以二进制存储内容的(客观),存储的东西是数据还是代码是人为的,电脑本身并不知道某一段内容是数据还是代码。

3.存储的数据超过设定的容量就会发生溢出,丢失一部分数据。

目前我们遵循的标准是c89/c99标准

在C语言中,单独一个语句的结束标志是西文的分号;不管你的语句是放在了一行还是单独另起一行,但是,如果是花括号构成的复合语句(准确来说整体的语句结束时的末尾为右花括号}),一般情况下分号可以省略

eg: int a;

{int a=3;

if(a==3) a=4;

else a=5;

}

数据类型

最开始我们会学到一些C语言自己拥有的数据类型,也就是基本类型,先介绍整数类型(有符号的是以补码的形式存储)

char类型是character的缩写,意思是字符类型。它是用来表示一个字符的编码。在被进行数学运算或者位运算的时候会被视为普通的整数类型,而在其他的情况则会与其他的整数类型区别对待,比如在输出成文字的时候系统会按照文字的某一种编码(ASCII码,GB2312,utf-8,big5码等)根据char类型的值寻找对应的文字,然后按照这个文字的显示方式(字体)和各种参数来显示或者输出。通常在编译器的设定里为1B

int类型(integer)为常用的整数类型,能够表示比较大的整数,参与数学运算或者位运算。有正负之分。short类型,long类型和int类型的区别是存储的数值范围是long>=int>=short>=char

unsigned是一个修饰符,用来表示后面的整数没有负数,不用考虑数学的符号,在表示unsigned int时候,int可以省略。

注意:C语言没有专门表示逻辑的类型和常量,用整数表示逻辑真假时,0表示假,非零的数表示真。逻辑转换为整数时,真为1,假为0。在c99里,引入了一个新的数据类型_Bool型专门表示逻辑类型,不过实际上它也是属于整数类型,只不过它只能为0或1,true或者false

接下来是浮点数类型,它们能表示一定范围的小数。表示范围的大小long double>=double>=float,它们的存储方式请自行搜索。

viod类型是特殊的类型,它表示什么类型都不是。一般用该函数的声明和定义表示不返回数据。

定义变量的格式是

数据类型 自定义 变量名;

c语言规定,自定义变量名字不能与c语言自己已经定好的名称重名(如果重名在有些情况下c语言无法判断这个名字是变量名还是预约好的名称),自定义变量名的开头只能是字母和下划线,后面可以使用字母,下划线和数字。

一般也可以在定义的时候赋予初值其形式是

数据类型 自定义变量名=值;

如果不赋值的话,初值是个随机数

实质是向系统申请一块内存区域,系统找到一块合适的地方再进行简单的标记(比如登记给定的类型,放入指定的值)。(就像是自己提出要租什么类型的房子,房东找到合适的房子给你,然后身份证进行简单的登记,房子里至于是什么样房东不管,这也解释了为什么初始化一个变量以后里面的内容是随机的。 严格来说,里面的内容不能算是随机,因为可以跟踪上一次程序使用这一块内存的操作来推出内容是什么,不过谁有这闲工夫干这没意义的事?)

一般情况下,如果程序发现变量被赋予的值和它自身的值不相同,会先进行隐式转换(一般是占用空间小的类型向占用空间大的类型转换),就是能简单的去去小数,把存储的位数进行调整,如果自己没办法进行调整,此时需要强制进行类型转换,格式为(数据类型) 最小单位的表达式


变量的修饰关键词

const关键词是用来声明变量所在的内存区域是只读的,也就是说可以使用其里面的值,但是不能修改,常常用于当做常量,或者写函数时将不需要修改值的变量设置成const防止意外修改。

aoto关键词是默认的关键词,用来声明局部变量,生命周期一般是在变量所在的范围最小的花括号内(可以把整个源代码文件的范围当做一个很大的无名花括号,定义在程序里的变量一般初值全为二进制的0),在生命周期外变量会被销毁,由于局部变量实在太常用,auto写的又不是很多,所以在c11标准中auto变成了根据给定的初值自动设置变量的类型的关键词。

register关键字是声明变量是在寄存器中存储,寄存器是一个高速小容量靠近CPU的储存单元,并且寄存器的数量有限,有些的还有特殊的用途,所以register只是一个建议,而且由于寄存器是一种单独离散的特殊单元,不能用&取地址(寄存器没有地址)

static关键字是程序运行时声明变量的所在的内存一直会被保存,直到程序退出内存才会释放这个空间。被其修饰的变量所在的内存区域一般全是二进制的0

extern表示这个全局变量是从别的文件定义的。


常量

常量顾名思义就是不变的量,数学里的π永远等于3.1415926535...,e等于

2.718281828459...,f(x)=x2+2x+1中的数2,1。类似的,代码里直接出现的数,和符号代替的数就是常量。在c语言中基本类型的数值都有表示方法

在整型常量中,有二进制,十进制,八进制和十六进制表示方法,十进制就跟正常生活数的表示方法一样。八进制要在八进制表示的数前面加一个0十六进制要在前面加0x或者0X二进制要在数的前面加0b,默认情况下,十进制表示的数都会被认为是int类型,如果想表示无符号类型就要在数的后面加一个u长整型要在数的后面加l长无符号整型在数的后面加lu长长整型要加ll浮点数一般是我们生活常用的表达。默认是double类型,要是表示float类型,需要在数的后面加一个f

字符型常量是用一对单引号包含一个字符 eg 'c' '1'

字符串(字符数组常量)是用一对双引号包含字符串。是特殊的字符数组常量的表示方法。eg“c++”

基本运算符号

赋值符号=是运算级别倒数第二的运算符号 它是将右边的值赋值给左边,不难理解,赋值符号左边只能是像可以写入的变量这样的存储单元,所以这样的存储单元又叫左值(lvalue),赋值表达式返回的值是等号右边得到的值。eg a=1;这个返回的值是1

逗号,是运算级别最低的符号,它主要是从最左边以逗号为分界点,逐一执行里面的操作得到数值,整个返回值的最后结果是最右边得到的值。

加号+ 减号- 称号* 除号/和数学意义上的运算是一样的,他们相对的运算顺序也和数学的四则运算是一样的。

求余符号%是计算整数之间整除以后的余数。

位左移<<是把一个数当做二进制进行左移,左边移出的二进制位舍弃,右边移进来的二进制位用0填充。eg:6<<2表示将6这个int类型左移两位,得到24.

位右移>>是把一个数当做二进制进行右移,右边移出的二进制位舍弃,左边移进来的二进制位用0填充。eg:6>>2表示将6这个int类型右移两位,得到1.

位与&是把两个数的二进制逐个进行与运算。

位或|是把两个数的二进制逐个进行或运算。

位取反~是把一个数的二进制进行取反运算

异或^是把2个数的二进制进行异或运算

取地址符号&是得到一个变量在内存中的地址。(这里的地址是个相对概念,因为在系统里给程序的内存地址是个相对地址)

*寻址符号是根据内存地址来指向一个内存空间,eg *p=2;将2赋给p里的内存地址指向的内存单位。

成员运算符.是引出整体里的成员,比如k.name就是调出k里的小成员name

->指向成员运算符,就是通过其将内存地址直接指向成员而不是整体,eg p->name就是p这个指针通过此运算符直接指向那个内存单位的成员name

自增++是指存储单位的值加一个单位的数值,而自减--是指存储单位的值减一个单位的数值。他们在前面表示先进行运算再取值,在后面表示先取值在进行运算(有自增自减运算是因为汇编有专门的指令inc,dec)

符合赋值符号是先计算等号右边的值,再把左边的值和右边计算的结果进行运算赋值给左值。(有复合复制符号是因为汇编里像add eax,ebp都是把左边的值和右边的值进行运算并把结果存入左边的存储单元)eg a += 2就是a和2相加,再把结果给a。

括号()是将括号里的表达式强制提到最高运算的优先级,相对于数学运算里括号的作用。


逻辑运算

大于>,小于<,不大于<=,不小于>=,不等于!=,等于==表示的意义和数学一样,只不过它返回的是逻辑上的真或者假

逻辑与&&,逻辑或||,逻辑非!和数学里的用法是一样的,不过要注意的是,当一个运算只计算了左边得到的逻辑结果就能判定整个逻辑运算的结果时,它会跳过右边的逻辑运算。

条件运算符?:是计算问号左边的逻辑真假,如果为真结果就是冒号左边的结果,为假是冒号右边的结果。

流程控制语句

如果语句,格式:

if(返回整数的表达式)

语句1

[else 语句2]

此语句先计算返回整数的表达式,如果是逻辑上的真,就执行语句1,如果是假就执行语句2,如果没有逻辑为假的操作,方括号里的语句可以不写。

先判断当循环语句格式:

while(返回整数的表达式)

语句

此语句先判断返回整数的表达式,为真就执行循环语句,在进入下一次循环判断,为假就结束循环不执行语句

后判断循环语句格式:

do 循环语句 while(返回整数的表达式)

这个先执行循环语句,然后在判断返回整数的表达式,为真就继续进行循环,为假就结束循环。

记次循环语句格式:

for(语句a;返回整数的表达式b;语句c) 循环语句d

首先执行语句a,然后计算返回整数的表达式b,如果为逻辑上的真就执行循环语句d,最后在执行语句c进入下一个循环判断;如果为假就结束循环

注意:循环语句里可以使用break来跳出循环体,也可以使用continue来直接进入下一次的循环。

选择语句格式

switch(返回整数的表达式){

case 整数常量a:语句a1;

语句a2;

。。

语句an;

case 整数常量b:语句b1;

语句b2;

。。。

语句bn;

...

case 整数常量n:语句n1;

。。。。

语句nn;

default:语句1;

语句2;

。。。

语句n;

}

此语句是先计算返回整数的表达式,然后进入花括号与case后的整数常量进行判断,遇到相等的整数常量就在此开始执行后面的语句一直执行到底,当然,也可以中间使用break语句跳出这个花括号的复合语句。


函数(构成c语言程序最小的单元)

编程的函数和数学里的函数类似,只不过数学里的函数仅仅只是输入数(可以是一个数或者几个数)通过一定的方法得到另一个数。而编程里的函数不止可以做数学计算,还可以干其他的事,而且输入可以没有,也可以有好几个(就行你给一个人发出命令,可以让他去写一篇文章,可以规定一些要求,也可以什么也不要求,然后返回的东西就是写好的文章)

函数的声明:

数据类型 函数名([数据类型 参数名1,数据类型 参数名2。。。,数据类型 参数名n]);

函数的定义:

数据类型 函数名([数据类型 参数名1,数据类型 参数名2。。。,数据类型 参数名n]){

语句1。。。

语句n

}

其中函数不能嵌套定义,也就是说不能在一个函数的语句里不能在定义一个函数。

实际上,那些参数也是函数里的局部变量,只是摆在了括号里等待数据的传入。而且在c语言里,在调用函数时,传入参数的个数和类型都要正确。

往深处看,函数的声明有些类似于变量的声明,其实,函数的声明这一块是向系统申请一块内存,然后往这一块内存填充代码。函数名是函数的入口地址,本质就是指针。

函数的调用形式

存在的函数名(传入的参数1,。。。。,传入的参数n)

但调用的前提是前面必须有函数的定义或者声明,否则会出现错误

以上的一些规定其实可以和数学的函数类比,数学的函数哪里学过嵌套定义另外的函数,但是我们可以在前面设一个函数,然后在另外一个函数调用前面设好的函数,而且数学里前面没有设好的函数,后面的函数不能无中生有调用前面没有的函数(就像你之前如果不知道写文章是什么意思,老板命令你写文章,你不知道怎么回事。)

在c语言中,整个程序的入口函数名为main,定义入口函数的格式为:

int main(){}和int main(int argc,char**argv){}


其他的类型

数组类型是为了方便解决一些问题,在内存的排列是连续的。表示方法如下:

数据类型 []

数组变量初始化一般有如下几个方法

int a[3]={1,2,3}

int a[]={1,2,3,6,7}

int a[10]={1,2,3}

但是数组在定义后不能直接整体赋值,也就是说,像a={3,4,5,6,7}的赋值将会导致错误,这是因为数组名表示的是指针常量,而不是变量,只能间接通过内存复制来间接赋值。

数组变量引用的下标一定是有符号的整数类型(无符号的将会导致程序崩溃)

指针是存储内存地址的存储单元,它的作用是方便对某一块内存进行操作(比如对另一块传入的变量进行操作,对申请到的无名内存进行操作等)其基本形式是 数据类型 *,而在利用指针的时候,指针的使用方法是 *变量名,整体就变成了指向目标类型的变量了

结构体是指为了方便管理数据专门自己设置的数据类型,不管有名还是无名它都会开辟内存空间,一般定义方式为

struct 自定义结构体名 {

数据类型1 成员名称1

。。。

数据类型n 成员名称n

};

这里自定义结构体名可以省略,但是这里的分号不可以省略,因为定义的整体就是一个数据类型

eg struct student {

unsigned number;

unsigned age;

unsigned score;

} function(){}

这里的函数的返回类型为结构体student

使用定义的结构体类型的方法是struct 已定义的结构体名

枚举类型enum在c语言是一种构造类型,用于声明一组命名的常数。其基本定义格式是 enum 枚举类型名字 {成员名1[=整数值],。。。。,成员名n[=整数]}

如果成员1没有给出整数,默认为0,之后的元素以1递增,成员名不能重名。

使用定义的枚举类型为 enum 定义的枚举类型名字

共同体(联合,union)是一种构造类型,几个成员共用一个内存空间,最后的大小取决于占用内存最大的成员,其基本形式是

union 共同体名称{

数据类型 成员名1

数据类型 成员名2

。。。。

数据类型 成员名n

};

使用已定义的共同体类型为 union 已定义的名字


预处理指令

所有的预处理指令都是在程序编译以前就执行的指令,且前面都是#开头

#include指令是包含指令,在编译以前将给定的文件包含进去,有两种形式#include <文件名>和#include "文件名",其中前一个是让预处理程序到预定义的缺省路径下寻找文件,后一种是让其先在源代码文件的当前目录下寻找文件,然后在默认路径下找。

#define 目标1 结果1,是讲非双引号之外的内容进行简单的文本替换(结果1可以有多个空格),常见的形式为

#define pi 3.1415926

#define text “Hello world”

如果定义了函数的替换,函数的参数会在代码里简单的替换成目标指令

目标中的 #表示将参数变成字符串,##是连接两个字符串的

#define M(x,y) (x)*(y)

M(3+5,2+7)相对于(3+5)*(2+7)

#define paster( n ) printf( "token " #n" = %d ", token##n )

paster(9);相对于printf("token 9 = %d ",token9);

当然,如果替换的内容很长,又不想写在一行上,就可以在一行的末尾用结尾,然后另起一行继续写

#define menutext "1.scanf()

2.printf()

3.exit "

#if预处理是一个和类似于if语句的预处理指令,如果为真就执行#if和#else或者#elif之间的语句,否则就会执行后面的#else或者进行#elif的判断(else if的省略)

#ifdef和#ifndef比较特殊,它是判断前面有没有#define定义的标识符 执行方式类似于#if

#endif是结束前面预处理指令的判断


其他

typedef关键词是为一个数据类型其另外一个名字,并不是生成了一个新的类型,形式是typedef 数据类型 别名比如

typedef struct {int a;int b; int c;} ok;

typedef unsigned long DWORD;

个人吸收他人的一点见解

其实数组的定义应该是类似于java标准的定义int [2] a={2,3};(实际这样写C语言会报错)而且严格意义上来说,a指向的类型是int [2]类型,&a[0]指向的类型是int类型,除非是作为sizeof或者单目&操作符的操作数,C语言都将数组名弱化为基本的类型只是方便我们的处理。

希望对你有帮助!

————————

另外,对于准备学习C/C++编程的小伙伴,如果你想更好的提升你的编程核心能力(内功)不妨从现在开始!

编程学习书籍分享:

编程学习视频分享:

整理分享(多年学习的源码、项目实战视频、项目笔记,基础入门教程)

欢迎转行和学习编程的伙伴,利用更多的资料学习成长比自己琢磨更快哦!

对于C/C++感兴趣可以关注小编在后台私信我:【编程交流】一起来学习哦!可以领取一些C/C++的项目学习视频资料哦!已经设置好了关键词自动回复,自动领取就好了!

最近发表
标签列表