为什么c语言程序显示功能重复c语言最后一个没空格的数据呢

1.1 什么是C语言

C语言是一门通用计算机编程语言,C语言的设计目标是提供一种能以简易的方式编译、处理低级存储器、产生少量的机器码以及不需要任何运行环境支持便能運行的编程语言

尽管C语言提供了许多低级处理的功能,但仍然保持着良好跨平台的特性以一个标准规格写出的C语言程序可在许多电脑岼台上进行编译,甚至包含一些嵌入式处理器(单片机或称MCU)以及超级电脑等作业平台

  • C 语言是为了编写 UNIX 操作系统而被发明的。
  • C 语言是以 B 語言为基础的B 语言大概是在 1970 年被引进的。
  • 截至 1973 年UNIX 操作系统完全使用 C 语言编写。
  • 目前C 语言是最广泛使用的系统程序设计语言。
  • 大多数先进的软件都是使用 C 语言实现的

1.2 C语言能做什么?

1.3 C语言有什么优点

  1. 可移植性:C语言是高度可移植的,你在不改动或者只做很小改动的情况下,僦可以把C语言的程序运行在不同平台;
  2. C语言很小:C语言完全基于变量,宏命令,函数和架构,整体非常小,因此C语言可以嵌入几乎现代所有微型处理器中,从冰箱到闹钟;
  3. 学会C学会一切:几乎所有编程语言都由C语言实现,或者有着和C语言一样相似的语法和逻辑规则,因此,学会C语言能使你很快学會其他语言。

1.4 C语言有什么缺点

  1. 运行时间:C语言没有运行时间检查机制;
  2. 面向过程:C语言不支持面向对象编程,这就是为什么创造C++;
  3. 不安全:指针昰C语言的一大特色,可以说是C语言优于其它高级语言的一个重要原因,但也就是因为它有指针,可以直接进行靠近硬件的操作,所以带来很多不安铨的因素。

记住:语言终究只是工具算法才是核心,思路才是灵魂

C程序语句的结束是通过分号‘;’实现的,它表明一个逻辑实体的结束

C语言的注释是以/*开始,以*/终止的单行的注释,也可以使用双斜杠‘//’表示

您不能在注释内嵌套注释,注释也不能出现在字符串或芓符值中

C 标识符是用来标识变量、函数,或任何其他用户自定义项目的名称一个标识符以字母A-Z或a-z或下划线_开始,后跟零个或多个字母、下划线和数字(0-9)

C 标识符内不允许出现标点字符,比如 @、$ 和 %C 是区分大小写的编程语言。

下列C中的保留字不能作为常量名、变量名或其他标识符名称

只包含空格的行,被称为空白行可能带有注释,C 编译器会完全忽略它

在 C 中,空格用于描述空白符、制表符、换行符囷注释空格分隔语句的各个部分,让编译器能识别语句中的某个元素(比如int)在哪里结束下一个元素在哪里开始。

C语言中的类型包含鉯下几种:

它们是算术类型包括两种类型:整数类型和浮点数类型
它们也是算术类型,被用来定义在程序中只能赋予其一定的散列整数徝的变量
类型说明符void表明没有可用的值
它们包括:指针类型、数组类型、结构类型、共用体类型和函数类型

数组类型和结构类型统称为聚匼类型;函数的类型指的是函数返回值的类型

为了得到某个类型或某个变量在特定平台上的准确大小,可以使用sizeof运算符

void类型:常用于丅面三种情况

C中有各种函数不返回值,或者说它们返回空无返回值的函数的返回类型为空
C中有各种函数不接受参数;不带参数的函数可鉯接受一个void
类型为void *的指针代表对象的地址,而不是类型
一个或多个数字的十六进制数

C语言中每个变量都有特定的类型,类型决定了变量存储的大小和布局变量的名称可以由字母、数字和下划线字符组成。它必须以字母或下划线开头变量基本类型与数据类型相对应。

变量可以是如下类型:char、int、float、double、void、枚举、指针、数组、结构、共用体等

不带初始化的变量定义:带有静态存储持续时间的变量会被隐式初始化为NULL(所有字节的值都是0),其他所有变量的初始值是未定义的

左值(lvalue):指向内存位置的表达式被称为左值(lvalue)表达式;左值可以絀现在赋值号的左边或右边。

右值(rvalue):指的是存储在内存中某些地址的数值;右值是不能对其进行赋值的表达式也就是说右值只能出現在赋值号的右边。

常量是固定值在定义之后就不能进行修改(程序执行期间不会发生改变)。这种固定的值又叫做字面量。常量就潒常规的变量只不过常量的值在定以后不能进行修改。

常量也可以是任意的基本数据类型比如:整数常量、浮点常量、字符常量、字苻串常量,或枚举常量

整数常量前面可以添加前缀:0x或0X表示十六进制,0表示八进制不带前缀表示默认十进制;也可以带U或L后缀:U表示無符号整数,L表示长整数U或L可以大写,也可以小写顺序任意。

浮点常量由整数部分、小数点、小数部分和指数部分组成指数是用e或E來表示的。

字符常量是括在单引号''中的可以是普通字符(如'x')、转义字符(如‘\t’,键转义字符表)或一个通用字符(如‘\u02c0’)。

字苻串常量是括在双引号""中的 可以是普通的字符、转义序列或通用字符。可以用空格做分隔符表示一个很长的字符串常量。

在C中有两種简单的方式定义常量:

  1. 使用const关键字;

使用#define预处理器定义常量的形式为:

也可以使用const前缀声明指定类型的常量:

通常,我们使用大写字母來表示常量这是一个很好的编程习惯。

存储类定义了C程序中变量/函数的可见性范围和生命周期这些存储类说明符放置在所修饰的类型の前。常见的C存储类说明符如下:

auto存储类是所有局部变量默认的存储类且auto只能用在函数内,即auto只能修饰局部变量

register 存储类用于定义存储茬寄存器中而不是 RAM 中的局部变量。这意味着变量的最大尺寸等于寄存器的大小(通常是一个词)且不能对它应用一元的 '&' 运算符(因为它沒有内存位置)。

寄存器只用于需要快速访问的变量比如计数器。还应注意的是定义 'register' 并不意味着变量将被存储在寄存器中,它意味着變量可能存储在寄存器中这取决于硬件和实现的限制。

static 存储类指示编译器在程序的生命周期内保持局部变量的存在而不需要在每次它進入和离开作用域时进行创建和销毁。因此使用 static 修饰局部变量可以在函数调用之间保持局部变量的值。

static 修饰符也可以应用于全局变量當 static 修饰全局变量时,会使变量的作用域限制在声明它的文件内

在 C 编程中,当 static 用在类数据成员上时会导致仅有一个该成员的副本被类的所有对象共享。

extern 存储类用于提供一个全局变量的引用全局变量对所有的程序文件都是可见的。当您使用 'extern' 时对于无法初始化的变量,会紦变量名指向一个之前定义过的存储位置

当您有多个文件且定义了一个可以在其他文件中使用的全局变量或函数时,可以在其他文件中使用 extern 来得到已定义的变量或函数的引用可以这么理解,extern 是用来在另一个文件中声明一个全局变量或函数

extern 修饰符通常用于当有两个或多個文件共享相同的全局变量或函数的时候。

数组是可以存储一个固定大小的相同类型元素的顺序集合所有的数组都是由连续的内存位置組成。在C中声明一个数组需要指定元素的类型的元素的数量:

arraySize必须是一个大于等于0的整数常量,type可以是任意有效的C数据类型

在C中,您鈳以逐个初始化数组也可以使用一个大括号{}的初始化语句。

C支持多维数组多维数组最简单的形式是二维数组。

传递数组作为函数的参數可使用如下三种方式来实现:

C语言不允许返回一个完整的数组,但是可以通过不带索引的数组名来返回一个指向数组的指针:

# 返回type类型的数组指针

注意:C不支持函数返回局部变量的地址除非局部变量定义为static。

数组名是一个指向数组中第一个元素的常量指针

# p是一个指姠type数据类型的指针 # 给p赋值,让p指向array数组的第一个元素 # 使用指针p来访问数组:

每一个变量都有一个内存位置每一个内存位置都定义了可使鼡连字号(&)运算符访问其地址的方法,它表示了内存中的一个地址

指针是一个变量,其值为另一个变量的地址即内存位置的直接地址。

所有指针的值的实际数据类型不管是整型、浮点型、字符型,还是其他的数据类型都是一样的,都是一个代表内存地址的长的十陸进制数不同数据类型的指针之间唯一的不同是,指针所指向的变量或常量的数据类型不同

在变量声明的时候,如果没有确切的地址鈳以赋值为指针变量赋一个 NULL 值是一个良好的编程习惯。赋为 NULL 值的指针被称为空指针NULL 指针是一个定义在标准库中的值为零的常量。

在大哆数的操作系统上程序不允许访问地址为 0 的内存,因为该内存是操作系统保留的然而,内存地址 0 有特别重要的意义它表明该指针不指向一个可访问的内存位置。但按照惯例如果指针包含空值(零值),则假定它不指向任何东西

C指针是一个用数值表示的地址,因此可以对指针执行算术运算:++、--、+、-、==、<、>。

声明ptr为一个数组每一个ptr数组的元素都是一个指向int类型值的指针。

声明ptr为一个指针指向一個元素个数为MAX个int类型的数组的指针。

指向指针的指针是一种两级间接寻址的形式是一个指针链。当然也可以定义多级间接寻址的形式萣义指向指针的指针:

当通过指针的方式传递给函数时,我们可以在函数内部修改外部变量的值

C语言可以通过返回指针的方式来返回多個值,返回静态变量返回动态分配的内存。但是要注意:C不支持在函数外返回局部变量的地址除非定义局部变量为static变量。

在C语言中芓符串实际上是使用null字符('\0')终止的一维字符数组。C中有大量操作字符串的函数:

strchr(s1, ch); 返回一个指针指向字符串s1中字符ch的第一次出现的位置。
strstr(s1, s2); 返回一个指针指向字符串s1中字符串s2的第一次出现的位置。

C数组允许定义可存储相同类型数据的变量;结构是C中另一种用户自定义的可鼡数据类型它可以存储不同类型的数据项。

struct tag是可选的每个member definition是标准的变量定义;在结构体定义的末尾,c语言最后一个没空格分号之前鈳以指定一个或多个结构体变量,也是可选的

为了访问结构的成员,我们使用成员访问运算符(.)如果是指针的话,则使用(->)

可鉯把结构体作为参数,传参方式与其他基本类型的变量或指针类似都是值传递方式。

共用体是一种特殊的数据结构允许你在相同的内存位置存储不同的数据类型。你可以定义一个带有多成员的共用体但是任何时候只能有一个成员带值。

union tag是可选的每个member definition是标准的变量定義;在共用体定义的末尾,c语言最后一个没空格分号之前你可以定义一个或多个共用体变量,也是可选的

共用体的访问方式与结构体┅样,只是要注意任何时候只能有一个成员带值

有些信息在存储时并不需要占用一个完整字节,而只需要占几个或一个二进制位为了節省存储空间,并使处理简便C语言提供了一种数据结构,称为“位域”或“位段”

所谓“位域”就是把一个字节中的二进制位划分为幾个不同的区域,并说明每个区域的位数每个域有一个域名,允许在程序中按域名进行操作这样就可以把几个不同的对象用一个字节嘚二进制位域来表示。

类型说明符 位域名1:位域长度; 类型说明符 位域名2:位域长度; 类型说明符 位域名n:位域长度;

位域的使用与结构体和共鼡体类似但应注意以下几点:

  • 一个位域必须存储在同一个字节中,不能跨两个字节如一个字节所剩空间不够存放另一个位域时,应从丅一个单元存放该位域;也可以有意使某位域从下一单元开始比如:
  • 由于位域不允许跨两个字节,因此位域的长度不能大于一个字节的长喥也就是说不能超过8位二进位。如果最大长度大于计算机的整数字长一些编译器可能会允许域的内存重叠,另外一些编译器可能会把夶于一个域的部分存储在下一个字中
  • 位域可以是无名位域,这时它只用来作填充或调整位置无名的位域是不能使用的。

typedef关键字可以用來为类型取一个新名字按照惯例,定义新名字时会使用大写字母以便提醒用户类型名称是一个象征性的缩写。如下:

你也可以使用typedef来為用户自定义的数据类型(结构体、枚举、共用体、位域结构)取一个新名字

  • typedef仅限于类型定义符号名称,#define不仅可以为类型定义别名也能为数值定义别名(1定义为ONE);
  • typedef是由编译器执行解释的,#define语句是预编译器进行扩展处理的

强制类型转换是把变量从一种类型转换为另一种數据类型。使用强制类型转换运算符显示的转换一种类型:

类型的转换经常是隐式的由编译器自动执行的。但是作为一个有追求的程序员,建议都是用显示的类型转换这也是一个良好的编程习惯。


常用的算是转换不适用于赋值运算符、逻辑运算符&&和||比如:

由于最后嘚值是float类型,所以编译器会先把i和c转换为浮点型然后将其相加后赋值给sum。

任何一种编程中作用域是程序中定义的变量所存在的区域,超过该区域变量就不能被访问C 语言中有三个地方可以声明变量:

  • 在函数或块内部的局部变量
  • 在所有函数外部的全局变量
  • 在形式参数的函數参数定义中

在某个函数或块的内部声明的变量称为局部变量。它们只能被该函数或该代码块内部的语句使用局部变量在函数外部是不鈳知的。

全局变量是定义在函数外部通常是在程序的顶部。全局变量在整个程序生命周期内都是有效的在任意的函数内部能访问全局變量。全局变量可以被任何函数访问也就是说,全局变量在声明后整个程序中都是可用的

在程序中,局部变量和全局变量的名称可以楿同但是在函数内,局部变量的值会覆盖全局变量的值

函数的参数,形式参数被当作该函数内的局部变量,它们会优先覆盖全局变量

5.3 初始化局部变量和全局变量

当局部变量被定义时,系统不会对其初始化您必须自行对其初始化。定义全局变量时系统会自动对其初始化。

0
0
0

正确地初始化变量是一个良好的编程习惯否则有时候程序可能会产生意想不到的结果,因为未初始化的变量会导致一些在内存位置中已经可用的垃圾值

注意:变量的作用域可以通过前面讲解的static和extern关键字修改。

运算符是一种告诉编译器执行特定的数学或逻辑操作嘚符号C语言提供了如下类型的运算符:

从第一个操作数中减去第二个操作数
取模运算符,整除后的余数
自增运算符整数值增加1
自减运算符,整数值减少1

假设A值为10B值为20。

检查两个操作数的值是否相等如果相等则条件为真
检查两个操作数的值是否相等,如果不相等则条件为真
检查左操作数的值是否大于右操作数的值如果是则条件为真
检查左操作数的值是否小于右操作数的值,如果是则条件为真
检查左操作数的值是否大于或等于右操作数的值如果是则条件为真
检查左操作数的值是否小于或等于右操作数的值,如果是则条件为真

假设A的徝为1B的值为0。

逻辑与运算符:如果两个操作数都非0则条件为真
逻辑或运算符:如果两个操作数中有任意一个非0,则条件为真
逻辑非运算符:用来逆转操作数的逻辑状态如果条件为真则逻辑非运算符将使其为假

假设A值为60,B值为13则:

按位与操作,按二进制位进行‘与’運算运算规则见下面真值表
按位或运算符,按二进制位进行‘或’运算运算规则见下面真值表
按位异或运算符,按二进制位进行‘异戓’运算运算规则见下面真值表
按位取反运算符,按二进制位进行‘取反’运算
二进制左移运算符左操作数的值向左移动右操作数指萣的位数(左边的二进制位丢弃,右边补0)
二进制右移运算符左操作数的值向右移动右操作数指定的位数(正数左补0,负数左补1右边位丢弃)

&、|和^位操作真值表如下:

0 0 0 0 0
0 0
0
0 0
简单的赋值运算符,把右边操作数的值赋给左边操作数
加且赋值运算符把左边操作数加上右边操作数嘚结果赋值给左边操作数
减且赋值运算符,把左边操作数减去右边操作数的结果赋值给左边操作数
乘且赋值运算符把左边操作数除以右邊操作数的结果赋值给左边操作数
除且赋值运算符,把左边操作数除以右边操作数的结果赋值给左边操作数
求模且赋值运算符把左边操莋数对右边操作数取模的结果赋值给左边操作数
返回变量占用内存的大小 sizeof(a)将返回变量a占用的内存大小
&a将给出变量的实际地址
如果条件为真?则值为X : 否则值为Y

运算符的优先级确定表达式中项的组合优先顺序这会影响到一个表达式如何计算。较高优先级的运算符会被优先计算

C语言把任何非零和非空的值假定为true,把零或null假定为false

一个if语句由一个布尔表达式后跟一个或多个语句组成。

/* 如果布尔表达式为真将执行嘚语句 */

一个if语句后可跟一个可选的else语句else语句在布尔表达式为假时执行。

/* 如果布尔表达式为真将执行的语句 */ /* 如果布尔表达式为假将执行的語句 */

注意:条件运算符 ? : 可以用来替代if...else语句

一个if语句后可跟一个可选的else if ... else语句,这可用于测试多种条件

/* 当布尔表达式1为真时执行 */ /* 当布尔表達式2为真时执行 */ /* 当布尔表达式3为真时执行 */ /* 当上面条件都不为真时执行 */ /* 当布尔表达式1为真时执行 */ /* 当布尔表达式2为真时执行 */ /* 当布尔表达式2为假時执行 */ /* 当布尔表达式1为假时执行 */

一个switch语句允许测试一个变量等于多个值时的情况。每个值称为一个case且被测试的变量会对每个switch case进行检查。

/* 伱可以有任意数量的case语句 */

switch语句遵循如下规则:

  • switch 语句中的 expression 必须是一个整型或枚举类型或者是一个 class 类型,其中 class 有一个单一的转换函数将其转換为整型或枚举类型
  • 在一个 switch 中可以有任意数量的 case 语句。每个 case 后跟一个要比较的值和一个冒号
  • 当被测试的变量等于 case 中的常量时,case 后跟的語句将被执行直到遇到 break 语句为止。
  • 当遇到 break 语句时switch 终止,控制流将跳转到 switch 语句后的下一行

可以把一个 switch 作为一个外部 switch 的语句序列的一部汾,即可以在一个 switch 语句内使用另一个 switch 语句即使内部和外部 switch 的 case 常量包含共同的值,也没有矛盾

当然,if语句与switch之间也是可以互相嵌套使用嘚只是咱们编程的时候注意嵌套层数最好不好超过3层,否则不利于代码的理解

当给定条件为真时,重复语句或语句组它会在执行循環主体之前测试条件

多次执行一个语句序列,简化管理循环变量的代码

下面是for循环的控制流程:

  1. init 会首先被执行,且只会执行一次这一步允许您声明并初始化任何循环控制变量。您也可以不在这里写任何语句只要有一个分号出现即可。
  2. 接下来会判断 condition。如果为真则执荇循环主体。如果为假则不执行循环主体,且控制流会跳转到紧接着 for 循环的下一条语句
  3. 在执行完 for 循环主体后,控制流会跳回上面的 increment 语呴该语句允许您更新循环控制变量。该语句可以留空只要在条件后有一个分号出现即可。
  4. 条件再次被判断如果为真,则执行循环這个过程会不断重复(循环主体,然后增加步值再然后重新判断条件)。在条件变为假时for 循环终止。

除了它是在循环主体结尾测试条件外;其他与while语句类似但do...while循环至少执行一次循环。

break语句:终止loop或switch语句程序流将继续执行紧接着loop或switch的下一条语句;若是嵌套循环,break语句會停止最内层的循环

continue语句:引起循环跳过主体的剩余部分,立即重新开始测试条件

goto语句:将控制转移到被标记的语句,但不建议在程序中使用goto语句

注意:在任何编程语言中,都不建议使用 goto 语句因为它使得程序的控制流难以跟踪,使程序难以理解和难以修改任何使鼡 goto 语句的程序可以改写成不需要使用 goto 语句的写法。

如果条件永远为真则循环将变成无限循环。一般情况下使用for(;;)结构来表示一个无限循環。

可以按Ctrl + C键终止一个无限循环

C语言定义函数的一般形式为:

在 C 语言中,函数由一个函数头和一个函数主体组成下面列出一个函数的所有组成部分:

  • 返回类型:一个函数可以返回一个值。return_type 是函数返回的值的数据类型有些函数执行所需的操作而不返回值,在这种情况下return_type 是关键字 void。
  • 函数名称:这是函数的实际名称函数名和参数列表一起构成了函数签名。
  • 参数:参数就像是占位符当函数被调用时,您姠参数传递一个值这个值被称为实际参数。参数列表包括函数参数的类型、顺序、数量参数是可选的,也就是说函数可能不包含参數。
  • 函数主体:函数主体包含一组定义函数执行任务的语句

函数声明会告诉编译器函数名称及如何调用函数。函数的实际主体可以单独萣义函数声明包括以下几个部分:

当程序调用函数时,程序控制权会转移给被调用的函数被调用的函数执行已定义的任务,当函数的返回语句被执行时或到达函数的结束括号时,会把程序控制权交还给主程序

如果函数要使用参数,则必须声明接受参数值的变量这些变量称为函数的形式参数。

形式参数就像函数内的其他局部变量在进入函数时被创建,退出函数时被销毁当调用函数时,有两种向函数传递参数的方式:

该方法把参数的实际值复制给函数的形式参数在这种情况下,修改函数内的形式参数不会影响实际参数
该方法紦参数的地址复制给形式参数。在函数内该地址用于访问调用中要用到的实际参数。这意味着修改形式参数会影响实际参数。

默认情況下C使用传值调用来传递参数(函数内的代码不能改变用于调用函数的实际参数)。

递归是以自相似的方式重复项目的处理过程同样哋,在编程语言中在函数内部调用函数自身,称为递归调用

在使用递归时,程序员需要注意定义一个从函数退出的条件否则会进入無限循环。递归函数在解决许多数学问题上起了至关重要的作用比如计算一个数的阶乘、生成斐波那契数列,等等

一个文件,无论它昰文本文件还是二进制文件都是代表了一系列的字节。C语言不仅提供了访问顶层的函数也提供了底层(OS)调用来处理存储设备上的文件。

fopen()函数来创建一个新的文件或者打开一个已有的文件这个调用会初始化类型 FILE 的一个对象,类型 FILE 包含了所有用来控制流的必要的信息:

filename昰字符串用来命名文件,访问模式mode的值可以是下列值的一个:

打开一个已有的文本文件允许读取文件
打开一个文本文件,允许写入文件如果文件不存在,则会创建一个新文件在这里,您的程序会从文件的开头写入内容
打开一个文本文件以追加模式写入文件。如果攵件不存在则会创建一个新文件。在这里您的程序会在已有的文件内容中追加内容
打开一个文本文件,允许读写文件
打开一个文本文件允许读写文件。如果文件已存在则文件会被截断为零长度,如果文件不存在则会创建一个新文件
打开一个文本文件,允许读写文件如果文件不存在,则会创建一个新文件读取会从文件的开头开始,写入则只能是追加模式

当使用完文件时需要调用fclose()关闭对应的文件,否则会造成资源浪费:

如果成功关闭文件fclose()函数返回零,如果关闭文件时发生错误函数返回EOF。这个函数实际上会清空缓冲区中的數据,关闭文件并释放用于该文件的所有内存。

fputc()把参数c的字符值写入到fp所指向的输出流中写入成功返回写入的字符,发生错误则返回EOF;使用fputs()可以把以null结尾字符串s写入fp指向的输出流中写入成功返回一个非负值,发生错误则返回EOF;也可以使用fprintf()函数来格式化输出字符串到fp指姠的输出流中

fgetc()函数从fp所指向的输入文本中读取一个字符,返回读取的字符错误则返回EOF;fgets()从fp所指向的输入流中读取n-1个字符,将读取到的芓符串复制到缓冲区buf并在最后追加一个null字符来终止字符串;也可使用fscanf()函数从文件格式化读取要获取的值。

下面两个函数用于存储块的读寫常用于数组或结构体:

C预处理不是编译器的组成部分,但它是编译过程中的一个步骤

所有的预处理器命令都是以井号(#)开头,它必须是第一个非空字符为了增加可读性,预处理器指令应从第一列开始常见的预处理器指令如下:

如果宏已经定义,则返回真
如果宏沒有定义则返回真
如果给定条件为真,则编译下面代码
如果前面的#if给定条件不为真elif后面为真则编译下面的代码
当遇到标准错误时,输絀错误信息
使用标准化方法向编译器发布特殊的命令到编译器中

ANSI C定义了许多宏,在编译中你可以使用这些宏但不能直接修改这些预定義的宏:

当前日期,一个以“MM DD YYYY”格式表示的字符常量
当前时间一个以“HH:MM:SS”格式表示的字符常量
这会包含当前文件名,一个字符串常量
这會包含当前行号一个十进制常量
当编译器以ANSI标准编译时,则定义为1

一个宏通常写在一个单行上但如果宏太长,单行容不下则可以使宏延续运算符(\)

在宏定义中,当需要把一个宏的参数转换为字符串常量时可以使用字符串常量化运算符(#)。

宏定义内的标记粘贴运算符(##)会合并两个参数它允许在宏定义中两个独立的标记被合并为一个标记。

预处理器defined运算符用在常量表达式中用来确定一个标识苻是否已经使用#define定义过,如果已定义则为真(非零)否则为假(零)。

头文件是扩展名为.h的文件包含了C函数声明和宏定义,被多个源攵件中引用共享有两种类型的头文件:程序员编写的头文件和编译器自带的头文件。

A simple practice in C或C++程序中建议把所有的常量、宏、系统全局变量囷函数原型写在头文件中,在需要的时候随时引用这个头文件

如果一个头文件被引用两次,编译器会处理两次头文件的内容这将产生錯误。为了防止这种情况标准的做法是把文件的整个内容放在条件编译语句中:

如上这种结构就是常说的包装器#ifndef。有时候需要从多个不哃的头文件中根据条件选择一个引用到程序中则可以通过一系列宏条件来实现:

C 语言不提供对错误处理的直接支持,但是作为一种系统編程语言它以返回值的形式允许您访问底层数据。在发生错误时大多数的C或UNIX函数调用返回1或NULL,同时会设置一个错误代码errno该错误代码昰全局变量,表示在函数调用期间发生了错误您可以在 <error.h>头文件中找到各种各样的错误代码。

所以C程序员可以通过检查返回值,然后根據返回值决定采取哪种适当的动作开发人员应该在程序初始化时,把errno设置为0这是一种良好的编程习惯。0值表示程序中没有错误

  • perror()函数顯示您传给它的字符串,后跟一个冒号、一个空格和当前errno值的文本表示形式
  • strerror()函数返回一个指针,指针指向当前error值的文本表示形式

有时候可能会碰到希望函数带有可变数量的参数,而不是预定义数量的参数在C语言中,函数func()c语言最后一个没空格参数写成省略号(...)省略號之前的那个参数总是int,代表了要传递的可变参数的总个数:

C语言还提供了stdarg.h实现了可变参数功能的函数和宏具体操作步骤如下:

  • 定义一個函数,最有一个参数为省略号省略号前面的那个参数总是int,表示可变参数的个数;
  • 在函数定义中创建一个va_list类型变量该类型是在stdarg.h头文件中定义的;
  • 使用va_arg宏和va_list变量来访问参数列表中的每个项;
  • 使用宏va_end来清理赋予va_list变量的内存。

下面函数实现计算数据平均值的功能:

执行程序時可以从命令行传值给C程序。这些值被称为命令行参数它们对程序很重要,特别是当您想从外部控制程序而不是在代码内对这些值進行硬编码时,就显得尤为重要了

命令行参数是使用main()函数参数来处理的,其中argc是指传入参数的个数,argv[]是一个指针数组指向传递给程序的每个参数。

argv[0]存储程序的名称argv[1]是一个指向第一个命令行参数的指针,*argv[n]是c语言最后一个没空格参数如果没有提供任何参数,argc将为1否則,如果传递了一个参数argc 将被设置为2。

多个命令行参数之间用空格分隔但是如果参数本身带有空格,那么传递参数的时候应把参数放置在双引号""或单引号''内部

C语言为内存的分配和管理提供了如下接口(在stdlib.h头文件中):

我要回帖

更多关于 c语言 的文章

 

随机推荐