C语言基础快速复习

C语言基础

1,基础语法

  • 在 C 程序中,分号是语句结束符——“ ;”
  • C语言中的注释
    // 单行注释
    /*
    	多行注释
    */
    
  • 标识符
    C 标识符是用来标识变量、函数,或任何其他用户自定义项目的名称。
  • 关键字: 略
  • 空格使用:略

2,数据类型

  • 在 C 语言中,数据类型指的是用于声明不同类型的变量或函数的一个广泛的系统。变量的类型决定变量存储占用的空间,如何解释存储的位模式。
  • 类型
序号类型与描述
1基本类型:它们是算术类型,包括两种类型:整数类型和浮点类型。
2枚举类型:它们也是算术类型,被用来定义在程序中只能赋予其一定的离散整数值的变量。
3void 类型:类型说明符 void 表明没有可用的值。
4派生类型:它们包括:指针类型、数组类型、结构类型、共用体类型和函数类型。
  • 整数类型
类型存储大小值范围
char1 字节-128 到 127 或 0 到 255
unsigned char1 字节0 到 255
signed char1 字节-128 到 127
int2 或 4 字节-32,768 到 32,767 或 -2,147,483,648 到 2,147,483,647
unsigned int2 或 4 字节0 到 65,535 或 0 到 4,294,967,295
short2 字节-32,768 到 32,767
unsignedshort2 字节 0 到 65,535
long4 字节-2,147,483,648 到 2,147,483,647
unsigned long4 字节0 到 4,294,967,295

注意:各种类型的存储大小与系统位数有关,但目前通用的以64位系统为主。

  • 浮点类型
类型存储大小值范围精度
float4 字节1.2E-38 到 3.4E+386 位有效位
double8 字节2.3E-308 到 1.7E+30815 位有效位
long double16 字节3.4E-4932 到 1.1E+493219 位有效位
  • void 类型
序号类型与描述
1函数返回为空,C 中有各种函数都不返回值,或者您可以说它们返回空。不返回值的函数的返回类型为空。例如 void exit (int status);
2函数参数为空,C 中有各种函数不接受任何参数。不带参数的函数可以接受一个 void。例如 int rand(void);
3指针指向 void 类型为 void * 的指针代表对象的地址,而不是类型。例如,内存分配函数 void *malloc( size_t size ); 返回指向 void 的指针,可以转换为任何数据类型。

3,变量

  • 变量其实只不过是程序可操作的存储区的名称。C 中每个变量都有特定的类型,类型决定了变量存储的大小和布局,该范围内的值都可以存储在内存中,运算符可应用于变量上。
类型描述
char通常是一个字节(八位), 这是一个整数类型。
int整型,4 个字节,取值范围 -2147483648 到 2147483647。
float单精度浮点值。单精度是这样的格式,1位符号,8位指数,23位小数。
double双精度浮点值。双精度是1位符号,11位指数,52位小数。
void表示类型的缺失。
  • C 语言也允许定义各种其他类型的变量,比如枚举、指针、数组、结构、共用体等等。
  • 变量申明
    • 1、一种是需要建立存储空间的。例如:int a 在声明的时候就已经建立了存储空间。
    • 2、另一种是不需要建立存储空间的,通过使用extern关键字声明变量名而不定义它。 例如:extern int a 其中变量 a 可以在别的文件中定义的。
    • 除非有extern关键字,否则都是变量的定义。
    extern int i; // 声明,不是定义
    int i; // 声明,也是定义
    
  • C 中的左值(Lvalues)和右值(Rvalues) ,不是很懂!!!

3,常量

常量是固定值,在程序执行期间不会改变。这些固定的值,又叫做字面量。

  • 整数常量

    • 前缀指定基数:0x 或 0X 表示十六进制,0 表示八进制,不带前缀则默认表示十进制
    • 也可以带一个后缀,后缀是 U 和 L 的组合,U 表示无符号整数(unsigned),L 表示长整数(long)
  • 浮点数常量
    浮点常量由整数部分、小数点、小数部分和指数部分组成。您可以使用小数形式或者指数形式来表示浮点常量。带符号的指数是用 e 或 E 引入的。

  • 字符常量
    在 C 中,有一些特定的字符,当它们前面有反斜杠时,它们就具有特殊的含义,被用来表示如换行符(\n)或制表符(\t)等。下表列出了一些这样的转义序列码:

    转义序列含义
    \\\ 字符
    \’’ 字符
    \"" 字符
    \?? 字符
    \a警报铃声
    \b退格键
    \f换页符
    \n换行符
    \r回车
    \t水平制表符
    \v垂直制表符
    \ooo一到三位的八进制数
    \xhh . . .一个或多个数字的十六进制数
  • 定义常量

    • 1 使用 #define 预处理器。
    • 2 使用 const 关键字。
    // #define 预处理器
    #define identifier value
    // const
    const type variable = value;
    

4,存储类

  • 存储类定义 C 程序中变量/函数的范围(可见性)和生命周期。这些说明符放置在它们所修饰的类型之前。
    • auto:
      auto 存储类是所有局部变量默认的存储类。
    • register:
      register 存储类用于定义存储在寄存器中而不是 RAM 中的局部变量。这意味着变量的最大尺寸等于寄存器的大小(通常是一个字),且不能对它应用一元的 ‘&’ 运算符(因为它没有内存位置)。
      寄存器只用于需要快速访问的变量,比如计数器。还应注意的是,定义 ‘register’ 并不意味着变量将被存储在寄存器中,它意味着变量可能存储在寄存器中,这取决于硬件和实现的限制。
    • static
      static 存储类指示编译器在程序的生命周期内保持局部变量的存在,而不需要在每次它进入和离开作用域时进行创建和销毁。因此,使用 static 修饰局部变量可以在函数调用之间保持局部变量的值。
      static 修饰符也可以应用于全局变量。当 static 修饰全局变量时,会使变量的作用域限制在声明它的文件内。
    • extern
      extern 存储类用于提供一个全局变量的引用,全局变量对所有的程序文件都是可见的。当您使用 extern 时,对于无法初始化的变量,会把变量名指向一个之前定义过的存储位置。

5,运算符

  • ”++“与”- -“运算符,尽量精简单行使用,不要混合使用。
  • 逻辑运算符
运算符描述
&&称为逻辑与运算符。如果两个操作数都非零,则条件为真。
||称为逻辑或运算符。如果两个操作数中有任意一个非零,则条件为真。
!称为逻辑非运算符。用来逆转操作数的逻辑状态。如果条件为真则逻辑非运算符将使其为假。
  • 位运算
    位运算符作用于位,并逐位执行操作。&、 | 和 ^
    << :二进制左移运算符。将一个运算对象的各二进制位全部左移若干位(左边的二进制位丢弃,右边补0)。
    >> :二进制右移运算符。将一个数的各二进制位全部右移若干位,正数左补0,负数左补1,右边丢弃。
  • 其他运算符
运算符描述实例
sizeof()返回变量的大小。sizeof(a) 将返回 4,其中 a 是整数。
&返回变量的地址。&a; 将给出变量的实际地址。
*指向一个变量。*a; 将指向一个变量。
? :条件表达式如果条件为真 ? 则值为 X : 否则值为 Y

6,运算符

  • 判断语句
语句描述
if 语句一个 if 语句 由一个布尔表达式后跟一个或多个语句组成。
if…else 语句一个 if 语句 后可跟一个可选的 else 语句,else 语句在布尔表达式为假时执行。
嵌套 if 语句您可以在一个 if 或 else if 语句内使用另一个 if 或 else if 语句。
switch 语句一个 switch 语句允许测试一个变量等于多个值时的情况。
嵌套 switch 语句您可以在一个 switch 语句内使用另一个 switch 语句。
  • ? : 运算符(三元运算符)

    ExpA ? ExpB : ExpC;
    

7,循环语句

  • 循环类型
循环类型描述
while 循环当给定条件为真时,重复语句或语句组。它会在执行循环主体之前测试条件。
for 循环多次执行一个语句序列,简化管理循环变量的代码。
do…while 循环除了它是在循环主体结尾测试条件外,其他与 while 语句类似。
嵌套循环您可以在 while、for 或 do…while 循环内使用一个或多个循环。
break 语句终止循环或 switch 语句,程序流将继续执行紧接着循环或 switch 的下一条语句。
continue 语句告诉一个循环体立刻停止本次循环迭代,重新开始下次循环迭代。
goto 语句将控制转移到被标记的语句。但是不建议在程序中使用 goto 语句。(建议不用

8,函数

  • 函数是一组一起执行一个任务的语句。每个 C 程序都至少有一个函数,即主函数 main() ,所有简单的程序都可以定义其他额外的函数。

  • 定义函数

    return_type function_name( parameter list )
    {
       body of the function
    }
    

    当程序调用函数时,程序控制权会转移给被调用的函数。被调用的函数执行已定义的任务,当函数的返回语句被执行时,或到达函数的结束括号时,会把程序控制权交还给主程序。
    调用函数时,传递所需参数,如果函数返回一个值,则可以存储返回值。

  • 函数参数传递

调用类型描述
传值调用该方法把参数的实际值复制给函数的形式参数。在这种情况下,修改函数内的形式参数不会影响实际参数。
引用调用通过指针传递方式,形参为指向实参地址的指针,当对形参的指向操作时,就相当于对实参本身进行的操作。
  • 变量作用域
    • 在程序中,局部变量和全局变量的名称可以相同,但是在函数内,如果两个名字相同,会使用局部变量值,全局变量不会被使用。

9,数组

  • 数组声明
    在 C 中要声明一个数组,需要指定元素的类型和元素的数量,
type arrayName [ arraySize ];
// 例子
double balance[10];
// 初始化
double balance[5] = {1000.0, 2.0, 3.4, 7.0, 50.0};
  • 示例
#include <stdio.h>

int main()
{
    int a[2] = {1,2};
    printf("a      = %d\n",a[0]);
    printf("*(a+0) = %d\n",*(a + 0));
    printf("a[1]   = %d\n",a[1]);
    printf("*a     = %d\n",*a);
    printf("*(a+1) = %d\n",*(a + 1));
    printf("\n");
    printf("a    的地址:%p\n",a);
    printf("(a+0)的地址:%p\n",(a + 0));
    printf("(a+1)的地址:%p\n",(a + 1));
    // %p 读入一个指针
    printf("\n");
    return 0;
}

// 结果
	a      = 1
	*(a+0) = 1
	a[1]   = 2
	*a     = 1
	*(a+1) = 2
	
	a    的地址:0x7ffe9e227634
	(a+0)的地址:0x7ffe9e227634
	(a+1)的地址:0x7ffe9e227638
  • 事实上 a[0] 、a[1]…a[i] 代表的都是值,a、(a+0)、(a+1)、(a+i) 代表的是地址;另外这里的 a 代表整个数组的首地址,相当于 a[0] 的地址,而这里 (a+1) 就代表的是 a[0+1] 的地址。

10,enum(枚举)

枚举是 C 语言中的一种基本数据类型,它可以让数据更简洁,更易读。

  • 定义
enum 枚举名 {枚举元素1,枚举元素2,……};
// 例
enum DAY
{
      MON=1, TUE, WED, THU, FRI, SAT, SUN
};
  • 注意:第一个枚举成员的默认值为整型的 0,后续枚举成员的值在前一个成员上加 1。我们在这个实例中把第一个枚举成员的值定义为 1,第二个就为 2,以此类推。
  • 先定义枚举类型,再定义枚举变量
enum DAY
{
      MON=1, TUE, WED, THU, FRI, SAT, SUN
};
enum DAY day;
  • 定义枚举类型的同时定义枚举变量
  • 枚举其实可以直接使用
enum DAY
{
      MON=1, TUE, WED, THU, FRI, SAT, SUN
} day;

11,指针(重要)

11.1什么是指针

指针也就是内存地址,指针变量是用来存放内存地址的变量。就像其他变量或常量一样,您必须在使用指针存储其他变量地址之前,对其进行声明。指针变量声明的一般形式为:

// type 是指针的基类型,它必须是一个有效的 C 数据类型,var_name 是指针变量的名称
type *var_name;

int    *ip;    /* 一个整型的指针 */
double *dp;    /* 一个 double 型的指针 */
float  *fp;    /* 一个浮点型的指针 */
char   *ch;    /* 一个字符型的指针 */
  • 每一个变量都有一个内存位置,每一个内存位置都定义了可使用 & 运算符访问的地址,它表示了在内存中的一个地址。
  • 在变量声明的时候,如果没有确切的地址可以赋值,为指针变量赋一个 NULL 值是一个良好的编程习惯。赋为 NULL 值的指针被称为空指针。NULL 指针是一个定义在标准库中的值为零的常量。
  • 指针详情
概念描述
指针的算术运算可以对指针进行四种算术运算:++、–、+、-
指针数组可以定义用来存储指针的数组。
指向指针的指针C 允许指向指针的指针。
传递指针给函数通过引用或地址传递参数,使传递的参数在调用函数中被改变。
从函数返回指针C 允许函数返回指针到局部变量、静态变量和动态内存分配。
11.2 函数指针

函数指针是指向函数的指针变量。函数指针可以像一般函数一样,用于调用函数、传递参数。

  • 函数指针变量的声明:
typedef int (*fun_ptr)(int,int); // 声明一个指向同样参数、返回值的函数指针类型
  • 回调函数
  • 函数指针变量可以作为某个函数的参数来使用的,回调函数就是一个通过函数指针调用的函数。
以下是来自知乎作者常溪玲的解说:
你到一个商店买东西,刚好你要的东西没有货,于是你在店员那里留下了你的电话,
过了几天店里有货了,店员就打了你的电话,然后你接到电话后就到店里去取了货。
在这个例子里,你的电话号码就叫回调函数,你把电话留给店员就叫登记回调函数,
店里后来有货了叫做触发了回调关联的事件,店员给你打电话叫做调用回调函数,
你到店里去取货叫做响应回调事件。

12,字符串

  • 在 C 语言中,字符串实际上是使用空字符 \0 结尾的一维字符数组。因此,\0 是用于标记字符串的结束。
  • C 中有大量操作字符串的函数:
序号函数 & 目的
1strcpy(s1, s2); 复制字符串 s2 到字符串 s1。
2strcat(s1, s2);连接字符串 s2 到字符串 s1 的末尾。
3strlen(s1);返回字符串 s1 的长度。
4strcmp(s1, s2);如果 s1 和 s2 是相同的,则返回 0;如果 s1<s2 则返回小于 0;如果 s1>s2 则返回大于 0。
5strchr(s1, ch);返回一个指针,指向字符串 s1 中字符 ch 的第一次出现的位置。
6strstr(s1, s2);返回一个指针,指向字符串 s1 中字符串 s2 的第一次出现的位置。

13,结构体

  • C 数组允许定义可存储相同类型数据项的变量,结构是 C 编程中另一种用户自定义的可用的数据类型,它允许您存储不同类型的数据项。
// 初始化
struct tag { 
    member-list
    member-list 
    member-list  
    ...
} variable-list ;
// 示例
struct Books
{
   char  title[50];
   char  author[50];
   char  subject[100];
   int   book_id;
} book;

14,共用体

  • 共用体是一种特殊的数据类型,允许您在相同的内存位置存储不同的数据类型。您可以定义一个带有多成员的共用体,但是任何时候只能有一个成员带有值。共用体提供了一种使用相同的内存位置的有效方式。
  • 定义
    您必须使用 union 语句,方式与定义结构类似。union 语句定义了一个新的数据类型,带有多个成员。
union [union tag]
{
   member definition;
   member definition;
   ...
   member definition;
} [one or more union variables];
  • 共用体占用的内存应足够存储共用体中最大的成员。
  • 访问共用体成员
    使用成员访问运算符(.),在同一时间一般只使用一个变量,能够完好输出的。

15,位域

  • 如果程序的结构中包含多个开关量,只有 TRUE/FALSE 变量,这种结构需要 8 字节的内存空间,但在实际上,在每个变量中,我们只存储 0 或 1。在这种情况下,C 语言提供了一种更好的利用内存空间的方式。
struct
{
  unsigned int widthValidated;
  unsigned int heightValidated;
} status;

// 列子
struct
{
  unsigned int widthValidated : 1;
  unsigned int heightValidated : 1;
} status;

现在,上面的结构中,status 变量将占用 4 个字节的内存空间,但是只有 2 位被用来存储值。有些信息在存储时,并不需要占用一个完整的字节,而只需占几个或一个二进制位。例如在存放一个开关量时,只有 0 和 1 两种状态,用 1 位二进位即可。为了节省存储空间,并使处理简便,C 语言又提供了一种数据结构,称为"位域"或"位段"。

元素描述
type只能为 int(整型),unsigned int(无符号整型),signed int(有符号整型) 三种类型,决定了如何解释位域的值。
member_name位域的名称。
width位域中位的数量。宽度必须小于或等于指定类型的位宽度。
struct bs{
    int a:8;
    int b:2;
    int c:6;
}data;
// data 为 bs 变量,共占两个字节。其中位域 a 占 8 位,位域 b 占 2 位,位域 c 占 6 位。

// 示例
#include <stdio.h>
 
int main(){
    struct bs{
        unsigned a:1;
        unsigned b:3;
        unsigned c:4;
    } bit,*pbit;
    bit.a=1;    /* 给位域赋值(应注意赋值不能超过该位域的允许范围) */
    bit.b=7;    /* 给位域赋值(应注意赋值不能超过该位域的允许范围) */
    bit.c=15;    /* 给位域赋值(应注意赋值不能超过该位域的允许范围) */
    printf("%d,%d,%d\n",bit.a,bit.b,bit.c);    /* 以整型量格式输出三个域的内容 */
    pbit=&bit;    /* 把位域变量 bit 的地址送给指针变量 pbit */
    pbit->a=0;    /* 用指针方式给位域 a 重新赋值,赋为 0 */
    pbit->b&=3;    /* 使用了复合的位运算符 "&=",相当于:pbit->b=pbit->b&3,位域 b 中原有值为 7,与 3 作按位与运算的结果为 3(111&011=011,十进制值为 3) */
    pbit->c|=1;    /* 使用了复合位运算符"|=",相当于:pbit->c=pbit->c|1,其结果为 15 */
    printf("%d,%d,%d\n",pbit->a,pbit->b,pbit->c);    /* 用指针方式输出了这三个域的值 */
}

16,typedef

C 语言提供了 typedef 关键字,您可以使用它来为类型取一个新的名字。

typedef unsigned char BYTE;
// 实例为单字节数字定义了一个术语 BYTE
  • 按照惯例,定义时会大写字母,以便提醒用户类型名称是一个象征性的缩写,您也可以使用 typedef 来为用户自定义的数据类型取一个新的名字。
typedef struct Books
{
   char  title[50];
   char  author[50];
   char  subject[100];
   int   book_id;
} Book;
 
int main( )
{
   Book book;
   // 没有typedef则使用:struct Book book;
 
   strcpy( book.title, "C 教程");
   strcpy( book.author, "Runoob"); 
   strcpy( book.subject, "编程语言");
   book.book_id = 12345;
 
   printf( "书标题 : %s\n", book.title);
   printf( "书作者 : %s\n", book.author);
   printf( "书类目 : %s\n", book.subject);
   printf( "书 ID : %d\n", book.book_id);
 
   return 0;
}
  • #define 是 C 指令,用于为各种数据类型定义别名,与 typedef 类似,但是它们有以下几点不同:

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

17, 输入 & 输出

C 语言把所有的设备都当作文件。所以设备(比如显示器)被处理的方式与文件相同。以下三个文件会在程序执行时自动打开,以便访问键盘和屏幕。

  • C 语言中的 I/O (输入/输出) 通常使用 printf() 和 scanf() 两个函数。
  • scanf() 函数用于从标准输入(键盘)读取并格式化, printf() 函数发送格式化输出到标准输出(屏幕)。
  • getchar() & putchar() 函数
    int getchar(void) 函数从屏幕读取下一个可用的字符,并把它返回为一个整数。这个函数在同一个时间内只会读取一个单一的字符。您可以在循环内使用这个方法,以便从屏幕上读取多个字符。
    int putchar(int c) 函数把字符输出到屏幕上,并返回相同的字符。这个函数在同一个时间内只会输出一个单一的字符。您可以在循环内使用这个方法,以便在屏幕上输出多个字符。
#include <stdio.h>
 
int main( )
{
   int c;
 
   printf( "Enter a value :");
   c = getchar( );
 
   printf( "\nYou entered: ");
   putchar( c );
   printf( "\n");
   return 0;
}
  • gets() & puts() 函数
    char *gets(char *s)函数从 stdin 读取一行到 s 所指向的缓冲区,直到一个终止符或 EOF。
    int puts(const char *s) *函数把字符串 s 和一个尾随的换行符写入到 stdout。
#include <stdio.h>
 
int main( )
{
   char str[100];
 
   printf( "Enter a value :");
   gets( str );
 
   printf( "\nYou entered: ");
   puts( str );
   return 0;
}
  • scanf() 和 printf() 函数
    int scanf(const char *format, …)*函数从标准输入流 stdin 读取输入,并根据提供的 format 来浏览输入。
    int printf(const char *format, …)函数把输出写入到标准输出流 stdout ,并根据提供的格式产生输出。

18,文件读取

  • 创建、打开、关闭文本文件或二进制文件。
  • 可以使用 fopen( ) 函数来创建一个新的文件或者打开一个已有的文件,这个调用会初始化类型 FILE 的一个对象,类型 FILE 包含了所有用来控制流的必要的信息。下面是这个函数调用的原型:
FILE *fopen( const char *filename, const char *mode );
模式描述
r打开一个已有的文本文件,允许读取文件。
w打开一个文本文件,允许写入文件。如果文件不存在,则会创建一个新文件。在这里,您的程序会从文件的开头写入内容。如果文件存在,则该会被截断为零长度,重新写入。
a打开一个文本文件,以追加模式写入文件。如果文件不存在,则会创建一个新文件。在这里,您的程序会在已有的文件内容中追加内容。
r+打开一个文本文件,允许读写文件。
w+打开一个文本文件,允许读写文件。如果文件已存在,则文件会被截断为零长度,如果文件不存在,则会创建一个新文件。
a+打开一个文本文件,允许读写文件。如果文件不存在,则会创建一个新文件。读取会从文件的开头开始,写入则只能是追加模式。
  • 如果处理的是二进制文件,则需使用下面的访问模式来取代上面的访问模式:
    "rb", "wb", "ab", "rb+", "r+b", "wb+", "w+b", "ab+", "a+b"
  • 关闭文件,请使用 fclose( ) 函数
  • 写入文件
  • 读取文件
FILE *fopen( const char *filename, const char *mode ); //打开
int fclose( FILE *fp ); // 关闭
int fputc( int c, FILE *fp ); // 写入
int fgetc( FILE * fp ); // 读取
  • 实例
#include <stdio.h>
 
int main()
{
   FILE *fp = NULL;
 
   fp = fopen("/tmp/test.txt", "w+");
   fprintf(fp, "This is testing for fprintf...\n");
   fputs("This is testing for fputs...\n", fp);
   fclose(fp);
}
  • 二进制 I/O 函数
    下面两个函数用于二进制输入和输出:
size_t fread(void *ptr, size_t size_of_elements, 
             size_t number_of_elements, FILE *a_file);
              
size_t fwrite(const void *ptr, size_t size_of_elements, 
             size_t number_of_elements, FILE *a_file);

19,预处理器

预处理器不是编译器的组成部分,但是它是编译过程中一个单独的步骤。简言之,C 预处理器只不过是一个文本替换工具而已,它们会指示编译器在实际编译之前完成所需的预处理。我们将把 C 预处理器(C Preprocessor)简写为 CPP。
所有的预处理器命令都是以井号(#)开头。它必须是第一个非空字符,为了增强可读性,预处理器指令应从第一列开始。

指令描述
#define定义宏
#include包含一个源代码文件
#undef取消已定义的宏
#ifdef如果宏已经定义,则返回真
#ifndef如果宏没有定义,则返回真
#if如果给定条件为真,则编译下面代码
#else#if 的替代方案
#elif如果前面的 #if 给定条件不为真,当前条件为真,则编译下面代码
#endif结束一个 #if……#else 条件编译块
#error当遇到标准错误时,输出错误消息
#pragma使用标准化方法,向编译器发布特殊的命令到编译器中
  • 预定义宏
    ANSI C 定义了许多宏。在编程中您可以使用这些宏,但是不能直接修改这些预定义的宏。
描述
DATE当前日期,一个以 “MMM DD YYYY” 格式表示的字符常量。
TIME当前时间,一个以 “HH:MM:SS” 格式表示的字符常量。
FILE这会包含当前文件名,一个字符串常量。
LINE这会包含当前行号,一个十进制常量。
STDC当编译器以 ANSI 标准编译时,则定义为 1。
  • 预处理器运算符
    宏延续运算符(\)
    一个宏通常写在一个单行上。但是如果宏太长,一个单行容纳不下,则使用宏延续运算符(\)。
    字符串常量化运算符(#)
    在宏定义中,当需要把一个宏的参数转换为字符串常量时,则使用字符串常量化运算符(#)。在宏中使用的该运算符有一个特定的参数或参数列表。
    标记粘贴运算符(##)
    宏定义内的标记粘贴运算符(##)会合并两个参数。它允许在宏定义中两个独立的标记被合并为一个标记。
  • 参数化的宏

20,头文件

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

  • 引用头文件的语法
    使用预处理指令 #include 可以引用用户和系统头文件。它的形式有以下两种:
// 它在系统目录的标准列表中搜索名为 file 的文件。
#include <file>
// 引用用户头文件。它在包含当前文件的目录中搜索名为 file 的文件。
#include "file"

21,强制类型转换

  • 强制类型转换是把变量从一种类型转换为另一种数据类型。
(type_name) expression
// 示例
#include <stdio.h>
 
int main()
{
   int sum = 17, count = 5;
   double mean;
 
   mean = (double) sum / count;
   printf("Value of mean : %f\n", mean );
 
}

// 结果
Value of mean : 3.400000

22,错误处理

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

  • errno、perror() 和 strerror()
    C 语言提供了 perror() 和 strerror() 函数来显示与 errno 相关的文本消息。
    • perror() 函数显示您传给它的字符串,后跟一个冒号、一个空格和当前 errno 值的文本表示形式。
    • strerror() 函数,返回一个指针,指针指向当前 errno 值的文本表示形式。
  • 示例
#include <stdio.h>
#include <errno.h>
#include <string.h>
 
extern int errno ;
 
int main ()
{
   FILE * pf;
   int errnum;
   pf = fopen ("unexist.txt", "rb");
   if (pf == NULL)
   {
      errnum = errno;
      fprintf(stderr, "错误号: %d\n", errno);
      perror("通过 perror 输出错误");
      fprintf(stderr, "打开文件错误: %s\n", strerror( errnum ));
   }
   else
   {
      fclose (pf);
   }
   return 0;
}
//结果
错误号: 2
通过 perror 输出错误: No such file or directory
打开文件错误: No such file or directory

23,内存处理

垃圾回收,处理是一个比较重要的问题

  • C 中的动态内存管理。C 语言为内存的分配和管理提供了几个函数。这些函数可以在 <stdlib.h> 头文件中找到。
序号函数和描述
1void calloc(int num, int size); 在内存中动态地分配 num 个长度为 size 的连续空间,并将每一个字节都初始化为 0。所以它的结果是分配了 numsize 个字节长度的内存空间,并且每个字节的值都是0。
2void free(void *address); 该函数释放 address 所指向的内存块,释放的是动态分配的内存空间。
3void *malloc(int num); 在堆区分配一块指定大小的内存空间,用来存放数据。这块内存空间在函数执行完成后不会被初始化,它们的值是未知的。
4void *realloc(void *address, int newsize); 该函数重新分配内存,把内存扩展到 newsize。
  • 动态开辟内存
    预先不知道需要存储的文本长度,例如您想存储有关一个主题的详细描述。在这里,我们需要定义一个指针,该指针指向未定义所需内存大小的字符,后续再根据需求来分配内存。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
int main()
{
   char name[100];
   char *description;
 
   strcpy(name, "Zara Ali");
 
   /* 动态分配内存 */
   /*	返回值的类型为void*型, malloc()函数并不知道连续开辟的size个字节是存储什么类型数据的 ,
   所以需要我们自行决定 ,方法是在malloc()前加强制转 ,转化成我们所需类型 ,如:  */ 
   (int*)malloc(sizeof(int)*n).
   description = (char *)malloc( 200 * sizeof(char) );
   if( description == NULL )
   {
      fprintf(stderr, "Error - unable to allocate required memory\n");
   }
   else
   {
      strcpy( description, "Zara ali a DPS student in class 10th");
   }
   printf("Name = %s\n", name );
   printf("Description: %s\n", description );
}
  • 函数 realloc() 来增加或减少已分配的内存块的大小。
description = (char *)malloc( 30 * sizeof(char) );
/* 假设您想要存储更大的描述信息 */
description = (char *) realloc( description, 100 * sizeof(char) );

24,命令行参数

  • 执行程序时,可以从命令行传值给 C 程序。这些值被称为命令行参数,它们对程序很重要,特别是当您想从外部控制程序,而不是在代码内对这些值进行硬编码时,就显得尤为重要了。
  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值