知识导图 知识导图
首页
iOS知识
计算机软件
  • 即时通讯网 (opens new window)
  • 开发常用网站 (opens new window)
首页
iOS知识
计算机软件
  • 即时通讯网 (opens new window)
  • 开发常用网站 (opens new window)
  • MD

  • Vue

  • C语法

    • C语法Day1-函数
      • 小试牛刀
        • 1.1、程序入口函数
        • 1.2第一行代码:打印信息
        • 1.3运行:在线演示
        • 1.4运行:终端命令
        • 1.5、简单运算:数据和字符
        • 1.6、函数声明和调用
      • 文件引用
        • 示例1:引用外部文件变量
        • 运行结果:
        • 变量声明
        • 示例2:引用外部文件函数
        • 运行结果:
        • 附:外部声明可以在当前实现吗?
      • 常量
      • 判断语句
        • if-else
        • switch
      • 循环控制语句
        • while
        • for 循环
        • do...while 循环
        • 循环控制语句:break、continue
        • 循环控制语句:goto
      • 函数
        • 函数定义格式
        • 示例:
        • 函数声明
        • 函数参数
        • 可变数量的参数
        • 实例
      • 递归
    • C语法Day2-运算
    • C语法Day3-结构
    • C语法Day4-指针
    • C语法Day5-预处理
    • C语法Day6-文件
    • C语法Day7-标准库
    • C语法Day8-编译
  • C++语法

  • 汇编语言

  • 软件编程及算法
  • C语法
2023-05-28
目录

C语法Day1-函数

# 小试牛刀

开始实操!

# 1.1、程序入口函数

所有的软件程序通常需要一个入口函数,就像大门一样,而C语言的大门就是 main 函数

一个空房子的C软件最基本的代码长这样:

#include <stdio.h> // 环境中自带标准库文件,直接引用即可
 
int main() {
   return 0;
}

不过上面这个程序啥也没干,直接返回了。

# 1.2第一行代码:打印信息

#include <stdio.h> // 环境中自带标准库文件,直接引用即可
 
int main() {
   /* 我的第一个 C 程序 */
   printf("Hello, World! \n");
   
   return 0;
}

# 1.3运行:在线演示

随便找一个可以在线编译的网站即可验证效果:

https://www.nhooo.com/tool/c/

# 1.4运行:终端命令

1、需要安装gcc环境,xcode环境自带, 新建文件名 main.c ,保存上述代码。

$ ls
main.c

2、终端命令窗口查看本地gcc 环境:which gcc

$ which gcc
/usr/bin/gcc

3、编译代码,生成可执行文件 a.out

# 编译代码, -o 表示产物名称
$ gcc main.c -o main.out
# 产看结果
$ ls
main.out	main.c
# 执行可执行文件a.out
$ ./main.out
Hello, World!

我们看到最后打印了Hello, World!, 自此,一个简单的程序完成

# 1.5、简单运算:数据和字符

数据类型

常用基本数据类型占用空间(64位机器为例)
 char : 1个字节
 int :4个字节
 float:4个字节
 double:8个字节

基本类型书写
【整数】
 a,默认为10进制 ,10 ,20。
 b,以0开头为8进制,045,021。
 c.,以0b开头为2进制,0b11101101。
 d,以0x开头为16进制,0x21458adf。

 	int a = 3;

【小数】
单精度常量:2.3f 。
双精度常量:2.3,默认为双精度。

	float e = 3.12578; // 定义双精度浮点数

字符型常量:
用英文单引号括起来,只保存一个字符'a'、'b' 、'*' 
还有转义字符; 换行'\n' 、制表符'\t'

	char name = 'A';
	printf("name = %c\n", name); // 打印字符

字符串常量:
用英文的双引号引起来 可以保存多个字符:"abc"。

⚠️ c语言中没有 String 字符串类型,而是通过char类型的数组代替,但是数组的最后需要结尾符号 '\0'

方式一
char name[] = "张三";
	
方式二
char name[] = {'A', 'B', '\0'};

方式三
⚠️ 也可以指定长度,但是不能比最大长度短,否则会越界错误
char name[2] = {'A', 'B'}; // 长度设置1就会报错

printf("name = %s\n", name); // 打印字符串

修改main.c 文件:

#include <stdio.h>

int main()
{
	int a = 3, b = 5;  // 定义并初始化a和b
	int c = a + b;
	printf("c = %d\n",c);
	
	float e = 3.12578; // 定义浮点数
	printf("f = %.2f\n",e); // 保留2位小数
   return 0;
}

运行结果:

将main.c文件编译为main可执行文件,并执行:

$gcc -o main main.c -lm
$./main
c = 8
f = 3.12

# 1.6、函数声明和调用

三步骤:函数声明 - 函数实现 - 函数的调用

#include <stdio.h>

/* 函数声明 */
int max(int num1, int num2);

int main()
{
	int result;
    result = max(3, 6); // 函数的调用
    printf("最大值为: %d\n",result);
    return 0;
}

/* 函数实现:求最大值 */
int max(int num1, int num2) 
{
   return num1 > num2 ? num1 : num2; 
}

打印结果:最大值为: 6

# 文件引用

前面介绍了单个文件的编译执行,现在介绍多个文件相互 依赖

# 示例1:引用外部文件变量

文件 class.c 获取 文件 student.c 中学生的年龄、班级和姓名,然后打印出来

class.c

#include <stdio.h>

int main()
{
  // 仅声明
	extern int s_age;
	extern char s_name[], class_name[];
	
  printf("%s, 学生:%s, 年龄:%d岁 \n",s_name, class_name, s_age);
  return 0;
}

student.c

#include <stdio.h>

// 定义并初始化
int s_age = 6;
char class_name[] = "一年级三班", s_name[] = "张三";

# 运行结果:

将class.c文件编译为class可执行文件,并执行:

$ gcc class.c student.c -o class1
$ ./main
c = 8
f = 3.12

# 变量声明

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

变量的声明有两种情况:

  • 1、一种是需要建立存储空间的。例如:int a 在声明的时候就已经建立了存储空间。
  • 2、另一种是不需要建立存储空间的,通过使用extern关键字声明变量名而不定义它。 例如:extern int a 其中变量 a 可以在别的文件中定义的。
  • 除非有extern关键字,否则都是变量的定义。
extern int i; //声明,不是定义
int i; //声明,也是定义
extern int d = 3, f = 5;    // d 和 f 的外部声明与初始化?
int a = 3, b = 5;           // 定义并初始化 d 和 f
byte z = 22;                // 定义并初始化 z
char x = 'x';               // 变量 x 的值为 'x'

没有extern 就是简单的变量定义,加上没有extern 的定义就是外部声明的,也就是说如果当前文件内没有定义和赋值的话,会去外部文件搜索定义实现,不会报错,除非找不到。

# 示例2:引用外部文件函数

入口文件 test_add.c

#include <stdio.h>
  
/*定义两个全局变量*/
int x=1;
int y=2;

/*
当您在一个源文件中定义函数且在另一个文件中调用函数时,函数声明是必需的。在这种情况下,您应该在调用函数的文件顶部声明函数。
这一行不能漏,否则在下面赋值时会报错,error: implicit declaration of function 'addtwonum' is invalid in C99 [-Werror,-Wimplicit-function-declaration]
*/ 
int addtwonum(); // 函数声明

int main(void)
{
    int result;
    result = addtwonum();
    printf("result 为: %d\n",result);
    return 0;
}

addtwonum.c 文件

#include <stdio.h>
/*外部变量声明,当前文件没有定义时就会去外部寻找值*/
extern int x ; 
extern int y ;
int addtwonum()
{
    return x+y;
}

# 运行结果:

// 编译
mac$ gcc addtwonum.c test_add.c -o main_add 
// 执行文件
mac$ ./main_add
// 结果输出
result 为: 3

# 附:外部声明可以在当前实现吗?

1、当前文件如果修改为
extern int x = 4;
extern int y = 7;

会报错,外部test_add.c 定义和实现了这个变量值,这里初始化有问题:
addtwonum.c:3:12: warning: 'extern' variable has an initializer [-Wextern-initializer]
extern int x = 4;
           ^

2、如果当前在定义一下变量:
extern int x ; 
extern int y ;
int x=4;
int y=2;

也是会报错,提示重复定义,因为外部test_add.c 已经定义

duplicate symbol '_y' in:
    /var/folders/84/yp82d91d5jvdwmx6kd1td9640000gn/T/addtwonum-f59002.o
    /var/folders/84/yp82d91d5jvdwmx6kd1td9640000gn/T/test_add-a2b257.o
duplicate symbol '_x' in:
    /var/folders/84/yp82d91d5jvdwmx6kd1td9640000gn/T/addtwonum-f59002.o
    /var/folders/84/yp82d91d5jvdwmx6kd1td9640000gn/T/test_add-a2b257.o
      
3、删掉入口处定义,改在addtwonum.c 定义 也不行
   addtwonum.c:3:12: warning: 'extern' variable has an initializer [-Wextern-initializer]
extern int x = 4;
           ^

# 常量

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

1、使用 #define 预处理器(宏定义)

2、使用 const 关键字

#include <stdio.h>

// 1、使用 **#define** 预处理器 定义常量
#define LENGTH 10   
#define WIDTH  5
#define NEWLINE '\n'
 
int main() {
   //2、const语法格式 定义常量 : const type variable = value;
   const int  LENGTH = 10;
   const int  WIDTH  = 5;
   const char NEWLINE = '\n';

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

# 判断语句

# if-else

// if-elseif-else
int a = 100;
if( a < 20 )
{
   printf("a 小于 20\n" );
  return; // 条件控制,结束当前函数,不再执行 if 语句
}
else if( a < 80 )
{
   printf("a 小于 80\n" );
} 
else
{
   printf("a 大于等于 80\n" );
}

# switch

// 等级分数
char grade = 'A';
switch(grade)
{
case 'A' :
  printf("优秀!\n" );
  break; // 条件控制,结束 switch,继续后面代码
case 'B' :
case 'C' :
  printf("很好\n" );
  break;
default :
  printf("加油\n" );
}

# 循环控制语句

# while

int a = 5;

/* while 循环:先判断括号内条件是否成立,再执行 */
while( a > 0 ) // 当 a <= 0时不满足循环条件,则循环结束
{
  printf("a 的值: %d\n", a);
  a--;
}

# for 循环

/* for 循环 */
for( int a = 0; a < 5; a++ )
{
  printf("a 的值: %d\n", a);
}

# do...while 循环

int a = 5;

/* 和while 循环的区别是:
do-while 循环:先至少执行一次,后面再判断条件
while 循环:先判断条件,条件成立再执行
*/
do {
   printf("a 的值: %d\n", a);
   a--;
}while(a > 0);

# 循环控制语句:break、continue

break: 终止循环或 switch 语句 ,继续后面代码

continue:表示当前循环内的后续代码不执行,直接判断下一次循环条件

/* for 循环 */
for( int a = 100; a > 0; a-- )
{
  printf("a 的值: %d\n", a);
  if (a > 80) {
    continue;
  } 
  
  if (a >= 60) {
    break;
  } 
}

# 循环控制语句:goto

在代码前面加上 “ 标签名:” 格式即可通过名称跳转

⚠️:不建议 c 大量使用goto语句,不好调试。但是在汇编中大量使用类似逻辑

int a = 50;
printf("a 的值: %d\n", a);
if (a > 40) {
  goto ENDIF; // 直接跳转到 ENDIF 执行后面的代码
} 

a += 50;
printf("a 的值: %d\n", a);

ENDIF: printf("if 条件被强制跳出结束 \n");

# 函数

# 函数定义格式

C 语言中的函数定义的一般形式如下:

// 返回类型		方法名称 			参数
return_type function_name( parameter list )
{
  // 方法主体 
  body of the function
}

# 示例:

// 1、没有参数
int zero() 
{
   return 0; 
}

// 2、有参数(参数是值传递),有返回值
int max(int num1, int num2) 
{
   return num1 > num2 ? num1 : num2; 
}

// 3、有参数(参数是值传递),没有返回值
void p_max(int num1, int num2) 
{
   printf("value of max : %d", num1 > num2 ? num1 : num2);
}

// 4、没有参数,没有返回值
void ssyhello() 
{
   printf("hello");
}

// 5、没有函数主体
{
   printf("hello");
}

// 6、有参数(参数是 指针传递)
void swap(int *x, int *y) 
{
  // ...
}

# 函数声明

函数调用前需要先进行函数声明,函数声明会告诉编译器函数名称及如何调用函数。

比如求最大值函数:

int max(int num1, int num2) 
{
   return num1 > num2 ? num1 : num2; 
}

针对上面定义的函数 max(),以下是函数声明:

int max(int num1, int num2);

在函数声明中,参数的名称并不重要,只有参数的类型是必需的,因此下面也是有效的声明:

int max(int, int);

# 函数参数

方式一、值传递 (int a)

将变量(或对象)的值传递给其它函数,函数内拿到的参数对象只能a取值,不能修改a

方式二、指针传递 (int *a)

将变量(或对象)的地址传递给其它函数,函数内拿到的参数对象不仅能取a值,也能修改a

#include <stdio.h>

/* 函数声明 */
void swap(int *x, int *y);

int main ()
{
   /* 局部变量定义 */
   int a = 100;
   int b = 200;
 
   /* 调用函数来交换值
    * &a 表示指向 a 的指针,即变量 a 的地址 
    * &b 表示指向 b 的指针,即变量 b 的地址 
   */
   swap(&a, &b); //通过指针传递方式
 
   return 0;
}

/* 函数实现 */
void swap(int *x, int *y) 
{
  int tmp = *x;
  x = y;
  y = &tmp;
  printf("x: %d; y: %d\n",*x, *y);
}

# 可变数量的参数

有时,您可能会碰到这样的情况,您希望函数带有可变数量的参数,而不是预定义数量的参数。

C 语言为这种情况提供了一个解决方案,它允许您定义一个函数,能根据具体的需求接受可变数量的参数。

下面的实例演示了这种函数的定义。

int func(int, ... )  // 可变数量参数
{
   ...
}
 
int main()
{
   func(2, 2, 3);
   func(3, 2, 3, 4);
}

请注意,函数 func() 最后一个参数写成省略号,即三个点号(...),省略号之前的那个参数是 int,代表了要传递的可变参数的总数。

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

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

现在让我们按照上面的步骤,来编写一个带有可变数量参数的函数,并返回它们的平均值:

# 实例

#include <stdio.h>
#include <stdarg.h>
 
double average(int num,...) // 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));
}

当上面的代码被编译和执行时,它会产生下列结果。应该指出的是,函数 average() 被调用两次,每次第一个参数都是表示被传的可变参数的总数。省略号被用来传递可变数量的参数。

Average of 2, 3, 4, 5 = 3.500000
Average of 5, 10, 15 = 10.000000

# 递归

递归指的是在函数的定义中使用函数自身的方法,并在指定条件下退出。

求数的阶乘:

#include <stdio.h>
 
double factorial(unsigned int i)
{
   if(i <= 1)
   {
      return 1;
   }
   return i * factorial(i - 1);
}

int  main()
{
    int i = 10;
    // 求:10*9....*2*1
    printf("%d 的阶乘为 %.f\n", i, factorial(i));
    return 0;
}

运行结果: 10 的阶乘为 3628800

vuepress使用
C语法Day2-运算

← vuepress使用 C语法Day2-运算→

Theme by Vdoing
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式