C语言学习

为什么要使用C?

  C语言最初是用于系统开发工作,特别是组成操作系统的程序。由于C语言所产生的代码运行速度与汇编语言编写的代码运行速度几乎一样,所以采用C语言作为系统开发语言。下面列举几个使用C语言的实例:

  • 操作系统
  • 语言编辑器
  • 汇编器
  • 文本编辑器
  • 打印机
  • 网络驱动器
  • 现代程序
  • 数据库
  • 语言解释器
  • 实体工具

C 程序结构

C程序主要包括以下部分:

  • 预处理器指令
  • 函数
  • 变量
  • 语句 & 表达式
  • 注释
#include <stdio.h>

int main()
{
      /* 我的第一个 C 程序 */
      printf("Hello ,World! 
");
      
      return 0;
}

接下来我们来讲解一下上面这个程序:

  1. 程序的第一行 #include <stdi0.h> 是预处理器指令,告诉 C 编译器在实际编辑之前要包含 stdio.h 文件
  2. 下一行 int main() 是主函数,程序从这里开始执行。
  3. 下一行 /* ... */ 将会被编辑器忽略,这是放置程序的注释内容,它们被称为程序的注释。
  4. 下一行 printf(...) 是 C 中另一个可用函数,会在屏幕上显示消息 “Hello,World !”。
  5. 下一行 return 0; 终止main()函数,并返回值0。

编译 & 执行 C 程序

接下来让我们看看如何把源代码保存在一个文件中,以及如何编译并运行它。

  1. 打开一个文本编辑器,添加上述代码。
  2. 保存文件为 hello.c
  3. 打开命令提示符,进入保存文件所在的目录。
  4. 键入 gcc hello.c ,回车,编译代码。
  5. 如果代码中没有错误,命令提示符会跳掉下一行,并生成a.out 可执行文件。
  6. 现在,键入 a.out 来执行程序。
  7. 屏幕显示 “Hello,World!”。
$ gcc hello.c
$ ./a.out
Hello, World!

C 语言基本语法

C 的令牌(Tokens)

C 程序由各种令牌组成,令牌可以是关键字、标识符、常量、字符串值,或者是一个符号。

例如,下面的 C 语句包括5个令牌

printf("Hello, World ! 
");

printf 
(
"Hello, World! 
"
)
;

分号:

在 C 程序中,分号是语句结束符。也就是说,每个语句必须以分号结束。它表明一个逻辑实体的结束。

注释:

C 语言有两种注释方式:

// 单行注释

/* 单行注释 */
/*
    多行注释
    ...
*/

标识符:

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

关键字:

下表列出了 C 语言中的保留字。这些保留字不能作为常量名、变量名或其他标识符名称。

关键字        说明
auto           声明自动变量
break         跳出当前循环
case           开关语句分支
char           声明字符型变量或函数返回值类型
const          声明只读变量
continue     结束当前循环,开始下一轮循环
default       开关语句中的“其它”分支
do              循环语句的循环体
double        声明双精度浮点型变量或函数返回值类型
else            条件语句否定分支(与 if 连用)
enum          声明枚举类型
float            声明浮点型变量或函数返回值类型
for              一种循环语句
goto            无条件跳转语句
if                条件语句
int              声明整形变量或函数
long            声明长整型变量会函数返回值类型
register       声明寄存器变量
return         子程序返回语句(可以带参数,也可以不带参数)
short           声明短整型变量或函数
signed         声明有符号类型变量或函数
sizeof          计算数据类型或变量长度(即所占字节)
static           声明静态变量
struct           声明结构体类型
switch          用于开关语句
typedef        用以给数据类型去别名
unsigned      声明无符号类型变量或函数
union           声明共用体类型
void             声明函数无返回值或无参数,声明无类型指针
volatile         声明变量在程序执行中科院被隐含的改变
while            循环语句的循环条件

C 数据结构

在 C 语言中,数据类型值的数用于声明不同类型的变量或函数的一个广泛的系统。变量的类型决定了变量存储占用的空间,以及如何解释存储的位模式。

C 中的类型可以分为以下几种:

  1. 基本类型:它们是算术类型,包括两种类型,整数类型和浮点类型。
  2. 枚举类型:它们也是算术类型,被用来定义在程序中只能赋于其一定的离散整数值的变量。
  3. void类型:类型说明符 void 声明没有可用的值。
  4. 派生类型:它们包括,指针类型,数组类型,结构类型,共用体类型和函数类型。

数组类型和结构体类型统称为聚合类型。函数的类型指的是函数的返回值的类型。

整数类型


类型             存储大小          值范围
char             1 字节           -128到127 或 0 到255
unsigned char    1 字节           0 到 255
signed char    1 字节        -128 到 127
int         2 或 4 字节   -32768 到 32767 或 -2147483648 到 2147483647
unsigned int    2 或 4 字节   0 到 65535 或 0 到 4294967295
short       2 字节         -32768 到 32767
unsigned short   2 字节       0 到 65535
long        4 字节        -2147483648 到 2147483647
unsigned long 4 字节      0 到 4294967295

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

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

# include <stdio.h>
# include <limits.h>

int main()
{
    printf(" int 存储大小 : %lu 
", sizeof(int));

    return 0;
}

浮点类型

类型      存储大小    值范围            精度
float     4 字节     1.2E-38 到 3.4E+38 6位小数
double   8 字节     2.3E-308 到 1.7E+308 15位小数
long double  16 字节    3.4E-4932 到 1.1E+4932 19位小数

头文件 float.h 定义了宏,在程序中可以使用这些值和其他有关实数二进制表示的细节。

# include <stdio.h>
# include <float.h>

int main()
{
    printf("float 存储最大字节数 : %lu 
", sizeof(float));
    printf("float 最小值 : %E 
", FLT_MIN);
    printf("float 最大值 : %E 
", FLT_MAX);
    printf("float 精度值 : %d 
", FLT_DIG);
    
    return 0;
}

void 类型

void 类型指定没有可用的值。它通常用于以下三种情况:

  1. 函数返回为空:C 中有各种函数都不返回值,或者我们理解返回空。不返回值的函数返回类型为空。例如 void exit(int status);
  2. 函数参数为空:C 中有各种函数不接受任何参数。不带参数的函数可用接受一个void。例如 int rand(void);
  3. 指针指向 void:类型为 void * 的指针代表对象的地址,而不是类型。例如:内存分配函数 void *malloc(size_t size); 返回指向 void 的指针,可以转换为任何数据类型。

C  中的变量

变量声明和定义:

变量声明向编译器保证变量以指定的类型和名称存在,这样编译器在不需要知道变量完整细节的情况下也能继续进一步的编译。变量声明只在编译时有它的意义,在程序连接时编译器需要实际的变量声明。

变量的声明有两种情况:

  1. 一种是需要建立存储空间的。例如:int a 在声明的时候就已经建立了存储空间。
  2. 另一种是不需要建立空间的,通过使用 extern 关键字声明变量名而不定义它。例如:extern int a 其中变量 a 可以在别的文件中定义的。

  除非有 extern 关键字,否则都是变量的定义。

extern int i; // 声明,不是定义
int j; // 声明,也是定义
#include <stdio.h>
 
// 变量声明
extern int a, b;
extern int c;
extern float f;
 
int main ()
{
  /* 变量定义 */
  int a, b;
  int c;
  float f;
 
  /* 初始化 */
  a = 10;
  b = 20;
  
  c = a + b;
  printf("value of c : %d 
", c);
 
  f = 70.0/3.0;
  printf("value of f : %f 
", f);
 
  return 0;
}

C 常量

  整数常量、浮点常量、字符常量、字符串常量

定义常量

  1. 使用 #define 预处理器。
  2. 使用 const 关键字。    

#define 实例

#include <stdio.h>

#define LENGTH 10
#define WIDTH 5
#define NEWLINE '
'

int main()
{
    int area;

    area = LENGTH * WIDTH;
    printf("value of area : %d", area);
    printf("%c", NEWLINE); 

    return 0;   
}

const 实例

#include <stdio.h>

int main()
{
    const int LENGTH = 10;
    const int WIDTH = 5;
    const char NEWLINE = '
';
    int area;

    area = LENGTH * WIDTH;
    printf("value of area : %d", area);
    printf("%c", NEWLINE);

    return 0;
}

C 存储类

在存储定义 C 程序中变量/函数的范围(可见性)和生命周期。这些 说明符放置在他们所修饰的类型之前。下面列出 C 程序中可用的存储类:

  • auto
  • register
  • static
  • extern 

auto 存储类

auto 存储类是所有局部变量默认的存储类。

{
    int mount;
    auto int month;
}

上面的实例定义了两个带有相同存储类的变量,auto 只能用在 函数内,即 auto 只能修饰局部变量。

register 存储类

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

{
    register int miles;
}

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

static 存储类

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

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

static 是全局变量的默认存储类,以下两个变量 (count 和 road)都是一个 static 存储类。

static int Count;
int Road;

main()
{
    printf(" %d 
", Count);
    printf(" %d 
", Road);
}

实例:static 修饰全局变量和局部变量的应用

#include <stdio.h>

/* 函数声明 */
void func1(void);

static int count = 10;  /* 全局变量 - static 是默认的 */

int main()
{
    while (count--) {
        func1();
    }
    return 0;
}


void func1(void)
{
/* 'thingy' 是 ‘func1’ 的局部变量,只初始化一次
 * 每次调用函数 'func1' 'thingy' 值不会被重置
 */
    static int thingy = 5;
    thingy++;
    printf(" thingy 为 %d, count 为 %d 
", thingy, count);
}

实例中 count 作为全局变量可以在函数内使用,thingy 使用 static 修饰后,不会再次调用时重置。

extern 存储类

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

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

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

文件 : main.c

#include <stdio.h>

int count;
extern void write_extern();

int main()
{
    count = 5;
    write_extern();
}

文件:support.c

#include <stdio.h>

extern int count;

void write_extern(void)
{
    printf(" count is %d 
", count)
}

 C 运算符

运算符是一种告诉编译器执行特定的数学或逻辑操作的符号。C语言内置了丰富的运算符,并提供了以下类型的运算符:

  • 算术运算符
  • 关系运算符
  • 逻辑运算符
  • 位运算符
  • 赋值运算符
  • 杂项运算符

算术运算符

+  -  *  /  %  ++  --
a++ 先赋值后运算
++a 先运算后赋值

关系运算符

==  !=  >  <  >=  <=

逻辑运算符

&&  ||  !

位运算符 

p        q        p&q          p|q          p^q
0            0            0                0                0
0            1            0                1                1
1            1            1                1                0
1            0            0                1                1

假如 A = 60, B = 13,现在以二进制格式表示
A = 0011 1100
B = 0000 1101
----------------
A&B = 0000 1100
A|B = 0011 1101
A^B = 0011 0001
~A  = 1100 0011
----------------
&  --> 0&0=0  0&1=0  1&0=0  1&1=1
|  --> 0|0=0  0|1=1  1|0=1  1|1=1
^  --> 0^0=0  0^1=1  1^0=1  1^1=1
~  --> ~1=0   ~0=1
<< --> A << 2 = 1111 0000 
>> --> A >> 2 = 0000 1111

赋值运算符

=  +=  -=  /=  %=  <<=  >>=  &=  ^=  |=  

杂项运算符sizeof & 三元

sizeof() //  返回变量的大小

&  // 返回变量的地址  &a --> 将给出变量a的实际地址

*  // 指向一个变量,*a --> 将指向一个变量

?:  // 条件表达式, 如果条件为真?则值为X,否则值为Y
#include <stdio.h>

int main()
{
    int a = 4;
    short b;
    double c;
    int* ptr;

    /* sizeof 运算符实例 */
   printf("Line 1 - 变量 a 的大小 = %lu 
 ", sizeof(a));

    /* & 和 * 运算符实例 */
    ptr = &a;  // 'ptr' 现在包含 ‘a’ 的地址
    printf("a 的值是 %d 
", a);
    printf("*ptr 是 %d 
", *ptr);

    /* 三元运算符实例 */
    b = 10;
    b = (a == 1) ? 20: 30;
    printf("b 的值是 %d 
", b);
    
    b = (b == 10) ? 20: 30;
    printf("b 的值是 %d 
", b);
} 

C 判断

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

判断语句

if    if ... else    嵌套if    switch    嵌套switch

? : 运算符(三元运算符)

Exp1 ? Exp2 : Exp3;

  

#include <stdio.h>

int main()
{
    int num;

    printf("输入一个数字 : ");
    scanf("%d", &num);

    (num % 2 == 0) ? printf("偶数") : printf("奇数");
}

C 循环

循环类型

while    for    do...while 

循环控制语句

break    continue    goto

C 函数

定义函数

在 C 语言中,函数由一个函数头和一个函数主体组成。

  • 返回类型:一个函数可以返回一个值。
  • 函数名称:这是函数的实际名称。函数名和参数列表一起构成函数签名。
  • 参数:参数就像是占位符。当函数被调用时,我们可以向参数传递一个值,这个值被称为实际参数。参数列表包括函数参数的类型,顺序数量。参数是可选的,也就是说,函数可能不包含参数。
  • 函数主体:函数主体包含一组定义函数执行任务的语句。
/* 函数返回两个数中较大的那个 */

int max(int num1, int num2)
{
    // 局部变量声明
    int result;
  
    if (num1 > num2)
        result = num1;
    else
        result = num2;

    return result;
}

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

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

数据类型        初始化默认值
int              0
char             ''
float            0
double           0
pointer          null

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

C 数组

C 语言支持数组数据结构,它可以存储一个固定大小的相同类型元素的顺序集合。数组是用来存储一系列数据,但它往往被认为是一系列相同类型的变量。

数组的声明并不是声明一个个单独的变量,比如number0,number1,....,number99,而是声明一个数组变量,比如 numbers ,然后使用 numbers[0]、numbers[1]、...、numbers[99] 来代表一个个单独的变量。数组中的特定元素可以通过索引访问。

声明数组

在 C 中要声明一个数组,需要指定元素的类型和元素的数量。

type arrayName [ arraySize ];

这个叫做一维数组,arraySize必须是一个大于零的整数常量,type 可以是任意有效的 C 数据类型。例如 要声明一个类型为 double 的包含 10 个元素的数组 balance,声明语句如下:

double balance[10];

初始化数组

在 C 中,可以逐个初始化数组,也可以使用一个初始化 语句,如下:

double balance[5] = {12.0, 123.0, 32.0, 31.0, 65.0};
balance[4] = 50.0;
#include <stdio.h>

int main()
{
    int n[10]; /* n 是一个包含 10 个整数的数组 */
    int i, j;

    /* 初始化数组元素 */
    for (i = 0; i < 0; i++)
    {
        n[i] = i + 100; /* 设置元素 i 为 i + 100 */
    }

    /* 输出数组中每个元素的值 */
    for (j = 0; j < 10; i++)
    {
        printf("Element[%d] = %d 
", j, n[j]);
    }
    return 0;
}

C enum(枚举)

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

枚举语法定义格式:

enum 枚举名 {枚举元素1, 枚举元素2,... }

接下来我们举个例子,比如:一个星期有7天,如果不用枚举,我们需要使用#define 来为每个整数定义一个别名:

#define MON 1
#define TUE 2
#define WED 3
#define THU 4
#define FRI 5
#define SAT 6
#define SUN 7

这个看起来代码量就比较多,接下来我们看看使用枚举的方式:

 enum DAY
{
 MON = 1, TUE, WED, THU, FRI, SAT, SUM
}

这样看起来是不是更加简洁了。

注意:第一个枚举成员默认为整数的0,后续枚举成员的值在前一个成员上加1。我们在这个实例中把第一个枚举成员的值定义为1, 第二个就为2,以此类推。

也可以在定义枚举类型时改变枚举元素的值:

enum season {spring, summer=3, autumn, winter }

这里没有指定值的枚举元素,其值为前一元素加1,。也就是说 spring 的值为0,summer 的值为3,autumn 的值为4,winter 的值为5.

 枚举变量的定义

前面我们只是声明了枚举类型,接下来我们看看如何定义枚举变量

1、先定义枚举类型,再定义枚举变量

enum DAY
{
    MON=1,, TUE, WED, THU, FRI, SAT, SUN
};

enum DAY day;

2、定义枚举类型的同时定义枚举变量

enum DAY
{
    MON=1, TUE, WED, THU, FRI, SAT, SUN
} day;

3、省略枚举每次,直接定义枚举变量

enum
{
    MON=1, TUE, WED, THU, FRI, SAT, SUM  
} day;

 实例:

#include <stdio.h>

enum DAY
{
    MON=1, TUE, WED, THU, FRI, SAT, SUM
};

int main()
{
    enum DAY day;
    day = WED;
    printf("%d", day);
    return 0;
}

 以上实例输出结果为:3

#include <stdio.h>

enum DAY
{
    MON=1, TUE, WED, THU, FRI, SAT, SUM
} day;

int main()
{
    // 遍历枚举元素
    for (day=MON; day <= SUN; day++) {
        printf("枚举元素:%d 
", day);
    }
}

输出实例:

枚举元素:1
枚举元素:2
枚举元素:3
枚举元素:4
枚举元素:5
枚举元素:6
枚举元素:7

枚举在 switch 中使用

#include <stdio.h>
#include <stdlib.h>

int main()
{
    enum color {red=1, green, blue };
    
    enum color favorite_color;

    /* 选择颜色 */
    printf("请输入你喜欢额颜色:(1.red、2.green、3.blue):");
    scanf("%d", &favorite_color);

    /* 输出结果 */
    switch (favortie_color)
    {
    case red:
            printf("你喜欢的颜色是红色~");
            break;
    case green:
            printf("你喜欢的颜色是绿色~");
            break;
    case blue:
            printf("你喜欢的颜色是蓝色~");
            break;
    default:
            printf("你没有选择你喜欢的颜色");
    }
    return 0;
}    

将整数转换为枚举

#include <stdio.h>
#include <stdlib.h>

int main()
{
    enum day
    {
        saturday,
        sunday,
        monday,
        tuesday,
        wednesday,
        thursday,
        friday
    } workday;
    
    int a = 1;
    enum day weekend;
    weekend = ( enum day ) a; // 类型转换
    /* weekedn = a; 错误 */
    printf("weekedn:%d", weekend);
    return 0;
}
 
原文地址:https://www.cnblogs.com/xushuhai/p/9465376.html