C语言语法和库函数-学习笔记

一、简介

C语言是在1978年,K&R为了编写UNix操作系统,从B语言的基础上改进而来。

在1989年被美国美国国家标准协会ANSI标准化,称之为C89(第二版)。

1999年再次标准化C99(第二版)

2011年再次被标准化C11(第三版)

目前linux系统,单片机开发等底层开发都使用C语言开发,搭配 GNU 的 C/C++ 编译器使用。

二、语言特点

从上到下执行,有预处理器#,分支、循环、指针三大法宝。作用域以代码块来分开

三、C编译器语法:包括了预处理器#

1.数据类型:决定存储单元和如何解释存储的数据。

基本数据类型:整数(int)、小数(float)、字符(char).

枚举数据类型:枚举(enum)

void类型:void * 类型表示未确定类型的指针。C、C++ 规定 void * 类型可以通过类型转换强制转换为任何其它类型的指针。

派生类型:数组(array)、指针(*p)、结构体(struct)

typedef关键字:可以自己定义数据类型

2.变量:某一块内存的别名

1.命名规则:数字、字母、下划线组成且不能以数字开头。

2.声明与定义:不分配存储空间,定义:即有赋初值,并分配存储空间。

对变量而言只有extern 是才是声明,其余全是定义。函数不带{}时就是声明,带{}时就是定义。

3.左值和右值:左值是地址,右值是数据,故在赋值(=)时,右值不可以在左边只能在右边,而左值均可以,因为赋值语句(a = b),对左边的变量是写操作,对右边的变量是读操作。

3.常量:其值在程序运行期间不可修改

在程序期间其值不可以修改,有整数常量10,小数常量,字符常量'a',字符串常量“abcd”

对字符串常量编译器会自动在最后加NUL=\0作为结尾,在声明char array[]时数组长度要比字符串多1个用来存储\0.

4.存储类型:

可调整变量、函数的存储位置、局部变量的生命周期、全局变量的作用域。

①对局部变量,默认是atuo,进入函数使用变量,退出函数释放变量。加static后,内存不会被释放,且值只能初始化一次。相当于常量啦。

②对全局变量:默认是static,其作用域是整个源程序,加static修饰作用域限制为本文件内部且只能初始化一次。

③对函数:普通函数在每个没调用周期内维持一份,加static后在内存中只有一份,这一点没太多优势。

5.运算符:5类

1.算术运算符:加、减、乘、除(/)、取余(%)、自增(++)、自减(--)

2.关系运算符:大于(>)、小于(<)、等于(==)、不等于(!=)、大于等于(>=)、小于等于(<=)

3.逻辑运算符:与(&&)、或(||)、非(!)

4.位运算:位与(&)、位或(|)、位异或(^)、按位取反(~)、按位左移动(<<)、按位右移(>>)

5.简单赋值运算:=

6.复合赋值运算: 算术运算符、位运算符与简单运算符号组合成新的运算符号
+=、-=、*=、/=、%=、&=、|=、^=、<<=、>>=

7.杂项运算符: 求变量内存单元sizeof()、取地址符&、指针运算符*、如果A为真?则值为x:否则为y。逗号表达式A,B,C;返回C的值。

条件表达式如一组if(条件为真) 执行x,否则else执行y


6.分支语句:2个

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

if...else,和swtich....case、条件表达式?:

7.循环语句:

计数循环:for ( ;  ; )  

条件循环while()、 do ....while()

死循环:while(1) 或者for( ; ; )for循环条件为空默为真。

8.退出循环语句:

break;退出本级循环、退出swtich

continue;终止本次循环,开始下一次循环

goto  语句标号: 跳转到语句标号执行

9.作用域规则:

1.大括号内部的为局部变量,包括函数的大括号或者块。作用域再块内部有效,存放再动态区(栈)

2.大括号外部的为全局变量,存在静态区,作用域为整个程序,static可以修改为本文件内部。

3.函数形参为函数{}内部的局部变量

4.当全局变量和局部变量同名时,使用局部变量。

10.数组:申请一篇连续的内存单元,且每个内存单元相等,即同类型变量。

1.数组名为数组地址,即数组首元素的地址

2.按照列来存放,故一位数组可以省略数组单元长度,二位数组第二位列长度不可以省略。

3.静态数组再申明时指定内存块大小,动态内存根据需要手动分配。

11.枚举:默认从0开始增加1,也可以指定

声明:enum 枚举名{ }枚举变量名;此处枚举名相当于结构名,相当于类型名。

声明时:枚举名和变量名至少有一个,可以同时存在。结构体定义一样。

ege:enum Day{ MON,TUE,WED,THU,FRI,SAT,SUN}day;其中Day和day最多只能省略一个。

12.指针变量:用来存放普通变量地址的变量,普通变量是用来存值的。

13.函数指针和回调函数:

1.函数指针:存储函数地址的变量。声明将指向的函数名改为指针变量即可。

typedef int (*fun_ptr)(int,int); // 声明一个指向同样参数、返回值的函数指针类型

2.回调函数,函数指针作为另外一个函数的参数,需要先注册,再使用。

此函数中回调函数是getNextRandomValue产生随机数的函数。因为给函数指针传递的是此函数的地址。

14.字符串:字符串实际上是使用空字符 \0 结尾的一维字符数组

空字符(Null character)又称结束符,缩写 NUL,是一个数值为 0 的控制字符,\0 是转义字符,意思是告诉编译器,这不是字符 0,而是空字符。

ege:   char site[] = "RUNOOB";

结尾的\0由编译器自动添加。

15.结构体:指向自己的数据结构,构建链表注意理解

声明:struct 结构名{ 成员}结构变量,此处类型名是struct 结构名。

指向结构自己,为了构建链表、树等高级数据结构,每个节点都有相同的数据类型

16.共用体union

成员占用同一块内存,内存大小由最大的成员决定,可以存储不同类型的变量。即在这块内存上不用区分数据类型了。共用体变量访问用.指针用->

17.结构体位域:为了节省内存定义的,按二进制位分配存储单元

struct 位域名

{

  类型 变量名:宽度      //类型名只能为signed \unsigned int,宽度不能操作类型宽度

}

18.typedef 与#define异同

1.typedef与#define均可对类型取别名,但是#define还可以给数值取别名,而typedef不行。

2.#define由预处理器解释,typedef由编译器解释

3.语法相反:typedef 原名  新名字;#define   新名  原名;

19.预处理器:文本替换工具,在编译器之前替换,均以#开头

1.处理指令:

#define: 定义宏

#include :包含一个源代码文件

#undef :取消已定义的宏

#ifdef、#endif如果宏以定义返回真与#endif搭配使用

#ifndef:如果宏没有定义返回真

#if、#elif、#else与if 、else if、else一样

#error:预处理时遇到#error停止编译,并答应#error后面定义的信息(与编译器有关)

#pragma:预处理时遇到#pragma可以打印信息,但是运行时不打(与编译器有关)

2.预处理器运算符

延续运算符(\):宏太长可以使用\来延续,相当于在一行上

字符串常量化运算符(#):将形参转换为字符串常量

标记粘贴运算符(##):将两个参数拼接为一个参数。

3.参数化的宏:可以定义宏函数

4.预处理器内置的宏:

__DATA__:当前日期,以"MMM  DD  YYYY"表示的字符常量

__TIME__:当前日期,一个”“HH:MM:SS"格式表示的字符常量

__FILE__:当前文件名,一个字符串常量

__LINE__:当前行号,一个十进制常量

—STDC__,当以ANSI标准编译时,则定义为1

20.头文件:

#include<file>:编译器到自己根目录去寻找file

#include"file":编译器到当前工程空间下寻找file

21.类型转换说明符:重新分配有效存储单元

1.类型转换分为隐式转换和显示转换。对算术运算符存在隐式转换,对赋值运算符和逻辑运算符&&\||不存在隐式转换。隐式转换常常用于char 、int、long、long、foat、double类型之间转换

2.显示转换由程序员自己决定转换:(new_type) 变量名

22.递归函数:即函数调用自己,一直循环。

计算数学问题时很有帮助:如数的阶乘、斐波那契数列。

①计算数的阶乘:

#include <stdio.h>
 
double factorial(unsigned int i)
{
   if(i <= 1)
   {
      return 1;
   }
   return i * factorial(i - 1);
}
int  main()
{
    int i = 14;
    printf("%d 的阶乘为 %f\n", i, factorial(i));
    return 0;
}

②计算斐波那契数列:

#include <stdio.h>
 
int fibonaci(int i)
{
   if(i == 0)
   {
      return 0;
   }
   if(i == 1)
   {
      return 1;
   }
   return fibonaci(i-1) + fibonaci(i-2);
}
 
int  main()
{
    int i;
    for (i = 0; i < 10; i++)
    {
       printf("%d\t\n", fibonaci(i));
    }
    return 0;
}

23.C语言命令行参数:

编译时可以从外部给main函数传递参数:参数之间用空格隔开,想要传入空格时用双引号转义。

//或者 int main(int agc,char ** argv)
int main(int argc,char *argv[])//agrc缓存传入的参数,argv[0]存储程序名称,
                               //argv[1]存储第一个参数的地址。故argc至少大于1
{

    return 0;

至此:C语言编译器自带的语法已经写完,下一部分写,标准库提供 的函数接口。

二、库文件常用函数说明

1.输入输出头文件:<stdio.h>

C语言与linux一样,把一切设备当文件,因此外设就是一个个的文件指针代替。stdin、stdout、stderr这三个文件指针,在编译时时自动打开。

stdin:键盘指针,表示从键盘读入数据。

stdout:屏幕指针,表示输出到屏幕(输出到标准串口)

stderr:你的屏幕指针,表示输出错误信息到你的屏幕(存在多个telnet连接时)

1.通用输入输出函数:printf--scanf

printf("输出格式化列表",参数);scanf("格式化读入列表",接受缓存地址)

int scanf(const char *format, ...) 函数从标准输入流 stdin 读取输入,并根据提供的 format 来浏览输入。读到空格时停止读入。

int printf(const char *format, ...) 函数把输出写入到标准输出流 stdout ,并根据提供的格式产生输出。

#include <stdio.h>
int main( ) {
 
   char str[100];
   int i;
 
   printf( "Enter a value :");
   scanf("%s %d", str, &i);
 
   printf( "\nYou entered: %s %d ", str, i);
   printf("\n");
   return 0;
}

2.输入输出单个字符: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;
}

3.输入输出字符串: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;
}

2.读写文本文件:<stdio.h>打开、关闭、读文件、写文件

1.打开文件:FILE *fopen( const char *filename, const char *mode );

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

r:只读,w:只写,文件不存在时创建文件,从头开始覆盖写入。a:追加写入,文件不存在时创建

+:补全读写权限,创建和从头开始、追加不变:r+,w+,a+

如果是二进制文件:"rb"、"wb"、"rb+"、"r+b"、"wb+"、"w+b"、“ab+”、“a+b”

2.关闭文件: int fclose( FILE *fp );

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

3.写入单个字符:int fputc( int c, FILE *fp );

函数 fputc() 把参数 c 的字符值写入到 fp 所指向的输出流中。如果写入成功,它会返回写入的字符,如果发生错误,则会返回 EOF

4.写入字符串:int fputs( const char *s, FILE *fp );
函数 fputs() 把字符串 s 写入到 fp 所指向的输出流中。如果写入成功,它会返回一个非负值,如果发生错误,则会返回 EOF

使用 int fprintf(FILE *fp,const char *format, ...) 函数把一个字符串写入到文件中。

注意:请确保您有可用的 tmp 目录,如果不存在该目录,则需要在您的计算机上先创建该目录。

/tmp 一般是 Linux 系统上的临时目录,如果你在 Windows 系统上运行,则需要修改为本地环境中已存在的目录,例如: C:\tmp、D:\tmp等

#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);
}

5.读单个字符:int fgetc( FILE * fp );

fgetc() 函数从 fp 所指向的输入文件中读取一个字符。返回值是读取的字符,如果发生错误则返回 EOF

6.读字符串:char *fgets( char *buf, int n, FILE *fp );

函数 fgets() 从 fp 所指向的输入流中读取 n - 1 个字符。它会把读取的字符串复制到缓冲区 buf,并在最后追加一个 null 字符来终止字符串。

如果这个函数在读取最后一个字符之前就遇到一个换行符 '\n' 或文件的末尾 EOF,则只会返回读取到的字符,包括换行符。

使用 int fscanf(FILE *fp, const char *format, ...) 函数来从文件中读取字符串,但是在遇到第一个空格和换行符时,它会停止读取。

#include <stdio.h>
 
int main()
{
   FILE *fp = NULL;
   char buff[255];
 
   fp = fopen("/tmp/test.txt", "r");
   fscanf(fp, "%s", buff);
   printf("1: %s\n", buff );
 
   fgets(buff, 255, (FILE*)fp);
   printf("2: %s\n", buff );
   
   fgets(buff, 255, (FILE*)fp);
   printf("3: %s\n", buff );
   fclose(fp);
 
}

3.读写二进制文件:<stdio.h>

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);

这两个函数都是用于存储块的读写 - 通常是数组或结构体

4.错误处理: errno.h 

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

errno、perror() 和 strerror()

C 语言提供了 perror() 和 strerror() 函数来显示与 errno 相关的文本消息。

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

让我们来模拟一种错误情况,尝试打开一个不存在的文件。您可以使用多种方式来输出错误消息,在这里我们使用函数来演示用法。另外有一点需要注意,您应该使用 stderr 文件流来输出所有的错误。

#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

5.可变参数:stdarg.h 

需要使用 stdarg.h 头文件,该文件提供了实现可变参数功能的函数和宏。具体步骤如下:

  • 定义一个函数,最后一个参数为省略号,省略号前面可以设置自定义参数。
  • 在函数定义中创建一个 va_list 类型变量,该类型是在 stdarg.h 头文件中定义的。
  • 使用 int 参数和 va_start() 宏来初始化 va_list 变量为一个参数列表。宏 va_start() 是在 stdarg.h 头文件中定义的。
  • 使用 va_arg() 宏和 va_list 变量来访问参数列表中的每个项。
  • 使用宏 va_end() 来清理赋予 va_list 变量的内存。

常用的宏有:

  • va_start(ap, last_arg):初始化可变参数列表。ap 是一个 va_list 类型的变量,last_arg 是最后一个固定参数的名称(也就是可变参数列表之前的参数)。该宏将 ap 指向可变参数列表中的第一个参数。

  • va_arg(ap, type):获取可变参数列表中的下一个参数。ap 是一个 va_list 类型的变量,type 是下一个参数的类型。该宏返回类型为 type 的值,并将 ap 指向下一个参数。

  • va_end(ap):结束可变参数列表的访问。ap 是一个 va_list 类型的变量。该宏将 ap 置为 NULL

  • 现在编写一个带有可变数量参数的函数,并返回它们的平均值:

  • #include <stdio.h>
    #include <stdarg.h>
     
    double average(int num,...)
    {
     
        va_list valist;
        double sum = 0.0;
        int i;
     
        /* 为 num 个参数初始化 valist */
        va_start(valist, num);
     
        /* 访问所有赋给 valist 的参数 */
        for (i = 0; i < num; i++)
        {
           sum += va_arg(valist, int);
        }
        /* 清理为 valist 保留的内存 */
        va_end(valist);
     
        return sum/num;
    }
     
    int main()
    {
       printf("Average of 2, 3, 4, 5 = %f\n", average(4, 2,3,4,5));
       printf("Average of 5, 10, 15 = %f\n", average(3, 5,10,15));
    }

    6.内存管理: <stdlib.h> 

  • 程序员可以对内存进行操作,包括分配、释放、移动和复制等。

1.分配内存:单位字节

void *malloc(int num);在堆区中分配num个未初始化的内存(字节)

void *calloc(int num, int size);在内存中分配num个大小为size的连续内存空间,并初始化为0。(字节)

void *realloc(void *address, int newsize);将原来的内存大小改为nuwsize(字节)

2.释放内存:void free(void *address);

3.复制内存:void *memcpy(void*dest, const void *src, size_t n);

从源地址复制n个字节到dest中,并返回指向dest的指针。

4.移动内存: void *memmove(void *str1, const void *str2, size_t n)

从 str2 复制 n 个字符到 str1,但是在重叠内存块这方面,memmove() 是比 memcpy() 更安全的方法。如果目标区域和源区域有重叠的话,memmove() 能够保证源串在被覆盖之前将重叠区域的字节拷贝到目标区域中,复制后源区域的内容会被更改。如果目标区域与源区域没有重叠,则和 memcpy() 函数功能相同。

三、C89、C95、C99、C11演变过程:

标准库接口编写目的:C标准库的定义是让C编译器开发商之间的C程序能相互移殖, C标准库系统API都是动态链接库(相互各态关系),因此各个编译器都支持这些函数,在使用时只需要包含其头文件即可。常用C语言编译器有GCC、Clang、Intel C++ Complier支持到C11

1.C89的15个头文件

   1. <assert.h>
   2. <ctype.h>
   3. <errno.h>
   4. <float.h>
   5. <limits.h>
   6. <locale.h>
   7. <math.h>
   8. <setjmp.h>
   9. <signal.h>
   10. <stdarg.h>
   11. <stddef.h>
   12. <stdio.h>
   13. <stdlib.h>
   14. <string.h>
   15. <time.h>

2.C95新增头文件:

   1. <iso646.h>
   2. <wchar.h>
   3. <wctype.h>

3.C99新增头文件:

 1. <complex.h>
   2. <fenv.h>
   3. <inttypes.h>
   4. <stdbool.h>
   5. <stdint.h>
   6. <tgmath.h>

  • 27
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。
"C语言字符串处理函数大全-简书"是一篇在简书上的教程,介绍了C语言中常用的字符串处理函数。 该教程详细介绍了C语言中字符串操作的相关函数,包括函数的使用方法和示例代码。通过该教程,读者可以学习到如何使用C语言中的字符串处理函数来进行字符串的复制、连接、比较、查找、截取等操作。 在这篇教程中,读者可以了解到以下一些常见的字符串处理函数: 1. strcpy:用于将一个字符串复制到另一个字符串中。 2. strcat:用于将一个字符串连接到另一个字符串的末尾。 3. strlen:用于计算一个字符串的长度。 4. strcmp:用于比较两个字符串的大小。 5. strchr:用于在一个字符串中查找指定字符的第一次出现位置。 6. strstr:用于在一个字符串中查找指定子串的第一次出现位置。 7. strtok:用于将一个字符串按照指定的分隔符分割成多个子串。 8. strncpy:用于将指定长度的字符串复制到目标字符串中。 9. strncmp:用于比较指定长度的两个字符串。 10. sprintf:用于将格式化的字符串输出到一个字符数组中。 这些函数在C语言中非常常用,并且对于字符串的处理非常方便。通过学习和掌握这些字符串处理函数,可以更加高效地完成C语言程序中的字符串操作。 总之,"C语言字符串处理函数大全-简书"这篇文章提供了丰富的字符串处理函数以及示例代码,对于C语言开发者来说是一个很好的参考和学习资料。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值