C语言基础知识

C语言基础知识,第1张

目录

一.数据类型

二、运算符,表达式和语句

三、循环

四、分支和跳转

         五、函数

         六、数组

         七、结构体与联合体(重要)


一、数据类型

 

数据类型概括就是上面的表格中的内容。

补充:

在32 位的系统上

short 占据的内存大小是2 个byte;

int占据的内存大小是4 个byte;

long占据的内存大小是4 个byte;

float占据的内存大小是4 个byte;

double占据的内存大小是8 个byte;

char占据的内存大小是1 个byte。

int(整型)

整型   短整型  长整型

处理的整数既可以正整数也可以是负整数(但是在程序当中,有一类数据,他可能永远都是正数,正整数;比如说我做一个计数器123...永远是正数)

(他是处理整数的一个工具)

短整型 可以简写为short;如果我在程序里边如果处理的这个整数比较小,我可以把它看成是一个short int类型的;由于short int他表示的数值范围比较小,所以他在内存里边占用的空间呢,也要比int类型比较少,如果你要节约你的存储空间的话处理一个比较小的整数的话,可以把它定义成short int类型,在C语言标准当中他并没有规定说int一定占多少字节,short一定要占多少字节,它是由编译器来决定的,C语言只是规定了short int占用的空间应该是小于等于int类型的数字占用的空间;如果我这个变量是short int类型的变量,我怎么去输出这个变量的值呢?肯定和输出int类型是不一样的,比如说我int类型是占用4个字节,那么我输出的时候在内存里边我就要读取4个字节的内容;如果short int是占用两个字节,那么在输出之后呢在内存里边我就要读取两个字节的内容,

长整型,就是比整型表示范围更大的一个整型类型;长整型在内存中占用多少个单元呢?同样是取决于编译器,C语只是规定长整型你要占用的内存空间呢是大于等于int型占用的空间的,如果说我一个整数Int类型放不下的话,那么你可以把它变成一个长整型,输出长整型的数?

unsigned

无符号型

为了更精确的表示这类数据就是前边说的计数器123...C语言提供了一个unsigned这样一个保留字 unsigned可以和int、long、short组合在一起使用, unsigned int、unsigned long、unsigned short一旦加unsigned之后呢,这一类就不能表示负数了,表示的就都是正整数。

char

字符类型

他处理一个字符(一个字母、或者一个标点符号之类的,)

float double

单精度数 双精度数

都是处理实型数的工具(两者的区别在于实型数的精度和表示范围不一样,float的精度和表示范围是小于等于double的表示范围和精度)

二、运算符,表达式和语句

C用运算符(operator)表示算术运算,基本运算符有:“=,+,-,*和/".C语言中没有指数运算符,不过,C标准数学库提供了一个pow()函数用于指数运算。

除基本运算符外,还有

求模运算符:%

递增运算符:++

递减运算符:--

关系运算符:>< <= >= == !=

逻辑运算符: !逻辑非 &&逻辑与 ||逻辑或

位运算:& 按位“与”  | 按位“或”  ^ 按位“异或”  ~ 取反

<< 左移   >> 右移

条件运算符(?:)如果expression1为真,输出expression2;如果expression1为假,输出expression3。

逗号运算符( , )在C语言中,逗号既可以作分隔符,又可以作运算符

逗号作为分隔符使用时,用于间断说明语句中的变量或函数中的参数;作为运算符使用时,将若干个独立的表达式连接在一起,组成逗号表达式。

长度运算符sizeof():单目运算符,以字节为单位返回运算对象的大小。

C语言规定,sizeof()返回size_t类型的值,这是一个无符号整数类型。

下标引用运算符[]:用来表示数组元素

强制类型转换运算符(类型):强制类型转换

查找地址 &运算符:一元&运算符给出变量的存储地址

间接(解引用)运算符*:找出存储在某变量中的值

表达式是由运算符运算对象组成的。

最简单的表达式是一个单独的运算对象。

一个表达式可以产生一个值,有可能是运算、函数调用、有可能是字面量。

表达式可以放在任何需要值的地方。

语句

语句可以理解为一个行为,循环语句和判断语句就是典型的语句。

一个程序有很多个语句组成,一般情况下;分割一个一个的语句。


三、循环

循环结构

循环必须要有某些固定的内容组成:

    1.初始化 i=0

    2.条件判断 i<10

    3.要执行的代码

4.自身改变 i

循环一般分为三种:while循环,do...while 循环,for循环

WHILE 循环

当…...时,当条件满足时就执行代码,一旦不满足了就不执行了

语法 while (条件) { 执行语句 }

因为满足条件就执行,所以我们写的时候一定要注意,就是设定一个边界值,不然就一直循环下去了,进入死循环。

此类循环语句是先判断在执行。

还有一类是先执行在判断  do......while

do{执行语句}while(条件)

FOR 循环(最常用)

和 while 和 do while 循环都不太一样的一种循环结构

道理是和其他两种一样的,都是循环执行代码的

语法: for (var i = 0; i < 10; i++) { 要执行的代码 }

BREAK 终止循环 在循环没有进行完毕的时候,因为我设置的条件满足,提前终止循环要终止循环,就可以直接使用 break 关键字结束整个循环,break所在的循环完全结束了 CONTINUE 结束本次循环

在循环中,把循环的本次跳过去,继续执行后续的循环

比如:吃五个橘子,到第三个的时候,我感觉不想吃第四个,直接拿第五个。

跳过本次循环,就可以使用 continue 关键字


四、分支和跳转

if语句被称为分支语句或选择语句,因为它相当于一个交叉点,程序需要在两条分支中选择一个执行。

if语句的通用形式如下:

if(expression)

statement

if else语句

if else形式,可以在两条语句之间作选择。

if else语句的通用形式:

if(expression)

statement1

else

statement2

如果expression为真(非0,则执行statement1;如果expression为假或0,则执行else后面的statement2.statement1和statement2可以是一条简单语句或复合语句 如果要在if和else之间执行多条语句,必须用花括号把这些语句括起来。

因为C语言中,if后如果不加花括号,程序只执行后面的一条语句。

如果没有花括号,else与离它最近的if匹配,除非最近的if被花括号起来。

switch (expression)

{

    case label1: statement1 //使用break跳出switch

    case label2: statement2

    default: statement3

   switch在圆括号中的测试表达式的值应该是一个整数值(包括char类型)。

case后的必须是整数类型(包括char类型)的常量或整型常量表达式(即,表达式中只包含整型常量)。

不能用变量作为case标签。

要对紧跟在关键字switch后圆括号中的表达式求值。

在上面的程序当中,程序扫描标签列表,直到发现一个匹配的值为止。

然后程序跳转至那一行。

如果没有匹配的值,如果有default:就跳转至改行;否则,程序就不会进入Switch,继续执行在switch后面的语句。

     break语句它让程序离开switch语句,跳出switch语句后面的下一条语句。

如果没有break语句,就会从匹配到的语句执行后接着按顺序往下一一执行。

 

五、函数

1:在我们写代码的时候,有时候会重复写一段代码,而这段代码所执行的功能, *** 作是一样的,只是针对的数据不一样,这个时候,将这段功能写成一个函数模块,在需要用到的时候调用即可,进而避免了写重复的代码,避免了重复性 *** 作。


2:函数是C语言的模块,一块块的,有较强的独立性,可以相互调用,也就是说,你可以在函数A中调用函数B,又可在函数B中调用函数C,不仅如此,你还可以调用函数自身(递归)。


3:函数是完成一个个特定任务的语句集合它能完成你所想要的某种特定任务,当你要用时,只需要调用它即可,在后续的修改或是维护过程中,只需要针对这一个进行修改即可。

在一个程序中一定要有一个main函数,可以有其他函数,当程序运行的时候,进入主函数,期间如果有其他函数,程序会按顺序调用其他函数,从而可以更加清楚的看懂代码的运行过程。

六、数组

数组:代表一组同类的数据(比如一组整型数、一组实型数、一组字符)

数组是构造数据类型之一

数组: 有序数据的集合,用数组名标识



例: int a[6]={1,2,3,4,5,6}

 

1、数组必须先定义,后使用。


2、只能逐个引用数组元素,不能一次引用整个数组。


3、数组元素表示形式: 数组名[下标] ,下标可以是常量或整型表达式

说明:
1、数组不初始化,其元素值为随机数。


2、对static数组元素不赋初值,系统会自动赋以0值。



3、只给部分数组元素赋初值。



4、当全部数组元素赋初值时,可不指定数组长度。

 

 七、结构体与联合体(重要)

结构体:  描述一些复杂的处理的对象,这个处理对象不是一个整型数、一个实数;而是需要由很多不同的方面组合起来的一个对象,当我把这些信息整合起来就形成了一个完整的类型,就叫做结构体类型。

结构体的一般定义形式为:struct是关键字,是结构体类型的标志。

struct 结构体名

{

成员1类型  成员1名;

成员2类型  成员2名;

.......   ......

};

struct 结构体名 结构体变量名;

结构体的初始化

1.将各成员的初值,按顺序地放在一对大括号{}中,并用逗号分隔,一一对应赋值。

比如初始化Student结构体变量stu,只能在定义变量的同时进行初始化赋值

struct students  stu1{“张三”,18};

2.使用已有的相同类型结构体初始化

struct students  stu2=stu1;

  1. 一般对结构体变量的 *** 作是以成员为单位进行的,引用的一般形式为:结构体变量名.成员名。

    如果某个成员也是结构体变量,可以连续使用成员运算符"."访问最低一级成员

age=stu.age;//

2.对于结构体指针,我们也可以通过成员运算符"."访问。

age=(*p).age;//"."的优先级高于”*“,因此使用是要加括号

age=p->age;//第二种方式

联合体(又称作联合或者共用体):

联合体、共用体是指在一块内存当中我可以把它存储的数据有时候看成是一个整型,有时候看成是一个数组,也就是说在一块内存当中可以存储不同的类型数据,但是同一时刻他存储的是一类数据。

结构体和联合体的区别在于:结构体的各个成员会占用不同的内存,互相之间没有影响;而共用体的所有成员占用同一段内存,每个成员的起始地址相同, 修改一个成员会影响其余所有成员。

结构体占用的内存大于等于所有成员占用的内存的总和(成员之间可能会存在缝隙),共用体占用的内存等于最长的成员占用的内存。

共用体使用了内存覆盖技术,同一时刻只能保存一个成员的值,如果对新的成员赋值,就会把原来成员的值覆盖掉。

共用体也是一种自定义类型,可以通过它来创建变量,
八、指针 (重要)

指针,也就是内存的地址;所谓指针变量,也就是保存了内存地址的变量。

**指针的值本是指针变量自身所储存的数值,但是例如

int p1=&i;

p1的值为i的地址,可分解为两句

int p1;p1=&i;

这样就不难理解了,p1所储存的值就是i的首地址,因为&i表示变量i的首地址。

&是取地址运算符,*是间接运算符,也叫解引用 *** 作符。

   在C语言中,允许用一个变量来存放指针,这种变量称为指针变量。

指针变量的值就是某份数据的地址,这样的一份数据可以是数组、字符串、函数,也可以是另外一个普通变量或者指针变量。

datatype *name;  或者  datatype *name = value;

其中,*表示这是一个指针变量,datatype表示该指针变量所指向的数据的类型。

*是一个特殊符号,表明一个变量是指针变量,定义指针变量时必须带*,给指针变量赋值时不能带*。

·   //定义指针变量

·   float *p1 = &a;

·   char *p2 = &c;

·   //修改指针变量的值

·    p1 = &b;

·   p2 = &d;

需要强调的是,p1、p2 的类型分别是float*和char*,而不是float和char,它们是完全不同的数据类型,要引起注意。

程序被编译和链接后,a、p 被替换成相应的地址。

使用 *p 的话,要先通过地址 0XF0A0 取得变量 p 本身的值,这个值是变量 a 的地址,然后再通过这个值取得变量 a 的数据,前后共有两次运算;而使用 a 的话,可以通过地址 0X1000 直接取得它的数据,只需要一步运算。

也就是说,使用指针是间接获取数据,使用变量名是直接获取数据,前者比后者的代价要高。

指针变量保存的是地址,而地址本质上是一个整数,所以指针变量可以进行部分运算,例如加法、减法、比较等。

但是不能对指针变量进行乘法、除法、取余等其他运算,除了会发生语法错误,也没有实际的含义。

   数组指针指向的是数组中的一个具体元素,而不是整个数组,所以数组指针的类型和数组元素的类型有关,上面的例子中,p 指向的数组元素是 int 类型,所以 p 的类型必须也是int *。

C语言有两种表示字符串的方法,一种是字符数组,另一种是字符串常量,它们在内存中的存储位置不同,使得字符数组可以读取和修改,而字符串常量只能读取不能修改。

指针的用法还有好多好多,大家还可以深入研究。


九、宏定义

从开始写C语言到生成执行程序的流程大致如下(姑且忽略预处理之前的编译器的翻译处理流程等),在进行编译的第一次扫描(词法扫描和语法分析)之前,会有由预处理程序负责完成的预处理工作。

预处理工作是系统引用预处理程序对源程序中的预处理部分做处理,而预处理部分是指以“#”开头的、放在函数之外的、一般放在源文件的前面的预处理命令,如:包括命令 #include,宏命令 #define 等,合理地利用预处理功能可以使得程序更加方便地阅读、修改、移植、调试等,也有利于模块化程序设计。

本文主要介绍宏定义的以下几个部分:

每个#define行(即逻辑行)由三部分组成:第一部分是指令 #define 自身,“#”表示这是一条预处理命令,“define”为宏命令。

第二部分为宏(macro),一般为缩略语,其名称(宏名)一般大写,而且不能有空格,遵循C变量命令规则。

“替换文本”可以是任意常数、表达式、字符串等。

在预处理工作过程中,代码中所有出现的“宏名”,都会被“替换文本”替换。

这个替换的过程被称为“宏代换”或“宏展开”(macro expansion)。

“宏代换”是由预处理程序自动完成的。

在C语言中,“宏”分为两种:无参数 和 有参数。

无参宏是指宏名之后不带参数,上面最简单的宏就是无参宏。

注意宏不是语句,结尾不需要加“;”,否则会被替换进程序中

#define N 10;               // 宏定义

int c[N];                   // 会被替换为: int c[10;];

如果要写宏不止一行,则在结尾加反斜线符号使得多行能连接上,

例如:

#define HELLO "hello \

the world"

切记在写的时候 要注意对齐,否则空格也会被记录在您的代码中,也就是说行与行之间的空格也会被作为替换文本的一部分
宏名如果出现在源程序中的“”内,但“”不会被当做宏来进行宏代换。

运算过程谁在程序运行的时候进行的而不是在预处理器工作阶段完成,所以宏不进行运算,它只是按照指令进行文字的替换 *** 作。

再强调下,宏进行简单的文本替换,无论替换文本中是常数、表达式或者字符串等,预处理程序都不做任何检查,如果出现错误,只能是被宏代换之后的程序在编译阶段发现。

 宏定义的缺点
  1. 由于是直接嵌入的,所以代码可能相对多一点;
  2. 嵌套定义过多可能会影响程序的可读性,而且很容易出错,不容易调试。

  3. 对带参的宏而言,由于是直接替换,并不会检查参数是否合法,存在安全隐患。

宏函数的适用范围

  1. 一般来说,用宏来代表简短的表达式比较合适。

  2. 在考虑效率的时候,可以考虑使用宏,或者内联函数。

  3. 还有一些任务根本无法用函数实现,但是用宏定义却很好实现。

    比如参数类型没法作为参数传递给函数,但是可以把参数类型传递给带参的宏。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/674708.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-04-19
下一篇 2022-04-19

发表评论

登录后才能评论

评论列表(0条)

保存