总结

C语言基础回顾

C语言历史与计算机结构

1972年贝尔实验室 Dennis Ritchie 和 Ken Thompson 在开发 UNIX 时设计 C 语言。

C语言在 B 语言(汤普逊发明)的基础上进行设计。

由于 C 语言与 UNIX 关系密切,UNIX 系统通常会将 C 编译器作为软件包的一部分。安装 Linux 时,通常也会安装 C 编译器。

功能强大且灵活的 UNIX 操作系统,大部分是用 C 语言写的。

很多其它的语言(如 FORTRAN、Perl、Python、Pascal、LISP、Logo、BASIC)的许多编译器和解释器都是用 C 语言编写的。也就是用 C 开发的工具去把这些语言的源码转换为计算机可以执行的程序。

另外,大多数 C 实现都有一个大型的库,包含众多有用的 C 函数。这些函数用于处理程序员经常需要解决的问题。

先了解计算机的结构:

  1. 中央处理单元(CPU)承担绝大部分的运算工作
  2. 随机存取内存(RAM)是存储程序和文件的工作区
  3. 永久内存存储设备(过去一般指机械硬盘,现在还包括固态硬盘)即使在关闭计算机后,也不会丢失之前储存的程序和文件
  4. 外围设备(如键盘、鼠标、触摸屏、监视器)提供人与计算机之间的交互

CPU 的工作是核心,其实它的工作也是很简单枯燥:它就是从内存中读取一条条的指令,执行一条指令再到下一条指令,指令执行的时候,可能需要用到一些数据。

CPU 就是这样不断在执行这些指令。只不过是它的执行速度非常快。每秒钟可以达到十几亿次。以后还会更快。

就是因为它快,所以我们的计算机可以同时多个软件在运行。

CPU 由若干个寄存器组成,每个寄存器都可以储存一个数字。这些数字有可能代表一个数据,比如 12、2、3 这些,也可能表示一条指令,比如 mov 移动等。

CPU 能理解的指令有限(这些指令的集合叫作指令集)。而且,这些指令相当具体,其中的许多指令都是用于请求计算机把一个数字从一个位置移动到另一个位置。例如,从内存移动到寄存器。

比如下面要求两个数的和:

  1. 从内存位置 2000 上把一个数字拷贝到寄存器 A。
  2. 从内存位置 2004 上把另一个数字拷贝到寄存器 B。
  3. 把寄存器 B 中的内容与寄存器 A 中的内容相加,把结果储存在寄存器 A 中。
  4. 把寄存器 A 中的内容拷贝到内存位置 2008。
mov 2000 A
mov 2004 B
add B A
mov A 2008

上面的指令就完成了两个数的和,具体就是 2000 内存中的数和 2004 内存中的数的和。

机器语言、汇编语言、高级语言

高级语言的目的就是抽象和简化低级语言,使得程序员可以使用更接近人类思维的语言来要求计算机做事情。

例如我们之前要求两个数的和,汇编语言可能是这样子(如下代码只是例子,不是正确的代码):

mov 2000 A
mov 2004 B
add B A
mov A 2008

如果是机器语言,比如以前的卡片机。bug 为什么叫 bug?

现在高级语言就简单了:

int a = 1;
int b = 2;
int c = a + b;

对于我们人来说看上面的高级语言可能非常好理解,但是对于计算机来说那就是一堆无法理解的无用数据。

编译器在这里派上了用场。编译器是把高级语言程序翻译成计算机能理解的机器语言指令集的程序。

程序员进行高级思维活动,而编译器则负责处理冗长乏味的细节工作。

编译器还有一个优势:它可以把同一份代码,转换为不同的 CPU 的机器语言。因为不同的 CPU 它们的架构是不一样的,指令也就不一样。比如对于 Intel 的 CPU 可能 0111110 是加,而对于 ARM 的 CPU 可能 01101010 是加。

因此,使用合适的编译器或编译器集,便可把一种高级语言程序转换成供各种不同类型 CPU 使用的机器语言程序。一旦解决了一个编程问题,便可让编译器集翻译成不同 CPU 使用的机器语言。

简而言之,高级语言(如 C、Java、Pascal)以更抽象的方式描述行为,不受限于特定 CPU 或指令集。而且,高级语言简单易学,用高级语言编程比用机器语言编程容易得多。

程序开发过程

最早的编译器

我们如果要开发一个程序,那么要经过那些过程呢?

  1. 程序的作用和目的是什么?想要程序去做什么首先自己要明确自己想做什么,思考你的程序需要哪些信息,要进行哪些计算和控制,以及程序应该要报告什么信息,也就是程序是做什么的。要用户提供什么,最后给什么结果用户。
  2. 设计程序,给程序设计,要什么数据,提供什么,那个地方放什么,比如按钮、图片等等,还有程序分多少个模块等等这些。
  3. 编写代码。代码是一串文本,我们可以使用一些工具来编写。
#include <stdio.h>

int main(void)
{
    int dogs;
    printf("How many dogs do you have?\n");
    scanf("%d", &dogs);
    printf("So you have %d dog(s)!\n", dogs);
    return 0;
}Code language: PHP (php)

C 是最广泛使用的计算机编程语言之一。C 之所以如此受欢迎是因为它可靠、简单且易于使用。这就是为什么尽管出现了许多新语言的事实,但 C 仍然是使用最广泛的语言。

C的特点
  • 快
  • 简单易学
  • 最强大的编程语言
  • 具有许多内置功能和运算符,可简化复杂程序
  • 可以在多种计算机平台上进行编译
  • 快速高效
  • 用 C 编写的程序是可移植的,即,为一种类型的计算机或操作系统编写的程序可以在最小的修改下就可以在另一种类型的计算机或操作系统上运行
  • 也广泛用于许多大型项目
如何开始?

在整个 C 教程中,我们将学习编写 C 程序。但是之后呢?

编写完任何程序后,我们需要编译并运行它以查看程序的输出。

那么,编译是什么意思?

当我们用 C 语言编写程序时,需要将其转换为机器语言(由 0 和 1 组成的二进制语言),以便计算机能够理解并执行它。这种转换称为编译程序。我们借助编译器来编译代码。

集成开发环境(IDE)

为了编写和编译我们的 C 程序,我们提供了许多 IDE。

IDE 由文本编辑器和编译器组成。我们在文本编辑器中键入程序,然后由编译器进行编译。

文本编辑器:我们在文本编辑器中编写程序。包含我们程序的文件称为源文件,并以 .c 扩展名保存。

C 编译器:将程序保存在扩展名为 .c 的文件中后,我们需要对其进行编译。如我们所见,我们需要编译代码以将其转换为计算机可以理解的机器语言。

现在让我们看看如何在不同的操作系统上编译和执行 C 程序。

在 Windows 上编写和编译 C 程序​

尽管有很多 IDE 可以用于 Windows 的 C 程序的编辑和编译,但在这里我们讨论的是使用 DevC++ 进行编辑和编译的程序,它允许我们编辑、编译和运行程序。我们可以使用 DevC++ 本身编写和保存程序,然后使用该程序进行编译。

在学习用 DevC++ 编写程序之前,请首先确保已将其安装在计算机中。如果没有,请下载并安装它。

要在 DevC++ 中编写和编译,请按照以下步骤操作:

  1. 打开 DevC++ 时,您将看到一个窗口。单击”源文件”选项。
  2. 如下所示,在空白处编写 C 程序并保存。
#include <stdio.h>
int main()
{
    printf("Hello World\n");
    return 0;
}Code language: PHP (php)
  1. 编写程序后,单击”编译并运行”。
  2. 将出现一个输出窗口,显示打印为”Hello World”的结果。

在 Linux 上编写和编译 C 程序​

对于 Linux,您可以使用各种文本编辑器(如 vim、gedit 或 Emacs)编写 C 程序。假设文本编辑器是 gedit,以下步骤显示了如何编辑和编译 C 程序。

  1. 打开终端(ctrl+alt+T)。
  2. 在您喜欢的编辑器中打开一个扩展名为 .c 的新文件(在我们的情况下文件名为 hello.c)。命令是:gedit hello.c
  3. 文本编辑器窗口将打开。在下面键入下面的 C 程序并保存。
#include <stdio.h>
int main()
{
    printf("Hello World\n");
    return 0;
}Code language: PHP (php)
  1. 要编译程序,请键入 cc -c hello.c,然后按 Enter。
  2. 现在键入 cc hello.c -o hello 并按 Enter。这将创建名称为 hello 的可执行文件。
  3. 要运行程序,请键入 ./hello,然后按 Enter。这将显示程序的输出。

第一个C程序解析

现在让我们从停下来的”Hello World”代码开始。

#include <stdio.h>
int main()
{
    printf("Hello World\n");
    return 0;
}Code language: PHP (php)

编译以上代码后,”Hello World”将显示在屏幕上。

printf("Hello World\n"); → printf 是一个函数,它在屏幕上显示括号内的内容。

我们使用了单词函数,所以让我们讨论一下它是什么。函数就像一个机器,需要从我们这里得到东西(不一定),然后执行操作。简而言之,函数从用户那里获取输入,然后返回输出。

在上面的示例中,printf 以”Hello World\n”作为输入,并在屏幕上显示”Hello World”,但不带有”\n”。因此,让我们讨论一下它是什么。

\n 是称为换行符的特殊字符,用于更改行或打印新行。因此,’Hello World’之后的’\n’更改了行或打印了新行。

#include <stdio.h>
int main()
{
    printf("Hello\n World\n");
    return 0;
}Code language: PHP (php)

如您所见,”\n”在”Hello”和”World”之间打印了新行。因此,”\n”用于在程序中打印新行。

最后尝试编写不带’\n’的相同代码,您将看到光标不会更改行,并且将开始在同一行上打印所有内容。

;(分号)告诉编译器语句结束。我们需要输入”;”在每个语句的末尾,例如函数调用、变量声明等。

因此,通过输入”;”在末尾 printf("Hello World\n");,我们已经在此处结束了该声明。此后写的所有内容将是新的声明。

#include <stdio.h>
int main()
{
    printf("Hello World\n"); return 0;
}Code language: PHP (php)

int main() → main 也是一个函数。它是在执行 C 代码时首先编译的,也就是说,任何 C 程序的执行都从该 main() 函数开始。int 在 main 之前表示该函数将返回(或返回给我们)一个整数。

由于每个 C 程序的执行均从该 main 功能开始,因此所有 C 程序都必须具有此 main() 功能。

{ }(大括号)在刚过 main() 功能包围该功能的主体。这意味着它表示”主体”内部的事物。

return 0 → 如前所述,该 main 函数返回一个整数值(int main()),因此此处返回 0。return 是一个关键字,用于从函数返回一些值。返回 0 表示我们的程序已成功运行,并且我们使用此 return 语句终止 main 函数。

#include <stdio.h> → stdio.h 代表标准输入输出。它是 C 语言的一个库,其中包含函数的定义,例如 printf。因此,它将告诉编译器”printf”应如何工作。#include 是一个预处理器,用于将程序与 stdio.h 链接。

注释

注释是在代码内部编写的语句,在编译我们的代码时,编译器只会忽略它们。编写注释以使我们的代码对人类更具可读性。

注释介于 /* ... */ 或 // 之间。

为什么要注释:如前所述,它使我们的代码更具可读性。假设您已经编写了一个软件,并在发布它之后,雇用了一些优秀的程序员来进行软件维护。没有注释,对他们来说,理解您的代码将是非常困难的工作。

//This is single line comment
//This is also a comment
#include <stdio.h>
int main()
{
    printf("Hello World\n");
    return 0;
}Code language: PHP (php)
/*Hello World code*/
/* Comments will not be compiled and will be ignored */
/* It is a
multiline
comment*/
#include <stdio.h>
int main()
{
    //printf function
    printf("Hello World\n");
    return 0;
}Code language: PHP (php)

接受用户输入

#include <stdio.h>
int main()
{
    int a;
    printf("Enter an integer");
    scanf("%d", &a);
    printf("Entered value is : %d\n", a);
    return 0;
}Code language: PHP (php)

int a; → 这是一条声明变量”a”是整数的语句。通过此声明,”a”进入了我们程序的世界。

scanf 是另一个功能,用于从键盘取值。%d 用于 C 中的整数,在这里,它表示 scanf 将从键盘获取整数值。&a → 表示在’a’的地址上。

#include <stdio.h>
int main()
{
    int x;
    int y;
    printf("Enter two integers\n");
    scanf("%d %d", &x, &y);
    int z = x + y;
    printf("Entered value is : %d and %d and their sum is %d\n", x, y, z);
    return 0;
}Code language: PHP (php)

数据类型与变量

在程序中使用变量之前,需要对其进行声明。数据类型用于为变量分配类型。

#include <stdio.h>
int main()
{
    int x;
    x = 10;
    return 0;
}Code language: PHP (php)

%d 用于 int,%c 用于 char,%f 用于 float。

#include <stdio.h>
int main()
{
    float a;
    int b;
    char ch;

    printf("\nEnter value of float\n");
    scanf("%f", &a);

    printf("\nEnter value of int\n");
    scanf("%d", &b);

    printf("\nEnter value of char\n");
    scanf(" %c", &ch);

    printf("\nValue of float : %f", a);
    printf("\nValue of int : %d", b);
    printf("\nValue of char : %c", ch);
    printf("\nValue of float(rounded) : %.2f\n", a);

    return 0;
}Code language: PHP (php)

%.2f 表示要打印的变量将为 float 类型,而’.2’表示将仅舍入到小数点后两位的数字。

有符号和无符号:有符号和无符号变量告诉我们它是否可以采取正值、负值或同时采取这两种方法。signed 关键字用于那些可以取正值也可以取负值的变量。unsigned 关键字用于那些只能接受零或正值的变量。

unsigned int x;
类型大小取值范围
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
char1个字节-128至127或0至255
signed char1个字节-128至127
unsigned char1个字节0至255

在 printf 中,%d 用于有符号整数,而 %u 用于无符号整数。

如何存储字符值:只要将字符值赋予 char 类型的变量,就会存储其 ASCII 值。

#include <stdio.h>
int main()
{
    char ch;
    printf("\nEnter value of char\n");
    scanf("%c", &ch);
    printf("\nCharacter value of character = %c", ch);
    printf("\nASCII value = %d\n", ch);
    return 0;
}Code language: PHP (php)

类型转换:类型转换是变量从一种数据类型到另一种数据类型的转换。

隐式转换:假设我们在 C 中添加一个整数和一个字符,例如 2 + 'a'。这是 C 语言中的有效表达式,因为 C 语言会自动将字符值”a”转换为整数(ASCII 值),然后将它们加起来。

#include <stdio.h>
int main()
{
    int a = 12;
    char ch = 'h';
    int sum = a + ch;
    printf("Sum = %d\n", sum);
    return 0;
}Code language: PHP (php)

显式转换:我们还可以手动将值从一种数据类型转换为另一种数据类型,如下所示:(数据类型)值;

#include <stdio.h>
int main()
{
    float x = 2.45;
    printf("%d\n", (int)x);
    return 0;
}Code language: PHP (php)

运算符

运算符是告诉编译器对变量执行某些操作的符号。

算术运算符
运算符描述例
+添加操作数a + b
–从第一个减去第二个操作数a – b
*将两个操作数相乘a * b
/用分子除以分母a / b
%模运算符,在整数除法后返回余数a % b
#include <stdio.h>
int main()
{
    int a = 25;
    int b = 8;
    printf("sum = %d", (a+b));
    printf("\ndifference = %d", (a-b));
    printf("\nproduct = %d", (a*b));
    printf("\nremainder = %d\n", (a%b));
    return 0;
}Code language: PHP (php)

如果我们将两个整数相除,则结果将是一个整数。5/2 = 2(不是 2.5)。要获得 2.5,分子或分母中的至少一个必须具有十进制(浮点)值。

运算符优先级:首先对方括号'()’中的表达式求值。之后遵循优先级表。

优先级类别运算符关联性
1乘除取模* / %左到右
2加减+ –左到右
3赋值=右到左
关系运算符
运算符描述例
==等于(a == b)
!=不等于(a != b)
>比…更大(a > b)
<少于(a < b)
>=大于或等于(a >= b)
<=小于或等于(a <= b)
#include <stdio.h>
int main()
{
    int a = 5, b = 6;
    printf("\n%d", a == b);
    printf("\n%d", a != b);
    printf("\n%d", a > b);
    printf("\n%d", a < b);
    printf("\n%d", a >= b);
    printf("\n%d", a <= b);
    return 0;
}Code language: PHP (php)

= 和 == 之间的差异:= 是赋值运算符,而 == 是相等运算符。

逻辑运算符
运算符描述例
&&逻辑与(a == b) && (a == 8)
||逻辑或(a != b) || (a == 5)
!逻辑非!(a == 5)
#include <stdio.h>
int main()
{
    int a = 5, b = 0;
    printf("\n%d", a && b);
    printf("\n%d", a || b);
    printf("\n%d", !a);
    printf("\n%d", !b);
    return 0;
}Code language: PHP (php)
赋值运算符
运算符描述例
=将右操作数的值分配给左操作数C = A + B
+=将右操作数的值添加到左操作数C += A
-=将右操作数的值减去左操作数C -= A
*=将右操作数的值与左操作数相乘C *= A
/=将左操作数的值与右操作数相除C /= A
%=使用两个操作数取模C %= A
#include <stdio.h>
int main()
{
    int a = 25;
    int b = 8;
    a += b;
    printf("%d\n", a);
    a -= b;
    printf("%d\n", a);
    a *= b;
    printf("%d\n", a);
    a /= b;
    printf("%d\n", a);
    a %= b;
    printf("%d\n", a);
    return 0;
}Code language: PHP (php)
增减运算符

++ 和 -- 分别称为增量和减量运算符。a++ 将变量’a’的值增加 1,而 a-- 将 a 的值减小 1。

前缀和后缀之间的区别:a++ 在’a’的值递增之前返回’a’的值,而 ++a 首先将’a’的值增加 1,然后返回递增值”a”。

#include <stdio.h>
int main()
{
    int a = 15, b = 15, c = 15, d = 15;
    printf("\nvalue of a++ = %d", a++);
    printf("\nvalue of ++b = %d", ++b);
    printf("\nvalue of c-- = %d", c--);
    printf("\nvalue of --d = %d", --d);
    return 0;
}Code language: PHP (php)
sizeof 运算符

sizeof() 运算符用于返回变量的大小。

#include <stdio.h>
int main()
{
    int i = 6;
    int j;
    char c;
    float f;
    double d;
    printf("size of integer variable i = %d", sizeof(i));
    printf("\nsize of integer variable j = %d", sizeof(j));
    printf("\nsize of character variable = %d", sizeof(c));
    printf("\nsize of float variable = %d", sizeof(f));
    printf("\nsize of double variable = %d", sizeof(d));
    return 0;
}Code language: PHP (php)

决策与条件

很多时候,我们需要先查看条件,然后做出决定。这种决策方式是通过在 C 中使用 if 语句完成的。

if 语句
#include <stdio.h>
int main()
{
    int a = 5;
    int b = 5;
    if (a == b)
    {
        printf("a and b are equal\n");
    }
    return 0;
}Code language: PHP (php)
if…else 语句
#include <stdio.h>
int main()
{
    int a = 5;
    int b = 8;
    if (a == b)
    {
        printf("a and b are equal\n");
    }
    else
    {
        printf("a and b are not equal\n");
    }
    return 0;
}Code language: PHP (php)
else if 语句
#include <stdio.h>
int main()
{
    int a = 10;
    if(a == 30)
    {
        printf("It is 30\n");
    }
    else if(a == 10)
    {
        printf("It is 10\n");
    }
    else if(a == 5)
    {
        printf("It is 5\n");
    }
    return 0;
}Code language: PHP (php)

如果有一条语句在 if、else 或者 else if 里面,我们可以跳过括号({})。

if/else 嵌套
#include <stdio.h>
int main()
{
    int a = 8;
    int b = 4;
    int c = 10;
    if (a > b)
    {
        if (a > c)
        {
            printf("a is the greatest number.\n");
        }
    }
    return 0;
}Code language: PHP (php)
三元运算符

条件 ? expression1 : expression2 ;

#include <stdio.h>
int main()
{
    int age;
    printf("Enter age");
    scanf("%d", &age);
    (age > 18) ? printf("eligible to vote\n") : printf("not eligible to vote\n");
    return 0;
}Code language: PHP (php)

循环

while 循环
#include <stdio.h>
int main()
{
    int a = 1;
    while (a <= 10)
    {
        printf("Hello World\n");
        a++;
    }
    return 0;
}Code language: PHP (php)
for 循环
for (初始化; 条件; 改变)
{
    语句
}
#include <stdio.h>
int main()
{
    int a;
    for (a = 1; a <= 10; a++)
    {
        printf("Hello World\n");
    }
    return 0;
}Code language: PHP (php)
嵌套循环
#include <stdio.h>
int main()
{
    int i;
    int j;
    for(i = 12; i <= 14; i++)
    {
        printf("Table of %d\n", i);
        for(j = 1; j <= 10; j++)
        {
            printf("%d*%d\t=\t%d\n", i, j, i*j);
        }
    }
    return 0;
}Code language: PHP (php)
do…while 循环
#include <stdio.h>
int main()
{
    int a = 1;
    do
    {
        printf("Hello World\n");
        a++;
    }
    while(a <= 10);
    return 0;
}Code language: PHP (php)
无限循环
#include <stdio.h>
int main()
{
    for(;;)
    {
        printf("This is not gonna end!\n");
    }
    return 0;
}Code language: PHP (php)

要终止无限循环,请按 Ctrl+C。

switch..case 语句

switch(expression)
{
    case constant1:
        statement(s);
        break;
    case constant2:
        statement(s);
        break;
    default:
        statement(s);
}Code language: JavaScript (javascript)
#include <stdio.h>
int main()
{
    char grade;
    printf("Enter your grade\n");
    scanf(" %c", &grade);
    switch(grade)
    {
        case 'A':
            printf("Excellent!\n");
            break;
        case 'B':
            printf("Outstanding!\n");
            break;
        case 'C':
            printf("Good!\n");
            break;
        case 'D':
            printf("Can do better\n");
            break;
        case 'E':
            printf("Just passed\n");
            break;
        case 'F':
            printf("You failed\n");
            break;
        default:
            printf("Invalid grade\n");
    }
    return 0;
}Code language: PHP (php)

break 和 continue

break 用于在需要时中断或终止循环。continue 语句将控制权传递给条件测试,跳过了循环的其余语句。

#include <stdio.h>
int main()
{
    int a;
    for(a = 1; a <= 10; a++)
    {
        printf("Hello World\n");
        if(a == 2)
        {
            break;
        }
    }
    return 0;
}Code language: PHP (php)
#include <stdio.h>
int main()
{
    int a;
    for(a = 1; a <= 10; a++)
    {
        printf("Hello World\n");
        if (a == 2)
        {
            continue;
        }
        printf("a is not 2\n");
    }
    return 0;
}Code language: PHP (php)

函数

函数不过是一组代码并命名而来。而且可以随时调用它们而无需一次又一次地编写整个代码。

库函数和用户定义函数

库函数是 C 中的预定义函数,如 printf() 和 scanf()。

用户定义函数:我们还可以在 C 中定义我们自己的函数。

return_type function_name(parameters);
float average(int num1, int num2);

定义函数:

float average(int num1, int num2)
{
    float avg;
    avg = (num1 + num2) / 2.0;
    return avg;
}Code language: JavaScript (javascript)

调用函数:

#include <stdio.h>

float average(int num1, int num2)
{
    float avg;
    avg = (num1 + num2) / 2.0;
    return avg;
}

int main()
{
    int num1, num2;
    float c;
    printf("Enter first number\n");
    scanf("%d", &num1);
    printf("Enter second number\n");
    scanf("%d", &num2);
    c = average(num1, num2);
    printf("Average is %.2f\n", c);
    return 0;
}Code language: PHP (php)

如果一个函数不返回任何东西,则其返回类型为 void。

void display(int n)
{
    printf("Number is %d\n", n);
}Code language: JavaScript (javascript)

在另一个内部调用一个函数:

#include <stdio.h>

int div_2(int a)
{
    if(a % 2 == 0)
    {
        return 1;
    }
    else
    {
        return 0;
    }
}

void div_6(int b)
{
    if(div_2(b) == 1 && b % 3 == 0)
    {
        printf("Yes, the number is divisible by 6.\n");
    }
    else
    {
        printf("No, the number is not divisible by 6.\n");
    }
}

int main()
{
    div_6(12);
    div_6(25);
    return 0;
}Code language: PHP (php)

递归:递归是在同一函数内调用一个函数。

#include <stdio.h>

int factorial(int a)
{
    if(a == 0 || a == 1)
    {
        return 1;
    }
    else
    {
        return a * factorial(a - 1);
    }
}

int main()
{
    int n;
    printf("Enter number\n");
    scanf("%d", &n);
    int fact = factorial(n);
    printf("Factorial of %d is %d\n", n, fact);
    return 0;
}Code language: PHP (php)

指针

指针指向某个变量,即它存储变量的地址。例如,如果”a”具有地址 9562628,则指向”a”的指针将在其中存储值 9562628。

int a = 44;
int *b;
b = &a;Code language: HTML, XML (xml)

int *b 表示”b”是一个指向整数的指针。b = &a 意味着”b”现在存储”a”的地址。

#include <stdio.h>
int main()
{
    int a = 10;
    int *p;
    p = &a;
    printf("p = %u\n", p);
    printf("*p = %d\n", *p);
    printf("&p = %u\n", &p);
    printf("*&p = %u\n", *&p);
    return 0;
}Code language: PHP (php)

将指针传递给函数:

#include <stdio.h>
void swap(int *a, int *b)
{
    int t;
    t = *a;
    *a = *b;
    *b = t;
}

int main()
{
    int num1, num2;
    printf("Enter first number\n");
    scanf("%d", &num1);
    printf("Enter second number\n");
    scanf("%d", &num2);
    swap(&num1, &num2);
    printf("First number : %d\n", num1);
    printf("Second number : %d\n", num2);
    return 0;
}Code language: PHP (php)

数组

简单来说,数组就是一个集合。在 C 语言中,它是一组相似类型的数据。

声明数组
int n[6];Code language: CSS (css)
int n[] = {2, 3, 15, 8, 48, 13};

数组索引从 0 开始。n[0] 是第一个元素。

#include <stdio.h>
int main()
{
    int marks[3];
    float average;

    printf("Enter marks of first student\n");
    scanf("%d", &marks[0]);

    printf("Enter marks of second student\n");
    scanf("%d", &marks[1]);

    printf("Enter marks of third student\n");
    scanf("%d", &marks[2]);

    average = (marks[0] + marks[1] + marks[2]) / 3.0;
    printf("Average marks : %f\n", average);

    return 0;
}Code language: PHP (php)
指向数组的指针

数组的名称是指向数组第一个元素的指针。

#include <stdio.h>
int main()
{
    float n[5] = {20.4, 30.0, 5.8, 67, 15.2};
    float *p;
    int i;
    p = n;
    for (i = 0; i < 5; i++)
    {
        printf("*(p + %d) = %f\n", i, *(p + i));
    }
    return 0;
}Code language: PHP (php)
在函数中传递数组
#include <stdio.h>
float average(float a[], int size)
{
    int i;
    float avg, sum = 0;
    for(i = 0; i < size; i++)
    {
        sum += a[i];
    }
    avg = sum / size;
    return avg;
}

int main()
{
    int size, j;
    printf("Enter the size of array");
    scanf("%d", &size);
    float b, n[size];
    for(j = 0; j < size; j++)
    {
        printf("Value of n[%d] : ", j);
        scanf("%f", &n[j]);
    }
    b = average(n, size);
    printf("Average of numbers=%.2f\n", b);
    return 0;
}Code language: PHP (php)

使用指针将数组传递给函数:

#include <stdio.h>
display(int *p)
{
    int i;
    for(i = 0; i < 8; ++i)
    {
        printf("n[%d] = %d\n", i, *p);
        p++;
    }
}

int main()
{
    int n[] = {1, 2, 3, 4, 5, 6, 7, 8};
    display(n);
    return 0;
}Code language: HTML, XML (xml)

二维数组

二维数组是数组的数组。

int board[3][3] = {
    {'1','2','3'},
    {'4','5','6'},
    {'7','8','9'}
};Code language: JavaScript (javascript)

数组

简单来说,数组就是一个集合。

同样在 C 语言中,它是一组相似类型的数据,可以是 int,float,double,char(字符串)等。所有数据类型必须相同。例如,我们不能有一个数组,其中一些数据是整数,有些数据是浮点数。

为什么要数组?

假设我们需要在一个班级中存储 50 名学生的分数并计算平均分数。因此,声明 50 个单独的变量将完成这项工作,但是没有程序员愿意这样做。数组就派上用场了。

如何声明数组

数据类型 array_name[array_size];Code language: CSS (css)

例如,采用整数 n 的数组:

int n[6];Code language: CSS (css)

n[ ] 用于表示数组 n。这意味着 n 是一个数组。

因此,int n[6] 意味着 n 是 6 个整数的数组。在这里,6 是数组的大小,即数组 n 中有 6 个元素。

我们需要给出数组的大小,因为编译器需要在内存中分配空间,而这在不知道大小的情况下是不可能的。编译器借助数组中元素的数量和数组中存在的数据类型的大小来确定数组所需的大小。

在这里 int n[6] 将空间分配给 6 个整数。

我们还可以通过其他方法声明数组:

int n[] = {2, 3, 15, 8, 48, 13};

在这种情况下,我们要同时声明并为数组分配值。此处,无需指定数组大小,因为编译器从 {2,3,15,8,48,13} 中获取它。

数组索引

数组的每个元素都有其索引。我们使用其索引访问数组的任何元素。

上述数组的图片视图为:

元素231584813
索引012345

0、1、2、3、4 和 5 是索引。就像它们是数组的 6 个不同元素的标识一样。索引始终从 0 开始。因此,数组的第一个元素的索引为 0。

数组的索引从 0 开始。

我们使用其索引访问数组的任何元素,并且语法如下:

array_name[index]Code language: CSS (css)

例如,如果数组的名称为 n,那么我们要编写访问第一个元素(索引为 0 的元素)n[0]。

在这里:

  • n[0] 是 2
  • n[1] 是 3
  • n[2] 是 15
  • n[3] 是 8
  • n[4] 是 48
  • n[5] 是 13

n[0]、n[1] 等等。就像我们使用的是任何其他变量,我们可以设置值作为 n[0] = 5; 像我们这样做与任何其他变量(x = 5;,y = 6; 等)。

给数组赋值

通过编写 int n[] = {2,4,8};,我们可以同时声明并向数组分配值,从而对其进行初始化。

但是,当我们声明类似的数组时 int n[3];,我们需要分别为其分配值。因为 int n[3]; 肯定会在内存中分配 3 个整数的空间,但是该空间中没有整数。

要对其进行初始化,请为数组的每个元素分配一个值。

n[0] = 2;
n[1] = 4;
n[2] = 8;

就像我们声明一些变量,然后为它们分配值一样。

int x, y, z;
x = 2;
y = 4;
z = 8;

因此,将值分配给数组元素的第一种方法是在声明数组时进行:

int n[] = {2, 4, 8};

第二种方法是先声明数组,然后为它的元素赋值:

int n[3];
n[0] = 2;
n[1] = 4;
n[2] = 8;

您可以通过将对待 n[0]、n[1] 和 n[2] 与之前使用的不同变量类似来理解这一点。

就像变量一样,数组也可以是任何其他数据类型。

float f[] = {1.1, 1.4, 1.5};

在这里,f 是一个浮点数数组。

首先,让我们看一下计算 3 个学生的平均分数的示例。在此,marks[0] 代表第一个学生的成绩,marks[1] 代表第二个学生的成绩,marks[2] 代表第三个学生的成绩。

#include <stdio.h>

int main()
{
    int marks[3];
    float average;

    printf("Enter marks of first student\n");
    scanf("%d", &marks[0]);

    printf("Enter marks of second student\n");
    scanf("%d", &marks[1]);

    printf("Enter marks of third student\n");
    scanf("%d", &marks[2]);

    average = (marks[0] + marks[1] + marks[2]) / 3.0;
    printf("Average marks : %f\n", average);

    return 0;
}Code language: PHP (php)

在这里,您看到了一个数组的工作示例,我们对待数组元素的方式与对待普通变量的方式完全相似。&marks[0]、&marks[1] 和 &marks[2] 分别表示 marks[0]、marks[1] 和 marks[2] 的地址。

在上面的示例中,应牢记两点:

  • 平均值应为 float 类型,因为整数的平均值也可以为 float。
  • 其次,在取平均值时,将数字的总和除以 3.0 而不是 3,否则平均值将作为整数而不是浮动的。

我们也可以使用 for 循环,如下面的示例所示:

#include <stdio.h>

int main()
{
    int n[10]; /* declaring n as an array of 10 integers */
    int i, j;
    /* initializing elements of array n */
    for (i = 0; i < 10; i++)
    {
        printf("Enter value of n[%d]", i);
        scanf("%d", &n[i]);
    }
    /* printing the values of elements of array */
    for (j = 0; j < 10; j++)
    {
        printf("n[%d] = %d\n", j, n[j]);
    }
    return 0;
}Code language: PHP (php)

上面的代码只是让您熟悉对数组使用循环,因为您将在以后做很多次。

代码很简单,因为数组的索引从 0 开始到 9(对于 10 个元素),所以 i 和 j 从 0 开始。因此,i 和 j 上升到 9 而不是 10(i < 10 和 j < 10)。因此,在代码 n[i] 中将是 n[1]、n[2]、…、n[9],事情将因此而去。

如果我们声明了一个具有一定数组大小的数组,并且仅对该数组的某些元素分配了值,则其他元素的值将自动分配为零。

假设我们声明并初始化一个数组为:

int n[5] = {12, 13, 5};

这意味着 n[0] = 12,n[1] = 13 和 n[2] = 5,其余所有元素均为零,即 n[3] = 0 和 n[4] = 0。

同样:

int n[5];
n[0] = 12;
n[1] = 13;
n[2] = 5;

在上面的代码中,n[0]、n[1] 和 n[2] 分别初始化为 12、13 和 5。因此,n[4] 和 n[5] 均为 0。

数组分配连续的内存。因此,如果整数数组的第一个元素的地址为 223698688,则第二个元素的地址将为 223698692(223698688 + 4(4 是一个整数的大小)),第三个元素的地址将为 223698696,依此类推。这意味着数组的所有元素的内存都分配在一起并且是连续的。

指向数组的指针

到目前为止,我们已经看到了如何声明和初始化数组。现在,我们将看到如何也可以拥有指向数组的指针。

众所周知,指针是一个变量,其值是其他变量的地址,即,如果变量 y 指向另一个变量 x,则意味着变量 y 的值就是 x。

同样,如果我们说变量 y 指向数组 n,则意味着 y 的值是数组第一个元素的地址,即 n[0]。这意味着数组的指针是其第一个元素的指针。

数组的名称是指向数组第一个元素的指针。

如果 p 是指向数组 age 的指针,则意味着 p(或 age)指向 age[0]。

int age[50];
int *p;
p = age;

上面的代码为 p 分配了数组 age 的第一个元素的地址。

现在,由于 p 指向数组 age 的第一个元素,因此 *p 是数组的第一个元素的值。

由于 *p 表示第一个数组元素,因此 *(p + 1) 和 *(p + 2) 分别表示第二个元素和第三个元素,依此类推。

因此,*p 是 age[0],*(p + 1) 是 age[1],*(p + 2) 是 age[2]。

类似地,*age 是 age[0](年龄值),*(age + 1) 是 age[1](年龄+1 值),*(age + 2) 是 age[2](年龄+2 值)等等。

这就是所有指向数组的指针。

现在让我们看一些例子:

#include <stdio.h>

int main()
{
    float n[5] = {20.4, 30.0, 5.8, 67, 15.2}; /* declaring n as an array of 5 floats */
    float *p; /* p as a pointer to float */
    int i;
    p = n; /* p now points to array n */
    /* printing the values of elements of array */
    for (i = 0; i < 5; i++)
    {
        printf("*(p + %d) = %f\n", i, *(p + i)); /* *(p+i) means value at (p+0),(p+1)...*/
    }
    return 0;
}Code language: PHP (php)

因为 p 指向数组的第一个元素,所以 *p 或 *(p+0) 表示 p[0] 处的值或 p 的第一个元素处的值。类似地,*(p+1) 表示 p[1] 处的值。并且分别 *(p+3) 和 *(p+4) 代表 p[3] 和 p[4]。因此,事情就已经印出来了。

以上示例总结了以上概念。现在,让我们打印数组的地址以及数组的各个元素:

#include <stdio.h>

int main()
{
    int n[4] = {20, 30, 5, 67}; /* declaring n as an array of 4 integers */
    int *p; /* a pointer */
    int i;
    p = n; /* p is pointing to array n */
    /* printing the address of array */
    printf("Address of array n[4] = %u\n", p); /* p points to array means store the address of the first element of array */
    /* printing the addresses of elements of array */
    for (i = 0; i < 4; i++)
    {
        printf("Address of n[%d] = %u\n", i, &n[i]);
    }
    return 0;
}Code language: PHP (php)

您已经注意到 n 和 p 的第一个元素的地址相同,这意味着我没有说谎!

您也可以使用 (p + 1)、(p + 2) 和 (p + 3) 打印其他元素的地址。

在函数中传递整个数组

在 C 语言中,我们可以将数组的元素或整个数组作为参数传递给函数。

首先让我们传递单个数组元素以起作用:

#include <stdio.h>

void display(int a)
{
    printf("%d\n", a);
}

int main()
{
    int n[] = {20, 30, 23, 4, 5, 2, 41, 8};
    display(n[2]);
    return 0;
}Code language: PHP (php)

在函数中传递整个数组

我们还可以通过将数组名称作为参数来传递整个数组给一个函数。是的,诀窍是我们将传递数组的地址,即数组的第一个元素的地址。因此,通过拥有第一个元素的指针,我们可以像上面的示例中那样获得整个数组。

让我们看一个例子来理解它:

#include <stdio.h>

float average(float a[])
{
    int i;
    float avg, sum = 0;
    for (i = 0; i < 8; ++i)
    {
        sum += a[i];
    }
    avg = sum / 8;
    return avg;
}

int main()
{
    float b, n[] = {20.6, 30.8, 5.1, 67.2, 23, 2.9, 4, 8};
    b = average(n);
    printf("Average of numbers=%.2f\n", b);
    return 0;
}Code language: HTML, XML (xml)

average(float a[]) → 该函数正在获取一个 float 数组。并且该功能的其余部分正在相应地执行。

b = average(n) → 您在此处应注意的一件事是,我们传递了 n。如前所述,n 是指向第一个元素的指针或指向数组的指针 n[]。因此,我们实际上已经传递了指针。

在上面的示例中,我们计算了数组元素的平均值,我们已经知道数组的大小,即 8。

假设我们从用户那里获取数组的大小。在这种情况下,数组的大小是不固定的。在这里,我们需要将数组的大小作为第二个参数传递给函数。

#include <stdio.h>

float average(float a[], int size)
{
    int i;
    float avg, sum = 0;
    for (i = 0; i < size; i++)
    {
        sum += a[i];
    }
    avg = sum / size;
    return avg;
}

int main()
{
    int size, j;
    printf("Enter the size of array");
    scanf("%d", &size);
    float b, n[size];
    for (j = 0; j < size; j++)
    {
        printf("Value of n[%d] : ", j);
        scanf("%f", &n[j]);
    }
    b = average(n, size);
    printf("Average of numbers=%.2f\n", b);
    return 0;
}Code language: PHP (php)

该代码与上一个代码相似,除了我们显式传递了数组的大小。

我们还可以使用指针将数组传递给函数。让我们看看如何:

#include <stdio.h>

display(int *p)
{
    int i;
    for (i = 0; i < 8; ++i)
    {
        printf("n[%d] = %d\n", i, *p);
        p++;
    }
}

int main()
{
    int n[] = {1, 2, 3, 4, 5, 6, 7, 8};
    display(n);
    return 0;
}Code language: HTML, XML (xml)

在上面的示例中,将数组的地址(即 n[0] 的地址)传递给函数的形式参数。

display(int *p) → 这意味着函数 display 正在使用指向整数的指针。

现在我们根据函数 display 的要求传递了整数指针,即数组 n[] 的指针。

由于 p 是函数 display 中数组 n[] 的地址,即数组第一个元素(n[0])的地址,因此 *p 表示 n[0] 的值。在 for 循环功能中,p++ 将 p 的值增加 1。因此,当 i = 0 时,将打印 *p 的值。然后 p++ 将 *p 增加到 *(p + 1),在第二个循环中,*(p + 1) 的值,即 n[1] 也被打印出来。当 *(p + 7) 的值(即 n[7])被打印时,此循环一直持续到 i = 7。

二维数组

如果数组是二维的怎么办?

是的,二维数组也存在,通常称为 matrix。这些由行和列组成。

在进入其应用程序之前,让我们首先了解如何声明和初始化 2D 数组。

二维数组声明

与一维数组相似,我们定义如下的二维数组:

int a[2][4];Code language: CSS (css)

这里,a 是整数的 2D 阵列,其由 2 行和 4 列。

它就像是:

第0栏第1栏第2栏第3栏
第0行a[0][0]a[0][1]a[0][2]a[0][3]
第1行a[1][0]a[1][1]a[1][2]a[1][3]

现在让我们看一下如何初始化二维数组。

将值分配给二维数组

与一维数组相同,我们也可以通过 2 种方式为二维数组的元素分配值。

在第一种方法中,只需为数组的元素分配一个值。如果未将任何值分配给任何元素,则假定其值为零。

假设我们声明了一个二维数组 a[2][2]。现在,我们需要为其元素分配值。

int a[2][2];
a[0][0] = 1;
a[0][1] = 2;
a[1][0] = 3;
a[1][1] = 4;

第二种方法是与一维数组同时声明和分配值:

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

此处,a[0][0] 的值为 1,a[0][1] 为 2,a[0][2] 为 3,a[1][0] 为 4,a[1][1] 为 5,a[1][2] 为 6。

我们也可以将以上代码编写为:

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

在声明时将值分配给数组时,不需要在一维数组中指定大小,但是在 2D 数组中,我们至少需要给出第二维的值。

让我们考虑在声明时将值分配给数组的不同情况:

int a[2][2] = {1, 2, 3, 4}; /* 有效 */
int a[][2] = {1, 2, 3, 4}; /* 有效 */
int a[2][] = {1, 2, 3, 4}; /* 无效 */
int a[][] = {1, 2, 3, 4}; /* 无效 */Code language: JavaScript (javascript)

为什么要使用二维数组

假设我们有 3 个学生,每个学生都在学习 2 个主题(主题 1 和主题 2),并且我们必须在这 3 个学生的两个主题中都显示分数。让我们输入用户的标记。

#include <stdio.h>

int main()
{
    float marks[3][2];
    int i, j;
    for (i = 0; i < 3; i++)
    {
        /* input of marks from the user */
        printf("Enter marks of student %d\n", (i + 1));
        for (j = 0; j < 2; j++)
        {
            printf("Subject %d\n", (j + 1));
            scanf("%f", &marks[i][j]);
        }
    }
    /* printing the marks of students */
    for (i = 0; i < 3; i++)
    {
        printf("Marks of student %d\n", (i + 1));
        for (j = 0; j < 2; j++)
        {
            printf("Subject %d : %f\n", (j + 1), marks[i][j]);
        }
    }
    return 0;
}Code language: PHP (php)

这就像:

主题1主题2
学生17867
学生27987
学生39089

字符串

数学和数学,代码与代码,但是在现实世界中,我们必须处理单词,句子等。C 语言中是否有任何东西可以处理这些类型的事物?答案是肯定的,它们被称为 string。

我们可以将字符串视为字符数组,例如 Sam 是字符串。

字符Sam\0
下标0123

因此,Sam 是字符 S、a、m 和 \0 的数组。

查看第 3 个索引处的字符。它代表空字符。ASCII 值的 \0 是 0 和的正常 0 是 48。它表示字符串的终止(结束)。

我们将字符串声明为:

char name[] = "Sam";Code language: JavaScript (javascript)

如您所见,字符串(char name[])的语法还告诉我们它是一个字符数组。

我们总是在 "" 中放置一个字符串,在 '' 中放置一个字符。

我们还可以使用字符声明一个字符串变量,如下所示:

char name[] = {'S', 'a', 'm', '\0'};Code language: JavaScript (javascript)

让我们看两个示例,分别显示不带 for 循环和带循环的字符串。

#include <stdio.h>

int main()
{
    char str[] = "Hello";
    printf("%s\n", str);
    return 0;
}Code language: PHP (php)

请注意,%s 用于字符串。

在上面的示例中,我们一次打印了整个字符串。现在,我们将看到相同的示例,但使用 for 循环打印单个字符。

#include <stdio.h>

int main()
{
    char str[] = "Hello";
    int i;
    for (i = 0; i < 6; i++)
    {
        printf("%c\n", str[i]);
    }
    return 0;
}Code language: PHP (php)

在第一个示例中,我们打印了字符串,并为此 %s 与 printf 函数一起使用。而在第二个示例中,我们每次只打印单个字符,因此我们使用 %c 该 printf 函数。

现在,让我们看一个从用户输入字符串的示例:

#include <stdio.h>

int main()
{
    char name[25];
    printf("Enter your name\n");
    scanf("%s", name);
    printf("Your name is %s\n", name);
    return 0;
}Code language: PHP (php)

您一定想知道在声明名称数组时将数组大小写为 25 的原因。这样做是因为我们不知道用户将输入的名称的长度。如果在上面的示例中,我们将数组的大小指定为 2,则字符串变量将不会采用输入,因为输入的大小大于数组的大小。因此,为了安全起见,请采用大于假定的输入大小的数组大小。

在使用 scanf 从用户那里获取字符串时,请勿在字符串名称前使用 &,因为在 name[25] 中,name 本身就是指向 name[25] 的指针。

scanf 从用户到字符串变量仅需要一个词。它以任何空白结尾。尝试在空格后写点什么,这只会占用第一个单词。

例如,如果在上面的示例中,我们输入 Sam Brad 作为名称,则输出将仅是 Sam,因为 scanf 仅考虑一个单词并在第一个单词之后终止。

如何获取多行字符串

#include <stdio.h>

int main()
{
    char name[25];
    printf("Enter your name\n");
    gets(name);
    printf("Your name is ");
    puts(name);
    return 0;
}Code language: PHP (php)

我们可以使用 gets 和 puts 接受输入并给出包含多个单词的字符串的输出,其中 gets 用于获取用户的字符串输入,而 puts 用于显示字符串。

考虑以下示例。

如果您收到关于 gets 的任何警告,请忽略它。

要进行打印,您也可以使用 printf 代替 puts。

您也可以使用 scanf("%[^\n]s", name); 用于获取多字串。

指针和字符串

字符串也可以使用指针声明。让我们考虑一个例子:

#include <stdio.h>

int main()
{
    char name[] = "Sam";
    char *p;
    p = name; /* for string, only this declaration will store its base address */
    while (*p != '\0')
    {
        printf("%c", *p);
        p++;
    }
    return 0;
}Code language: PHP (php)

在上面的示例中,p 存储 name[0] 的地址,因此 *p 的值等于 name[0] 的值,即 S。因此,在 while 循环中,第一个字符被打印出来,并将 p++ 的值加 1,以便现在 p + 1 指向 name[1]。这一直持续到指针到达字符串的末尾,即,在 *p 等于 \0 之前。

将字符串传递给函数

这与我们处理其他阵列相同。唯一的区别是这是一个字符数组。而已!

让我们来看一个例子:

#include <stdio.h>

void display(char ch[])
{
    printf("String :");
    puts(ch); /* display string */
}

int main()
{
    char arr[30];
    printf("Enter string\n");
    gets(arr); /* input string from user */
    display(arr);
    return 0;
}Code language: PHP (php)

预定义的字符串函数

我们可以执行不同类型的字符串功能,例如连接 2 个字符串,将一个字符串与另一个字符串进行比较或找到字符串的长度。让我们看一下这些函数的列表。

函数用途
strlen计算字符串的长度
strcat在另一个字符串的末尾附加一个字符串
strncat在另一个字符串的末尾追加字符串的前 n 个字符
strcpy将字符串复制到另一个
strncpy将一个字符串的前 n 个字符复制到另一个
strcmp比较两个字符串
strncmp比较两个字符串的前 n 个字符
strchr查找字符串中给定字符的首次出现
strrchr查找字符串中给定字符的最后一次出现
strstr查找另一个字符串中给定字符串的首次出现

这些函数在 string.h 头文件中定义,因此我们需要通过编写以下代码在代码中包含该头文件:

#include <string.h>Code language: CSS (css)

我们将看到一些例子 strlen、strcpy、strcat 和 strcmp 因为这些是最常用的。

strlen(s1) 计算字符串 s1 的长度。空格也以字符串的长度计算。

#include <stdio.h>
#include <string.h>

int main()
{
    char name[] = "Hello";
    int len1, len2;
    len1 = strlen(name);
    len2 = strlen("Hello World");
    printf("length of %s = %d\n", name, len1);
    printf("length of %s = %d\n", "Hello World", len2);
    return 0;
}Code language: PHP (php)

在计算字符串的长度时,strlen 不会计数 \0。

strcpy(s1, s2) 将第二个字符串 s2 复制到第一个字符串 s1。

#include <string.h>
#include <stdio.h>

int main()
{
    char s2[] = "Hello";
    char s1[10];
    strcpy(s1, s2);
    printf("Source string = %s\n", s2);
    printf("Target string = %s\n", s1);
    return 0;
}Code language: PHP (php)

strcat(s1, s2) 将第二个字符串 s2 连接(连接)到第一个字符串 s1。

#include <stdio.h>
#include <string.h>

int main()
{
    char s2[] = "World";
    char s1[20] = "Hello";
    strcat(s1, s2);
    printf("Source string = %s\n", s2);
    printf("Target string = %s\n", s1);
    return 0;
}Code language: PHP (php)

请注意,在上面的示例中,我们将数组大小指定为 s1,因为我们要向其中添加另一个字符串的字符。给定的数组大小应大于或等于串联后的字符串数组的大小。

strcmp(s1, s2) 比较两个字符串,找出它们是否相同。它逐字符比较两个字符串,直到不匹配为止。如果两个字符串相同,则返回 0。如果不是,则返回第一个非匹配字符对的 ASCII 值之间的差。

#include <stdio.h>
#include <string.h>

int main()
{
    char s1[] = "Hello";
    char s2[] = "World";
    int i, j;
    i = strcmp(s1, "Hello");
    j = strcmp(s1, s2);
    printf("%d \n %d\n", i, j);
    return 0;
}Code language: PHP (php)

二维字符数组

与整数和其他数据类型的 2D 数组相同,我们也有 2D 字符数组。

例如,我们可以写:

char names[4][10] = {
    "Andrew",
    "Kary",
    "Brown",
    "Lawren"
};Code language: JavaScript (javascript)

C语言中的预处理器

预处理程序在进入编译器之前会处理我们的程序。

如何声明?

预处理程序指令以哈希符号(#)开头。预处理程序指令是预处理程序命令。

最常见的预处理器指令是 #include。

这 #include 是一个预处理程序指令,它使诸如 stdio.h 的头文件对我们可用。

让我们再举一个预处理器指令的例子:

#define PI 3.14Code language: CSS (css)

这 #define 是预处理程序指令。它用于定义某些内容,例如此处我们已定义 PI 为 3.14。因此,在进入编译器之前,如果 PI 出现在程序中的任何位置,它将被 3.14 替换。

它与普通变量不同,因为普通变量是在编译期间处理的。但是,定义中的任何内容 #define 在编译之前都会被其值替换。

同样,#include 在开始编译之前,链接任何头文件。

以下是一个 C 程序来查找圆的区域:

#include <stdio.h>
#define PI 3.14

int main()
{
    int radius;
    float area;
    printf("Enter radius of circle\n");
    scanf("%d", &radius);
    area = PI * radius * radius;
    printf("Area of circle is %.2f\n", area);
    return 0;
}Code language: PHP (php)

您在这里应该唯一了解的是,即使在编译之前,只要程序中有 PI,PI 就会被 3.14 替换。因此,PI * radius * radius 将是 3.14 * radius * radius。

带参数的宏

#define 也可以用来编写宏定义,如下所示。宏也类似于函数,但与此有所不同。他们也可以争论。让我们看一个示例,以了解如何使用它们。

#define area(r) (3.14 * r * r)Code language: CSS (css)

让我们看一个使用宏打印圆形区域的示例:

#include <stdio.h>
#define area(r) (3.14 * r * r)

int main()
{
    int radius;
    float area;
    printf("Enter radius of circle\n");
    scanf("%d", &radius);
    area = area(radius);
    printf("Area of circle is %.2f\n", area);
    return 0;
}Code language: PHP (php)

我们定义了一个宏 area,它接受一个参数 r。所以,当我们叫 area(radius),它得到了替换 3.14 * radius * radius(如 area(r) 为 3.14 * r * r)。

与 area(x) 在编译过程中调用的函数不同,我们代码中的任何地方,在编译之前都会被直接替换 3.14 * x * x。

因此,以上代码等效于:

#include <stdio.h>

int main()
{
    int radius;
    float area;
    printf("Enter radius of circle\n");
    scanf("%d", &radius);
    area = 3.14 * radius * radius;
    printf("Area of circle is %.2f\n", area);
    return 0;
}Code language: PHP (php)

让我们将宏与函数进行比较

我们刚刚看到了使用宏打印圆形区域的示例。现在,让我们看看使用函数的相同示例。

#include <stdio.h>

float CircleArea(int r)
{
    float a;
    a = 3.14 * r * r;
    return a;
}

int main()
{
    int radius;
    float area;
    printf("Enter radius of circle\n");
    scanf("%d", &radius);
    area = CircleArea(radius);
    printf("Area of circle is %.2f\n", area);
    return 0;
}Code language: PHP (php)

让我们看一下宏和函数之间的基本区别:

  • 第一个区别是宏用其值替换代码(因为它用 (3.14 * r * r) 替换了 area(r))。因此,每次都会为代码分配一些空间。这意味着每次出现 area(r) 时,都会在内存中分配空间。但这不是函数的情况。
  • 其次,函数调用需要一些时间,但是在实际程序之前定义了宏。因此,宏更快。

结构

我们已经处理了数组。数组用于存储相似类型的数据。您是否曾经想过是否有任何方法可以存储不同的数据?

答案是肯定的。我们使用结构来存储不同类型的数据。例如,您是一名学生。您的名字是一个字符串,您的电话号码和 roll_no 是整数。因此,这里的姓名、地址和电话号码是这些不同类型的数据。在这里,结构出现在图片中。

定义结构

结构的语法为:

struct structure_name
{
    数据类型 member-1;
    数据类型 member-2;
    数据类型 member-3;
    数据类型 member-4;
};

在我们的例子中,我们将该结构命名为 student。在我们的案例中,该结构的成员为 name、roll_no 和 phone_number。

因此,我们的结构如下所示:

struct student
{
    int roll_no;
    char name[30];
    int phone_number;
};

结构变量声明

正如我们声明 int、char 等类型的变量一样,我们也可以声明结构的变量。

假设我们要存储三个学生的名册编号、姓名和电话号码。为此,我们将定义一个名称为 student 的结构(如上所述),然后声明结构 student 的三个变量,分别为 p1、p2 和 p3(分别代表三个学生)。

struct student
{
    int roll_no;
    char name[30];
    int phone_number;
};

main()
{
    struct student p1, p2, p3;
}

在此,p1、p2 和 p3 是结构 student 的变量。

我们还可以在定义结构时声明结构变量,如下所示:

struct student
{
    int roll_no;
    char name[30];
    int phone_number;
} p1, p2, p3;

现在,让我们看看如何输入每个学生的详细信息,例如 roll_no、姓名和电话号码。

假设我们要为第一个学生分配一个卷号。为此,我们需要访问第一个学生的卷号。我们通过写来做到这一点:

p1.roll_no = 1;

这意味着使用点(.)在结构中使用变量。p1.roll_no 可以理解为 p1 的 roll_no。

如果要为变量分配任何字符串值,将使用 strcpy,如下所示:

strcpy(p1.name, "Brown");Code language: JavaScript (javascript)

现在,让我们存储所有三个学生的详细信息:

#include <stdio.h>
#include <string.h>

int main()
{
    struct student
    {
        int roll_no;
        char name[30];
        int phone_number;
    };
    struct student p1 = {1, "Brown", 123443};
    struct student p2, p3;
    p2.roll_no = 2;
    strcpy(p2.name, "Sam");
    p2.phone_number = 1234567822;
    p3.roll_no = 3;
    strcpy(p3.name, "Addy");
    p3.phone_number = 1234567844;
    printf("First Student\n");
    printf("roll_no : %d\n", p1.roll_no);
    printf("name : %s\n", p1.name);
    printf("phone_number : %d\n", p1.phone_number);
    printf("Second Student\n");
    printf("roll_no : %d\n", p2.roll_no);
    printf("name : %s\n", p2.name);
    printf("phone_number : %d\n", p2.phone_number);
    printf("Third Student\n");
    printf("roll_no : %d\n", p3.roll_no);
    printf("name : %s\n", p3.name);
    printf("phone_number : %d\n", p3.phone_number);
    return 0;
}Code language: PHP (php)

始终使用 strcpy 将字符串值分配给字符串变量。

原因是在 C 语言中,我们不能将两个字符串(即字符数组)等价。如果我们写了 p1.name = "Brown";,那会给出一个错误。因此,通过编写 strcpy(p1, "Brown"),我们将字符串 Brown 复制到字符串变量 p1.name。

struct student p1 = {1, "Brown", 123443}; → 这也是我们初始化结构的方法之一。在下一行中,我们只是给变量赋值并打印出来。

结构使用连续的内存位置。

结构数组

我们还可以制作结构数组。在结构的第一个示例中,我们存储了 3 个学生的数据。现在假设我们需要存储 100 个此类孩子的数据。声明 100 个单独的结构变量绝对不是一个好选择。为此,我们需要创建一个结构数组。

让我们看一个 5 个学生的例子:

#include <stdio.h>

struct student
{
    int roll_no;
    char name[30];
    int phone_number;
};

int main()
{
    struct student stud[5];
    int i;
    for (i = 0; i < 4; i++)
    {
        printf("Student %d\n", i + 1);
        printf("Enter roll no. :\n");
        scanf("%d", &stud[i].roll_no);
        printf("Enter name :\n");
        scanf("%s", stud[i].name);
        printf("Enter phone number :\n");
        scanf("%d", &stud[i].phone_number);
    }
    for (i = 0; i < 4; i++)
    {
        printf("Student %d\n", i + 1);
        printf("Roll no. : %d\n", stud[i].roll_no);
        printf("Name : %s\n", stud[i].name);
        printf("Phone no. : %d\n", stud[i].phone_number);
    }
    return 0;
}Code language: PHP (php)

在这里,stud[0] 存储第一个学生的信息,stud[1] 第二个以此类推。

我们也可以一次复制两个结构:

#include <stdio.h>
#include <string.h>

int main()
{
    struct student
    {
        int roll_no;
        char name[30];
        int phone_number;
    };
    struct student p1 = {1, "Brown", 123443};
    struct student p2;
    p2 = p1;
    printf("roll_no : %d\n", p2.roll_no);
    printf("name : %s\n", p2.name);
    printf("phone_number : %d\n", p2.phone_number);
    return 0;
}Code language: PHP (php)

我们只写了 p2 = p1 就是这样。p1 的所有元素都已复制到 p2。

指向结构的指针

就像我们有用于 int、char 和其他数据类型的指针一样,我们也有指向结构的指针。这些指针称为结构指针。

现在,如何定义一个指向结构的指针?答案如下:

struct structure_name
{
    数据类型 member-1;
    数据类型 member-1;
    数据类型 member-1;
    数据类型 member-1;
};

main()
{
    struct structure_name *ptr;
}

让我们考虑一个使用结构指针的示例:

#include <stdio.h>

int main()
{
    struct student
    {
        char name[30];
        int roll_no;
    };
    struct student stud = {"sam", 1};
    struct student *ptr;
    ptr = &stud;

    printf("%s %d\n", stud.name, stud.roll_no);
    printf("%s %d\n", ptr->name, ptr->roll_no);

    return 0;
}Code language: PHP (php)

struct stud *ptr; → 我们已经声明 ptr 是结构 student 的指针。

ptr = &stud; → 我们使指针 ptr 指向结构 stud。

这是我们到目前为止所做的相同的事情。现在,来到 printf。

printf("%s %d\n", ptr->name, ptr->roll_no); → 是的,我们用来 -> 从其指针访问结构。就像我们在结构中使用(.)一样,我们在指针中使用 ->。

将结构传递给函数

我们还可以将结构传递给函数。

我们可以通过两种方法将结构传递给函数:

  • 值传递
  • 通过引用

值传递:在此,我们将结构变量作为参数传递给函数。通过一个例子,这将变得清楚。

#include <stdio.h>
#include <string.h>

struct student
{
    int roll_no;
    char name[30];
    int phone_number;
};

void display(struct student st)
{
    printf("Roll no : %d\n", st.roll_no);
    printf("Name : %s\n", st.name);
    printf("Phone no : %d\n", st.phone_number);
}

int main()
{
    struct student s;
    s.roll_no = 4;
    strcpy(s.name, "Ron");
    s.phone_number = 888888;
    display(s);
    return 0;
}Code language: PHP (php)

在此示例中,我们使用功能打印卷号、学生的姓名和电话号码。我们首先声明一个名为 student 的结构,其名称为 roll_no、名称和电话为成员,变量为 s。然后,我们将编号、姓名和电话号码的值分配给结构变量 s。就像我们将其他任何变量传递给函数一样,我们也将结构变量 s 传递给函数 display。

现在,在定义函数时,我们传递了变量 s 的副本作为其参数,并在其前面写入了 struct student,因为传递的变量是一个名为 student 的类型结构。最后,在函数中,我们将打印结构变量的名称、编号和电话号码。

通过引用:通过引用传递时,结构变量的地址传递给函数。在这种情况下,如果我们更改函数内部的结构变量,则用于调用该函数的原始结构变量将发生变化。按值调用不是这种情况。

#include <stdio.h>
#include <string.h>

struct student
{
    int roll_no;
    char name[30];
    int phone_number;
};

void display(struct student *st)
{
    printf("Roll no : %d\n", st->roll_no);
    printf("Name : %s\n", st->name);
    printf("Phone no : %d\n", st->phone_number);
}

int main()
{
    struct student s;
    s.roll_no = 4;
    strcpy(s.name, "Ron");
    s.phone_number = 888888;
    display(&s);
    return 0;
}Code language: PHP (php)

这种情况与前一种情况相似,唯一的区别是这一次,我们将结构变量的地址传递给了函数。在声明该函数时,我们的函数采用结构 st 的指针。由于指针是一个名为 student 的类型结构变量,因此我们在函数参数的指针名称之前写了 struct student。在函数中,如前所述,我们使用 -> 符号访问了指针的成员。

尝试在两种情况下都更改函数内部变量的值,并查看实际变量的更改。

纸牌游戏

游戏规则:

  1. 第一名玩家将选择一张牌。
  2. 现在,第二个玩家将选择一张牌。
  3. 如果第二位玩家选择的值与第一位玩家选择的卡相同,则将获得积分。
  4. 现在,第二位玩家将首先选择一张牌,然后是第一位玩家。
  5. 如果第一位玩家选择的值与第二位玩家选择的牌相同,那么他将获得积分。
  6. 重复步骤 1 至 5。
  7. 得分更高的玩家将赢得比赛。
#include <stdio.h>
#include <string.h>
#include <stdlib.h> //for srand and screen clear and echo off and on
#include <time.h>   //for shuffling

main()
{
    system("clear"); //screen clear
    int i, j, z, k, lp;
    char s, rc;
    struct card
    {
        char *value;
        char *suite;
    };
    struct card temp, list[52], player1[26], player2[26];
    //temp for swaping

    char *value[] = {"A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "K", "Q", "J"};
    char *suite[] = {"diamond", "spade", "heart", "club"};
    for (i = 0; i < 52; i++)
    {
        if (i < 13)
        {
            list[i].suite = *(suite);
            list[i].value = *(value + i);
        }
        else if (i >= 13 && i < 26)
        {
            list[i].suite = *(suite + 1);
            list[i].value = *(value + (i - 13));
        }
        else if (i >= 26 && i < 39)
        {
            list[i].suite = *(suite + 2);
            list[i].value = *(value + (i - 26));
        }
        else if (i >= 39)
        {
            list[i].suite = *(suite + 3);
            list[i].value = *(value + (i - 39));
        }
    }

    do //do while to ask after game play more ?y or n:
    {

        //shuffling

        int n = 52;
        srand(time(NULL));
        for (i = n - 1; i > 0; i--)
        {
            int j = rand() % (i + 1);
            temp.value = list[i].value;
            temp.suite = list[i].suite;
            list[i].value = list[j].value;
            list[i].suite = list[j].suite;
            list[j].value = temp.value;
            list[j].suite = temp.suite;
        }

        //distributing cards
        for (i = 0; i < 52; i++)
        {
            if (i < 26)
            {
                player1[i].value = list[i].value;
                player1[i].suite = list[i].suite;
            }
            else if (i >= 26)
            {
                player2[i - 26].value = list[i].value;
                player2[i - 26].suite = list[i].suite;
            }
        }

        //for cards info
        printf("Player1 has:\t\t\tPlayer2 has:\n");
        for (i = 0; i < 26; i++)
            printf("%d\t%s\t%s\t\t%d\t%s\t%s\n", i + 1, player1[i].value, player1[i].suite, i + 1, player2[i].value, player2[i].suite);

        printf("YOUR INPUT WILL NOT BE VISIBLE\n");

        int p1score = 0, p2score = 0;
        char a[10], b[10];
        char c[10], d[10];

        for (j = 0; j < 26; j++)
        {

            system("stty -echo"); //echo off. input will not be visible

            //even value of i will first let player1 to play and odd value to player 2
            if (j % 2 == 0)
            {

                int x = 0;
                do
                {
                    printf("Player1: type value and suite:");
                    scanf("%s %s", &a[0], &b[0]);

                    for (i = 0; i < 26; i++)
                    {
                        //checking if player owns card or not
                        z = strcmp(player1[i].value, a);
                        k = strcmp(player1[i].suite, b);

                        if (z == 0 && k == 0)
                        {
                            //removing used cards
                            player1[i].value = "\0";
                            player1[i].suite = "\0";

                            x++;
                        }
                    }
                    if (x == 0)
                        printf("ENTER CORRECT CARD\n");
                } while (x == 0);

                int y = 0;
                do
                {
                    printf("Player2: type value and suite:");
                    scanf("%s %s", &c[0], &d[0]);

                    for (i = 0; i < 26; i++)
                    {

                        z = strcmp(player2[i].value, c);
                        k = strcmp(player2[i].suite, d);

                        if (z == 0 && k == 0)
                        {
                            player2[i].value = "\0";
                            player2[i].suite = "\0";

                            y++;
                        }
                    }
                    if (y == 0)
                        printf("ENTER CORRECT CARD\n");
                } while (y == 0);

                //score if player2 choose same card
                lp = strcmp(a, c);

                if (lp == 0)
                    p2score = p2score + 10;
            }
            else //if i is odd first turn to player2
            {

                int y = 0;
                do
                {
                    printf("Player2: type value and suite:");
                    scanf("%s %s", &c[0], &d[0]);

                    for (i = 0; i < 26; i++)
                    {

                        z = strcmp(player2[i].value, c);
                        k = strcmp(player2[i].suite, d);

                        if (z == 0 && k == 0)
                        {
                            player2[i].value = "\0";
                            player2[i].suite = "\0";

                            y++;
                        }
                    }
                    if (y == 0)
                        printf("ENTER CORRECT CARD\n");
                } while (y == 0);

                int x = 0;
                do
                {
                    printf("Player1: type value and suite:");
                    scanf("%s %s", &a[0], &b[0]);

                    for (i = 0; i < 26; i++)
                    {

                        z = strcmp(player1[i].value, a);
                        k = strcmp(player1[i].suite, b);

                        if (z == 0 && k == 0)
                        {
                            player1[i].value = "\0";
                            player1[i].suite = "\0";

                            x++;
                        }
                    }
                    if (x == 0)
                        printf("ENTER CORRECT CARD\n");
                } while (x == 0);

                lp = strcmp(a, c);

                if (lp == 0)
                    p1score = p1score + 10;
            }

            //to see remaining cards

            printf("\nPlayer1 has:\t\t\tPlayer2 has:\n");
            for (i = 0; i < 26; i++)
                printf("%d\t%s\t%s\t\t%d\t%s\t%s\n", i + 1, player1[i].value, player1[i].suite, i + 1, player2[i].value, player2[i].suite);

            printf("\nPLAYER1 SCORE:%d\tPLAYER2 SCORE:%d\n\n", p1score, p2score);

            system("stty echo"); //echo on
        }

        if (p1score > p2score)
            printf("PLAYER1 WINS\n");
        else if (p1score < p2score)
            printf("PLAYER2 WINS\n");
        else
            printf("MATCH DRAWS\n");

        //if one has to play more...do while loop

        printf("want to play more? y or n:");
        scanf(" %c", &s);
    } while (s == 'y');
}Code language: PHP (php)

真正的游戏是这样制作的吗?

是的,我们刚刚制作了游戏的结构以将其链接到图形。完成本课程后,您可以扩展知识。

使它变得更好。

使用函数来减少代码的长度,询问用户播放器的数量,或实现您所拥有的其他想法。

文件

当程序运行时,数据在内存中,但是当程序结束或计算机关闭时,数据将会丢失。为了永久保留数据,我们需要将其写入文件。

文件用于存储数据。在本主题中,我们将学习从文件中读取数据以及在文件中写入数据的知识。

首先,让我们看看如何声明文件。

使用文件类型的指针声明文件,如下所示:

FILE *fr;

我们可以对文件执行许多功能。下面列出了其中一些功能。

函数描述
fopen()创建一个新文件或打开一个现有文件
fclose()关闭档案
fgetc()从文件中读取字符
fputc()写一个字符到文件
fscanf()从文件中读取字符串
fprintf()将字符串写入文件

让我们看看如何将数据写入文件,打开,关闭或读取文件。

打开文件

我们使用 fopen() 功能打开文件或创建新文件。让我们看一下语法的 fopen()。

int main()
{
    FILE *fr;
    fr = fopen("filename", "mode");
    return 0;
}Code language: JavaScript (javascript)

这里 fr 是指向文件的指针,filename 是我们要打开的文件的名称,也是我们要打开文件 mode 的原因。

模式可以采用以下值:

模式描述
r打开一个文本文件以供阅读
w打开一个文本文件进行写入
a打开一个文本文件进行追加。(追加意味着在末尾添加文本)
r+打开一个文本文件进行读写
w+打开一个文本文件以供读取和写入。(它首先将文件的长度减少为零(如果存在),或者如果不存在则创建一个文件)
a+在读写模式下打开一个文本文件。(如果文件不存在,它将创建一个文件。读取将从头开始,而写入只能从头开始)

这些是文本文件的模式。如果必须处理二进制文件,则模式如下:

rb、wb、ab、rb+、wb+、ab+

但是,在我们的教程中,我们将只处理文本文件。

当我们使用 fopen 它时,它将搜索磁盘上的文件,然后将文件加载到称为缓冲区的内存中。我们在关闭之前所做的更改是在缓冲存储器中进行的。进行更改时,可避免通过一次又一次访问磁盘来节省缓冲存储器。

关闭文件

我们使用 fclose() 函数关闭打开的文件。

fclose() 的语法如下:

#include <stdio.h>

int main()
{
    FILE *fr;
    fclose(fr);
    return 0;
}Code language: PHP (php)

fclose() 如果文件成功关闭,函数将返回零。如果关闭文件时出现错误,则返回 EOF(文件末尾)。

我们刚刚看到了如何打开和关闭文件。现在,我们将了解如何在文件中进行读写。

读取和写入文件

我们用于读取和写入的功能取决于我们要处理的是字符还是字符串。

例如,函数 fgetc() 和 fputc() 用于读取和写入文件中的字符。同样,函数 fscanf() 和 fprintf() 用于读取和写入文件中的字符串。

让我们来看每个示例,然后逐行了解它。

使用 fgetc() 和 fputc():fgetc() 读取在打开的文件的字符读模式使用 fopen()。它 EOF 在到达文件末尾时返回。

fputc() 将一个字符写入到打开的文件中写入模式使用 fopen()。

现在,让我们看一个从文件读取的示例:

#include <stdio.h>

int main()
{
    FILE *fr;
    char c;
    fr = fopen("prog.txt", "r");
    while (c != EOF)
    {
        c = fgetc(fr); /* read from file*/
        printf("%c", c); /* display on screen*/
    }
    fclose(fr);
    return 0;
}Code language: PHP (php)

在上面的示例中,首先我们以读取模式打开了一个名为 prog.txt 的文件,以便我们可以从该文件读取数据。为此,您的计算机中必须存在 prog.txt。

在 while 循环中,fgetc(fr) 从文件 prog.txt 中读取 c 的值。从文件中读取 c 的整个值并 EOF 达到(文件末尾)后,fclose(fr) 关闭文件。

就如此容易!

我们 fgetc() 使用变量 c 读取文件的内容。在 while 期间,printf 函数在屏幕上打印 c 的值。之后,我们将使用关闭文件 fclose。

使用 fscanf() 和 fprintf():虽然 getc 和 putc 用于字符,但是我们使用 fscanf() 和 fprintf 来读取和写入字符串到文件。

让我们借助示例来理解:

#include <stdio.h>

int main()
{
    FILE *fr;
    char s[40];
    int n;
    fr = fopen("welcome.txt", "w");
    printf("Enter a string and a number");
    scanf("%s%d", s, &n); /* read from keyboard */
    fprintf(fr, "%s %d", s, n); /* write to file */
    fclose(fr);
    fr = fopen("welcome.txt", "r");
    fscanf(fr, "%s%d", s, &n); /* read from file */
    printf("%s %d", s, n); /* display on screen */
    fclose(fr);
    return 0;
}Code language: PHP (php)

在这里,我们首先创建了一个名为 welcome.txt 的文件,并使用 fopen 功能在写入模式下将其打开。然后,我们使用 scanf 功能从键盘输入一个字符串和一个整数值,并将这些值分别存储在变量 s 和 n 中。

然后,fprintf 将字符串和整数值都写入文件。之后,fclose(fr) 关闭文件。

现在,我们将读取文件的内容,然后将其打印在屏幕上。为此,我们将首先使用 fopen 函数以读取模式打开文件。之后,fscanf 函数将读取文件的内容,printf 函数将在屏幕上显示文件的内容。

现在看到该程序将一个文件复制到另一个文件:

#include <stdio.h>

int main()
{
    FILE *s, *t;
    char c;
    s = fopen("source.txt", "r");
    t = fopen("target.txt", "w");
    while (1)
    {
        c = fgetc(s);

        if (c == EOF)
        {
            break;
        }
        else
        {
            fputc(c, t);
        }
    }

    fclose(s);
    fclose(t);
    return 0;
}Code language: PHP (php)

fputc(c, t) 将存储在 c 中的字符放入以 t 打开的文件中。

这是一项令人印象深刻的工作,您刚刚编写了复制两个文件的代码。为了使该程序正常运行,您必须具有一个名为 source.txt 的文件,或在代码本身中更改该文件的名称,以匹配存储在光盘中的文件。

动态内存分配

假设您想将玩具放在盒子里,但是您只知道它的大小。为此,您需要一个盒子,盒子的大小等于玩具的近似大小。

当我们想将一个句子作为字符数组输入但不确定该数组中的字符数时,我们也会遇到类似的情况。

现在,在声明字符数组时,如果我们指定其大小小于输入字符串的大小,则由于分配给数组的内存中的空间小于输入字符串的大小,我们将收到错误消息。这与尝试将大玩具放入较小的盒子中的情况相同。如果我们指定它的大小远大于输入字符串的大小,那么将在内存中为该数组分配一个比输入字符串的大小大得多的空间,因此即使在不需要时也不必要地消耗了更多的内存。这就像将一个小玩具放在一个大盒子里。

在上述情况下,直到编译时(当计算机编译代码并由用户输入字符串时),我们才知道数组的大小。在这种情况下,我们使用 malloc() 函数。

malloc

malloc 函数在运行时分配内存。它采用字节大小,并在内存中分配那么多空间。这意味着 malloc(50) 将在内存中分配 50 个字节。它返回一个空指针,并在 stdlib.h 中定义。

让我们借助示例来了解它:

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

int main()
{
    char name[20];
    char *address;

    strcpy(name, "Harry Lee");
    address = (char *)malloc(50 * sizeof(char)); /* allocating memory dynamically */
    strcpy(address, "Lee Fort, 11-B Sans Street");

    printf("Name = %s\n", name);
    printf("Address: %s\n", address);
    return 0;
}Code language: PHP (php)

在上面的示例中,我们像以前一样分配并打印了名称。对于地址,我们估计字符数应为 50 个左右。因此,地址的大小将为 50 * sizeof(char)。

char *address → 在这里,我们声明了指向地址字符的指针,而没有指定需要多少内存。

address = (char *)malloc(50 * sizeof(char)) → 通过编写此代码,我们为地址分配了 50 * sizeof(char) 字节的内存。我们曾经 (char *) 将 malloc 返回的指针类型转换为 character。

strcpy(address, "Lee Fort, 11-B Sans Street") → 通过编写此代码,最后我们分配了地址。

默认情况下,malloc 返回一个类型为 void 的指针,但是我们可以将其类型转换为任何其他形式的指针(在上面的示例中,我们将其转换为字符类型)。

如果 malloc 分配的内存空间不足,则分配失败,并且 malloc 返回 NULL 指针。

我们来看另一个例子:

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

int main()
{
    int n, i, *p;
    printf("Enter number of elements: ");
    scanf("%d", &n);
    p = (int *)malloc(n * sizeof(int)); //memory allocated using malloc
    if (p == NULL)
    {
        printf("memory cannot be allocated\n");
    }
    else
    {
        printf("Enter elements of array:\n");
        for (i = 0; i < n; ++i)
        {
            scanf("%d", &*(p + i));
        }
        printf("Elements of array are\n");
        for (i = 0; i < n; i++)
        {
            printf("%d\n", *(p + i));
        }
    }
    return 0;
}Code language: PHP (php)

在此示例中,首先,我们声明了一个 int 类型的指针 p,其中包含 n 个元素。因此,p 是包含 n 个元素的整数数组。因此,我们 n * sizeof(int) 为指针 p 所指向的数组分配了一个大小为大小的内存。因此,我们现在有一个存储空间分配给由 n 个元素组成的整数数组。此外,我们要求用户输入数组元素的值并显示这些值。

calloc

现在,假设您要在一个盒子里放多个玩具,而您只对玩具的数量和大小有一个大概的了解。为此,您需要一个盒子,盒子的大小等于所有玩具的大小之和。

在这种情况下,我们使用 calloc 函数。与 malloc 一样,calloc 也在运行时分配内存,并在 stdlib.h 中定义。它需要元素的数量和每个元素的大小(以字节为单位),将每个元素初始化为零,然后将空指针返回到内存。

它的语法是:

void *calloc(n, element-size);Code language: JavaScript (javascript)

在这里,n 是元素的数量,element-size 是每个元素的大小。

让我们再次看一下 malloc 的最后一个示例,但是这次是 calloc:

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

int main()
{
    int n, i, *p;
    printf("Enter number of elements: ");
    scanf("%d", &n);
    p = (int *)calloc(n, sizeof(int)); //memory allocated using calloc
    if (p == NULL)
    {
        printf("memory cannot be allocated\n");
    }
    else
    {
        printf("Enter elements of array:\n");
        for (i = 0; i < n; ++i)
        {
            scanf("%d", &*(p + i));
        }
        printf("Elements of array are\n");
        for (i = 0; i < n; i++)
        {
            printf("%d\n", *(p + i));
        }
    }
    return 0;
}Code language: PHP (php)

因此,这与 malloc 的示例相同,但 calloc 的语法有所不同。在这里,我们写了 (int *)calloc(n, sizeof(int)),其中 n 是整数数组中的元素数量(在这种情况下 sizeof(int) 为 5),并且是每个元素的大小。因此,数组的总大小为 n * sizeof(int)。

calloc 将分配的内存初始化为零值,malloc 否则不初始化。

为了证明这一点,让我们看两个例子:

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

int main()
{
    int n, i, *p;
    printf("Enter number of elements: ");
    scanf("%d", &n);
    p = (int *)calloc(n, sizeof(int));
    if (p == NULL)
    {
        printf("memory cannot be allocated\n");
    }
    else
    {
        printf("Elements of array are\n");
        for (i = 0; i < n; i++)
        {
            printf("%d\n", *(p + i));
        }
    }
    return 0;
}Code language: PHP (php)

在这里,我们指定了元素的数量,即 5,但是没有初始化任何元素。因此,calloc 将每个元素初始化为 0,从而将每个元素的值打印为 0。

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

int main()
{
    int n, i, *p;
    printf("Enter number of elements: ");
    scanf("%d", &n);
    p = (int *)malloc(n, sizeof(int));
    if (p == NULL)
    {
        printf("memory cannot be allocated\n");
    }
    else
    {
        printf("Elements of array are\n");
        for (i = 0; i < n; i++)
        {
            printf("%d\n", *(p + i));
        }
    }
    return 0;
}Code language: PHP (php)

由于 malloc 未将元素初始化为 0,因此在这种情况下会出现错误。

calloc 用于将内存分配给大多数数组和结构。

realloc

如果假设我们分配的内存多于或少于所需,则可以使用 realloc 更改先前分配的内存空间的大小。其语法如下:

void *realloc(pointer, new-size);Code language: JavaScript (javascript)

让我们看一个关于 realloc 的例子:

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

int main()
{
    char *p1;
    int m1, m2;
    m1 = 10;
    m2 = 20;
    p1 = (char *)malloc(m1);
    strcpy(p1, "Codesdope");
    p1 = (char *)realloc(p1, m2);
    strcat(p1, "Practice");
    printf("%s\n", p1);
    return 0;
}Code language: PHP (php)

在上面的示例中,我们声明了一个指针 p1,该指针将用于动态分配内存空间。

p1 = (char *)malloc(m1) → 通过编写此代码,我们分配了指针 p1 指向的 10 个字节的存储空间。我们曾经 (char *) 将 malloc 返回的指针类型转换为 character。

strcpy(p1, "Codesdope") → 这会将字符串值 Codesdope 分配给指针 p1 指向的内存。当前,存储空间为 10 个字节,可以轻松存储字符串 Codesdope,但如果现在我们希望该存储空间存储字符串 CodesdopePractice 怎么办?为此,我们需要扩展内存空间的大小,这可以通过 realloc 轻松实现。

p1 = (char *)realloc(p1, m2) → 这样会将内存空间(其地址存储在 p1 中)的大小增加到 20 个字节(由于 m2 的值为 20),因此可以轻松存储字符串 CodesdopePractice。

strcat(p1, "Practice") → 这会将字符串 Practice 添加到存储在 p1 指向的内存(即 Codesdope)中的字符串的末尾。因此,现在,由 p1 指向的内存现在存储字符串值 CodesdopePractice。

free

free 函数用于在程序完成后释放或释放内存,该内存是在程序中动态分配的。建议在程序完成后释放动态分配的内存,以便将来使用。

void free(pointer);Code language: JavaScript (javascript)

这是 free 函数的语法,其返回类型为 void。现在,让我们看一个示例,其中我们在程序结尾使用 free 释放了动态分配的内存。

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

int main()
{
    int n, i, *p;
    printf("Enter number of elements:\n");
    scanf("%d", &n);
    p = (int *)malloc(n * sizeof(int));
    if (p == NULL)
    {
        printf("memory cannot be allocated\n");
    }
    else
    {
        printf("Enter elements of array:\n");
        for (i = 0; i < n; ++i)
        {
            scanf("%d", &*(p + i));
        }
        printf("Elements of array are\n");
        for (i = 0; i < n; i++)
        {
            printf("%d\n", *(p + i));
        }
    }
    free(p);
    return 0;
}Code language: PHP (php)

因此,在这里,通过编写 free(p),我们释放了使用 malloc 动态分配的内存。

枚举

枚举(enum)是用户定义的数据类型(与结构相同)。它由该类型的各种元素组成。枚举没有这种特定的用途,我们只是为了使我们的代码更整洁,更易读而使用。我们也可以在不使用枚举的情况下编写 C 程序。

例如,夏季,春季,冬季和秋季是四个季节的名称。因此,可以说这些是季节类型。因此,这成为以季节和夏季,春季,冬季和秋季为名称的枚举。

因此,您很清楚枚举的基本概念。现在让我们看看如何定义它。

定义枚举

枚举以与结构相同的方式定义,其中关键字 struct 被关键字替换为关键字 enum,而元素由 逗号 分隔,如下所示:

enum enum_name
{
    element1,
    element2,
    element3,
    element4,
};

现在让我们定义上述季节示例的枚举:

enum Season
{
    Summer,
    Spring,
    Winter,
    Autumn
};

在这里,我们定义了一个名为 Season 和 Summer、Spring、Winter 和 Autumn 的枚举作为元素。

枚举变量声明

我们还以与结构相同的方式声明枚举变量。我们如下创建一个枚举变量:

enum season
{
    Summer,
    Spring,
    Winter,
    Autumn
};

main()
{
    enum season s;
}

因此,这里的 s 是名为 season 的枚举的变量。这个变量代表一个季节。我们还可以如下声明一个枚举变量:

enum season
{
    Summer,
    Spring,
    Winter,
    Autumn
} s;

枚举成员的价值观

枚举的所有元素都有一个值。默认情况下,第一个元素的值为 0,第二个元素的值为 1,依此类推。

让我们来看一个例子:

#include <stdio.h>

enum season
{
    Summer,
    Spring,
    Winter,
    Autumn
};

int main()
{
    enum season s;
    s = Spring;
    printf("%d\n", s);
    return 0;
}Code language: PHP (php)

在这里,我们首先定义了一个名为 Season 的枚举,并在主函数中声明了它的变量 s,如我们之前所见。Summer、Spring、Winter 和 Autumn 的值分别为 0、1、2 和 3。因此,通过编写 s = Spring,我们将变量 s 赋值为 1,因为 Spring 的值为 1。

我们还可以更改默认值,并将我们选择的任何值分配给枚举元素。一旦我们更改了任何枚举元素的默认值,其后所有元素的值也将相应地更改。一个例子将使这一点更清楚:

#include <stdio.h>

enum days
{
    sun,
    mon,
    tue = 5,
    wed,
    thurs,
    fri,
    sat
};

int main()
{
    enum days day;
    day = thurs;
    printf("%d\n", day);
    return 0;
}Code language: PHP (php)

默认值 sun 将为 0,mon 将为 1,tue 将为 2,依此类推。在上面的示例中,我们将 tue 的值定义为 5。因此,wed、thurs、fri 和 sat 的值将分别变为 6、7、8 和 9。对 sun 和 mon 的值将分别保持为 0 和 1 无效。因此,thurs 的值(即 7)将被打印出来。

让我们再看一个枚举的例子:

#include <stdio.h>

enum days
{
    sun,
    mon,
    tue,
    wed,
    thurs,
    fri,
    sat
};

int main()
{
    enum days day;
    day = thurs;
    printf("%d\n", day + 2);
    return 0;
}Code language: PHP (php)

在此示例中,thurs(即 4)的值分配给变量 day。由于我们正在打印 day + 2,即 6(= 4 + 2),因此输出为 6。

C语言的union

声明和使用结构的方式相同。像结构一样,它也用于存储不同类型的数据。

在探讨结构和联合之间的区别之前,让我们首先了解如何定义联合。

定义union

让我们看一下联合的语法:

union union_name
{
    数据类型 member-1;
    数据类型 member-2;
    数据类型 member-3;
    数据类型 member-4;
};

这不是结构的语法吗,除了我们写了关键词 union 来代替 struct 之外,这与结构的语法不同吗?

让我们以我们在结构中使用的相同示例为例。在这里,我们将 union 的名称称为 student,并将 name、roll_no 和 phone_number 用作其成员,如下所示:

union student
{
    int roll_no;
    char name[30];
    int phone_number;
};

union 变量声明

声明联合变量的方式与声明结构变量的方式相同。

同样,让我们以相同的示例为例,我们要存储三个学生的名册编号,姓名和电话号码。为此,我们将按照上面的定义定义一个名为 student 的联合,然后在主函数中声明其三个变量 p1、p2 和 p3(分别代表三个学生)。

union student
{
    int roll_no;
    char name[30];
    int phone_number;
};

main()
{
    union student p1, p2, p3;
}

还有另一种声明联合变量的方法,我们在定义联合时按如下方式声明它们:

union student
{
    int roll_no;
    char name[30];
    int phone_number;
} p1, p2, p3;

与结构类似,我们通过访问其姓名、roll_no 和电话号码来分配第一个学生的姓名、名次和电话号码(假设 p1),如下所示:

p1.roll_no = 1;

在这里,p1.roll_no 意味着 p1 的 roll_no。

总是使用 strcpy 为变量分配字符串值,因为我们为 p1(第一个学生)分配了名称 Brown:

strcpy(p1.name, "Brown");Code language: JavaScript (javascript)

到现在为止,您必须已经找到类似于结构的联合。现在让我们看一下两者之间的区别。

联合与结构之间的区别

在讨论差异之前,让我们先来看一个例子:

#include <stdio.h>

struct student1
{ //defining a union
    int roll_no;
    char name[40];
    int phone_number;
};

union student2
{
    int roll_no;
    char name[40];
    int phone_number;
};

int main()
{
    struct student1 s1;
    union student2 u1;
    printf("size of structure = %d\n", sizeof(s1));
    printf("size of union = %d\n", sizeof(u1));
    return 0;
}Code language: PHP (php)

谈论上面的示例,存储结构所需的内存量是其所有成员的内存大小的总和。在上面的示例中,变量 roll_no 和 phone_number 的内存大小将分别为 4 个字节(因为两者均为整数类型),而字符数组 name[40] 的内存大小将为 40 个字节(由于数组占用了内存)最多 40 个字符,并且 char 的大小为 1)。因此,该结构占用的内存将是 4 + 40 + 4 = 48 bytes。

现在进入联合,联合的内存大小等于其成员占据内存最大空间的大小。roll_no 和 phone_number 的大小分别为 4 个字节,name[40] 的大小为 40 个字节。因此,联合将占用 40 个字节的存储空间。

我们一次只能访问一个工会成员,因为我们在内存中只有一个位置,因此一次只能使用其中一个成员。所有其他成员将包含垃圾值(即会损坏)。对于可以同时访问所有成员变量的结构而言,情况并非如此,因为每个成员变量占用的存储空间不同。

现在让我们看一个联合的例子:

#include <stdio.h>
#include <string.h>

union student
{
    int roll_no;
    int phone_number;
    char name[30];
};

int main()
{
    union student p1;
    p1.roll_no = 1;
    p1.phone_number = 1234567822;
    strcpy(p1.name, "Brown");
    printf("roll_no : %d\n", p1.roll_no);
    printf("phone_number : %d\n", p1.phone_number);
    printf("name : %s\n", p1.name);
    return 0;
}Code language: PHP (php)

如您所见,名称按原样打印,垃圾值作为卷号和电话号码打印。让我们看看为什么会这样。

如您现在所知,我们一次只能访问一个工会成员,而其他成员则受到损坏。因此,当我们编写时 p1.roll_no = 1,访问了成员 roll_no 并为其分配了一个值 1。之后,通过写入 p1.phone_number = 1234567822,我们为成员 phone_number 分配了一个值。最后,我们为成员 name 分配了一个字符串值 Brown strcpy(p1.name, "Brown"),现在,其他两个成员 roll_no 和 phone_number 包含一个垃圾值。因此,name 的值按原样打印,输出中其他两个变量的值就是这两个变量的垃圾值。

让我们再看一个例子:

#include <stdio.h>
#include <string.h>

union student
{
    int roll_no;
    char name[30];
    int phone_number;
};

int main()
{
    union student p1;
    p1.roll_no = 1;
    printf("roll_no : %d\n", p1.roll_no);
    strcpy(p1.name, "Brown");
    printf("name : %s\n", p1.name);
    p1.phone_number = 1234567822;
    printf("phone_number : %d\n", p1.phone_number);
    return 0;
}Code language: PHP (php)

在这里,首先我们将 roll_no 的值分配为 1 并打印出来。因此,当前其他成员的值是一些垃圾值,而 roll_no 的值是 1,因此按原样打印。之后,我们给名称分配了一个字符串值 Brown,所以现在 roll_no 和 phone_number 包含垃圾值并且名称被打印出来。同样,我们打印了 phone_number。

C语言中的typedef

typedef 关键字用于为类型分配新名称。这只是为了防止我们编写更多内容。

例如,如果我们要声明一些 type 变量 unsigned int,则必须在程序中编写 unsigned int,这对于我们中的某些人可能非常忙。因此,我们可以使用 typedef 为 unsigned int 分配选择的新名称,该名称可以在我们想在程序中使用 unsigned int 的任何时间使用。

typedef current_name new_name;
typedef unsigned int uint;
uint i, j;

现在,我们可以在整个程序中编写 uint 而不是 unsigned int。上面的代码与编写相同:

unsigned int i, j;

让我们来看一个例子:

#include <stdio.h>

int main()
{
    typedef unsigned int ui;
    ui i = 5, j = 8;
    printf("i = %d\n", i);
    printf("j = %d\n", j);
    return 0;
}Code language: PHP (php)

因此,我们可以为任何数据类型分配一个新名称。

同样,我们也可以使用 typedef 为结构分配一个新名称,该结构是用户定义的数据类型,如下所示:

typedef struct structure_name
{
    数据类型 member-1;
    数据类型 member-2;
    数据类型 member-3;
    数据类型 member-4;
} type_name;

现在,在声明这种结构类型的变量的同时,我们可以 type_name 代替 struct structure_name 整个程序编写代码。

让我们以在 结构 主题中看到的名为 student 的结构为例:

#include <stdio.h>
#include <string.h>

typedef struct student
{
    int roll_no;
    char name[30];
    int phone_number;
} st;

int main()
{
    st p1, p2, p3;
    p1.roll_no = 1;
    strcpy(p1.name, "Brown");
    p1.phone_number = 123443;
    p2.roll_no = 2;
    strcpy(p2.name, "Sam");
    p2.phone_number = 1234567822;
    p3.roll_no = 3;
    strcpy(p3.name, "Addy");
    p3.phone_number = 1234567844;
    printf("First Student\n");
    printf("roll_no : %d\n", p1.roll_no);
    printf("name : %s\n", p1.name);
    printf("phone_number : %d\n", p1.phone_number);
    printf("Second Student\n");
    printf("roll_no : %d\n", p2.roll_no);
    printf("name : %s\n", p2.name);
    printf("phone_number : %d\n", p2.phone_number);
    printf("Third Student\n");
    printf("roll_no : %d\n", p3.roll_no);
    printf("name : %s\n", p3.name);
    printf("phone_number : %d\n", p3.phone_number);
    return 0;
}Code language: PHP (php)

在这里,整个示例与在 Structure 中所做的相同,唯一的区别是我们用 st 代替代替,struct student 即我们使用了新类型(名为 st)来声明该结构类型的变量(命名为 student)。

我们也可以结合使用 typedef 和联合。为此,所有内容都将与关键字关键字 union 代替 struct 的结构相同。

#include <stdio.h>
#include <string.h>

typedef union student
{
    int roll_no;
    int phone_number;
    char name[30];
} st;

int main()
{
    st p1, p2, p3;
    p1.roll_no = 1;
    p1.phone_number = 123443;
    strcpy(p1.name, "Brown");
    p2.roll_no = 2;
    p2.phone_number = 1234567822;
    strcpy(p2.name, "Sam");
    p3.roll_no = 3;
    p3.phone_number = 1234567844;
    strcpy(p3.name, "Addy");
    printf("First Student\n");
    printf("roll_no : %d\n", p1.roll_no);
    printf("phone_number : %d\n", p1.phone_number);
    printf("name : %s\n", p1.name);
    printf("Second Student\n");
    printf("roll_no : %d\n", p2.roll_no);
    printf("phone_number : %d\n", p2.phone_number);
    printf("name : %s\n", p2.name);
    printf("Third Student\n");
    printf("roll_no : %d\n", p3.roll_no);
    printf("phone_number : %d\n", p3.phone_number);
    printf("name : %s\n", p3.name);
    return 0;
}Code language: PHP (php)

C中的存储类

每个变量都有一个存储类,用于定义该变量的功能。它告诉编译器变量的存储位置,其初始值,作用域(可见性级别)和生存期(全局或局部)。

C 中有四个存储类:

  • auto
  • extern
  • static
  • register

让我们一一理解。

auto

默认情况下,在函数或块(块是一组代码的一部分,例如,用花括号括起来的语句构成代码块)中定义的变量属于自动存储类。这些变量也称为局部变量,因为它们是函数的局部变量,并且默认情况下为它们分配了一些垃圾值。由于这些变量是在函数内部声明的,因此只能在该函数内部访问。在声明这些变量时无需放置 auto,因为默认情况下它们是 auto。

虽然您在整个 C 教程中都使用了这些 auto(local)变量,但让我们看一个示例:

#include <stdio.h>

int sum(int n1, int n2)
{
    auto int s; //declaration of auto(local) variable
    s = n1 + n2;
    return s;
}

int main()
{
    int i = 2, j = 3, k;
    k = sum(i, j);
    printf("sum is : %d\n", k);
    return 0;
}Code language: PHP (php)

在此,变量 s 在函数 sum 内部声明,因此只能在函数内部使用。在声明时无需放置 auto。

extern

我们在变量之前编写 extern 关键字,以告诉编译器该变量在其他地方声明。基本上,通过在任何变量告诉我们该变量是在其他程序文件中声明的全局变量之前编写 extern 关键字。

现在让我们看看实际发生了什么。

您必须知道什么是全局变量。全局变量是在所有函数外部声明的变量。可以在整个程序中访问它,我们可以在任何函数中随时更改其值,如下所示:

#include <stdio.h>

int g;

void print()
{
    g = 10;
    printf("g = %d\n", g);
}

int main()
{
    g = 7;
    printf("g = %d\n", g);
    print();
    return 0;
}Code language: PHP (php)

在这里,g 是在所有功能之外定义的全局变量。在 main 函数中,将其值分配为 7,在 print 函数中将其值分配为 10。

在声明全局变量时,将像所有其他变量一样在内存中分配一些空间。我们可以像在上面的示例中一样,在声明它的同一程序文件中为其分配值。但是,如果我们要使用它或在任何其他程序文件中为其分配值,该怎么办。

我们可以使用 extern 关键字来做到这一点,如下所示。

firstfile.c:

int g = 0;

在第一个程序文件中 firstfile.c,我们声明了一个全局变量 g。

现在,我们将在头文件中将此变量 g 声明为 extern firstfile.h,然后将其包含在我们要使用此变量的第二个文件中。

firstfile.h:

extern int g;

现在在第二个程序文件中 secondfile.c,为了使用全局变量 g,我们需要通过写入在其中包含头文件 #include "firstfile.h"。在这里,我们为变量 g 分配了值 4,因此该程序中的 g 的值变为 4。

secondfile.c:

#include "firstfile.h"

main()
{
    g = 4;
    printf("%d", g);
}Code language: PHP (php)

static

初始化后声明为静态的变量将一直存在,直到程序结束。如果在函数内部声明了静态变量,则该静态变量将一直存在,直到程序结束,并且不会因为该函数的存在而被销毁(如 auto 中一样)。如果在程序中所有函数之外声明了静态变量,则只能在声明了该变量的程序中使用它,而对其他程序文件不可见(如 extern)。

让我们看一个静态变量的例子:

#include <stdio.h>

static int g = 5;

void fn()
{
    static int i = 0;
    printf("g = %d\t", g--);
    printf("i = %d\n", i++);
}

int main()
{
    while (g >= 2)
        fn();
    return 0;
}Code language: PHP (php)

在这里,g 和 i 是静态变量,其中 g 是全局变量,i 是局部变量。如果我们未 static 在声明 i 之前编写过代码,则每次将调用函数 fn() 时,每次都会将 i 声明为初始值 0 并作为函数 fn() 将退出,也将被摧毁。

register

它告诉编译器变量将被存储在寄存器中,而不是存储在内存(RAM)中。我们可以比普通变量更快地访问寄存器变量。并非所有定义为的寄存器 register 都将存储在寄存器中,因为它取决于实现和硬件的各种限制。

我们无法访问此类变量的地址,因为它们没有一个存储位置,通过以下示例可以清楚地看到这些位置:

#include <stdio.h>

int main()
{
    register int n = 20;
    int *ptr;
    ptr = &n;
    printf("address of n : %u", ptr);
    return 0;
}Code language: PHP (php)

Previous:

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注