首页 > 其他分享 >标准C语言4

标准C语言4

时间:2024-05-05 16:33:06浏览次数:19  
标签:arr 函数 int void C语言 标准 printf 返回值

一、函数

什么是函数:function

​ 函数就是一段具有某一项功能的代码集合,它是C语言中管理代码的最小单位,把具有某项功能的若干行代码封装在函数中方便管理代码且方便重复调用。

函数的分类:

标准库函数:

​ C语言标准委员会为C语言以函数形式提供了一些基础功能,这些函数被封装在libc.so库文件中,使用时需要导入对应的头文件,它们的详细介绍在man手册的第3章节。

系统函数:

​ 操作系统为程序员提供了一些系统API,可以以函数形式调用,但它们不是真正的函数,讲UNIX系统环境编程时会详细讲解,它们的详细介绍在man手册的第2章节。

第三方库函数:

​ 一些公司或开源组织实现的一些常用工具供程序员使用。

​ MD5 、 JSON 序列化反序列化、XML配置文件

自定义函数:

​ 为了更方便的管理、调用代码,降低开发难度,程序员自己封装的一些函数。

常用标准库函数介绍:

​ 标准库中除上封装了函数,还提供一些头文件,里面是对函数的说明。

stdio.h 输入输出相关功能的函数:
int printf(const char *format, ...);
功能:输出数据到终端
format:提示信息+占位符+转义字符组成
...:若干个变量名或数据
返回值:成功输出的字符个数

int scanf(const char *format, ...);
功能:从终端读取数据
format:一般情况下,只需要占位符即可,除了占位符以外的信息,在输入数据时要原样补出。
...:若干个变量的地址
返回值:成功读取的变量个数

int getchar(void);
int putchar(int c);
int puts(const char *s);
stdlib.h 实用的库函数:
int system(const char *command);
功能:调用系统命令,命令执行完成后,该函数才返回
返回值:成功返回0,失败返回-1。
	system("clear");	//	清屏命令

int rand(void);
功能:从系统中获取随机数 0~RAND_MAX
返回值:都是正整数,如果需要负数或浮点数,需要程序员自已处理。

void srand(unsigned int seed);
功能:所谓的随机数就是把所有整数打乱顺序,从某个位置获取,默认从1位置获取,程序运行时如果"位置"不改变,获取随机数与上次一样,为了保证每次运行时,提供的位置都发生变化,一般把time函数的返回值提供给srand作为随机数的种子。
	srand(time(NULL));
    
int abs(int j);
功能:计算并返回j的绝对值
ctype.h 字符类型的判断函数:
int isdigit( int ch );
功能:判断是否是数字字符
int islower( int ch );
功能:判断是否是小写字母
int isupper( int ch );
功能:判断是否是大写字母
time.h 时间日期相关的函数:
time_t time(time_t *tloc);
功能:获取当前系统的时间,返回自 1970年1月1日 00:00:00 到现在一共过了多少秒,格林时间+8小时就是北京时间。
	time(NULL)

struct tm *localtime(const time_t *timep);
功能:把秒数据时间转换成年月日、时分秒
math.h 数学相关的函数 :
double pow(double x, double y);
功能:计算出x的y次数

double sqrt(double x);
功能:计算x的平方根

double ceil(double x);
功能:向上取整,返回大于x的最小整数

double floor(double x);
功能:向下取整,返回小于x的最大整数
注意:使用这些函数在编译时必须有-lm参数 libm.so

自定义函数:

​ 有两情况适合把代码封装成自定义函数:
​ 1、代码量过多,一般代码量超过50行就要考虑封装成函数,方便管理代码,提高代码的安全性(程序员平均每50行会出现一个BUG)。
​ 2、如果一个代码需要在不同位置多次执行,为了防止出现代码冗余,就要把它封装成函数,方便重复使用,也能降低可执行文件的大小。

函数声明:

返回值类型 函数名(参数列表);

​ 1、根据函数的功能为函数取名字,在Linux系统下函数名全部小写,多个单词用下划线分隔。
​ 2、参数列表,指的是函数执行时,调用者需要传递它的数据,此时重点关注的是参数的类型,在函数声明时可以忽略参数的名,如果函数执行时不需要调用者传递数据则写void。

返回值类型 函数名(类型名 形参名1,类型名 形参名2,...);
返回值类型 函数名(int n1,int n2,...);
返回值类型 函数名(void);

​ 3、返回值类型,指的是函数的执行结果是什么类型的数据,如果函数没有返回值,则写void。
​ 4、函数声明就是告诉编译器该函数的格式,方便编译器检查调用者的使用是否正确。

​ 5、一般函数声明放在main函数之前

函数定义:
返回值类型 函数名(类型 参数名) {
    // 函数体
}
// 如果函数的定义出现在调用之前,函数声明可以省略
函数调用:

函数名(实参);

1、调用者会把实参赋值给形参变量。
2、函数的返回值会放置在调用位置,可立即使用,也可用变量保存。

输入两个日期yyyy-mm-dd,计算相差多少天,考虑封装函数
#include <stdio.h>                                                                                                         
#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>
uint32_t date_to_days(uint16_t year,uint8_t month,uint8_t day) {//  计算日期天数函数
    uint32_t sum = day;
    for (int y = 1; y < year; ++y) {
        sum += 365 + is_leap(y);
    }
    char arr[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    arr[1] += is_leap(year);
    for (int m = 0; m < month - 1; ++m) {
        sum += arr[m];
    }
    return sum;
}
bool is_leap(uint16_t year) { //  判断闰平年
    return 0 == year % 4 && 0 != year % 100 || 0 == year % 400;
}
int main() {
    uint16_t y = 0;
    uint8_t m = 0,d = 0;
    printf("请输入一个日期(yyyy-mm-dd)");
    scanf("%hu-%hhu-%hhu",&y,&m,&d);
    uint32_t day = date_to_days(y,m,d);
    printf("请再输入一个日期(yyyy-mm-dd)");
    scanf("%hu-%hhu-%hhu",&y,&m,&d);
    printf("间隔了%d天\n", abs((int)date_to_days(y,m,d)-(int)day));
}
自定义函数要注意的问题:

​ 1、函数的命名空间互相独立,函数之间传参是单向值传递(实参给形参赋值),所以两个函数之间不能通过传参共享变量。

#include <stdio.h>
int func(int num) {
    printf("func:%d\n",num);
    num = 100;
    printf("func:%d\n",num);
    printf("func:%p\n",&num);
    return 0;
}
void swap(int n1, int n2) { //  实现一个交换两个变量的值的函数
    printf("swap:n1:%d n2:%d\n",n1,n2);
    int temp = n1;
    n1 = n2;
    n2 = temp;
    printf("swap:n1:%d n2:%d\n",n1,n2);
}
int main() {
    int num = 10;
    printf("main:%d\n",num);
    printf("main:%p\n",&num);
    func(num);
    printf("main:%d\n",num);
    int num1 = 10,num2 = 20;
    printf("num1:%d num2:%d\n",num1,num2);
    swap(num1,num2);
    printf("num1:%d num2:%d\n",num1,num2);
}                                                                              

​ 2、C语言中如果函数的参数列表是空的,则意味着该函数提供任意类型、多个参数都可以调用,容易给调用者造成误会,影响代码的可读性,如果函数执行时不需要调用者传递数据则参数列表要写void,不要空着。

#include <stdio.h>
int func(void) {
    printf("func\n");
}
int main() {
    func(); 
    //func(10); 
    //func(3.14,10);    
    //func(3.14,"hehe",10);                                  
}

​ 3、如果函数有返回值但没有写return语句,调用该函数时依然有返回值。
​ 当调用一个有返回值的函数时,系统会为调用者和被调用者约定一个空间用于存储返回值,而return语句的作用就是把一个数据存储到这个空间,如果没有写return语句,调用者依然会从共用空间读取返回值,只是读取到的数据是随机的。

#include <stdio.h>
int func(void) {
    //return 10;
}
int main() {
    int num = func();
    printf("%d\n",num);                                      
}

​ gcc -Wall -Werror xxx.c 可以防止漏写return语句。

xxx.c:x:x: error: control reaches end of non-void function [-Werror=return-type]

​ 4、当使用数组作为函数的参数传递时,它的长度信息就丢失了,(数组会蜕变成指针),无法使用sizeof计算数组的长度,需要调用者额外提供一个参数作为数组的长度。

void show_arr(int arr[], size_t len) {
    for (int i = 0; i < len; ++i) {
        printf("%d%c", arr[i], " \n"[i == len - 1]);
    }
}
int main() {
    int arr[] = {1,2,3,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5};
    show_arr(arr,sizeof(arr)/sizeof(arr[0]));
}
练习4:定义一个函数,功能是对一个数组进行升序排序

5、当函数中使用数组作为参数传递是,是"址传递" ,是可以被函数所共享数组

6、当使用二维数组作为函数的参数时,C语言规则定义二维数组时必须有列数,所以要行、列数在前,数组在后,并且把列数设置给数组。

void show_arr(int row, int col, int arr[][col]) {
    for (int i = 0; i < row; ++i) {
        for (int j = 0; j < col; ++j) {
            printf("%d%c", arr[i][j], " \n"[j == col - 1]);
        }
    }
}

int main() {
    int arr[2][5] = { 
        {1,2,3,4,5},
        {2,3,4,5,6}
    };  
    show_arr(2,5,arr);
}

项目;五子棋游戏

数据分析:

​ 1、定义15*15的二维数组,作为棋盘 char ' * ' ' @ ' ' $ '

​ 2、定义记录落子位置的变量

​ 3、定义一个棋子角色变量 char role = '@'

业务逻辑分析:
1、定义15*15的二维数组,作为棋盘 char ' * '  ' @ ' ' $  '
2、定义记录落子位置的变量
3、定义一个棋子角色变量  char role = '@'
 
//	初始化棋盘
void init_board(void);
//	显示棋盘
void show_board(void);
//	落子	如果位置非法,需继续重新落子,直到成功后才能返回
void get_key(void);
//	判断五子连珠
bool is_win(void);

int main() {
    for(;;) {
        1、清理屏幕、显示棋盘
        2、落子
        3、判断是否五子连珠
           是:提示+结束程序
        4、交换角色
    }
}
要求:每个功能实现函数来调用

如何通过方向键控制光标:

    
#include <stdio.h>
#include <getch.h>
#include <stdbool.h>
int dx[] = {-1, 1, 0, 0}, dy[] = {0, 0, 1, -1};
char g[25][25];
void print() {
	system("clear");
	for (int i = 0; i < 15; ++i) {
		for (int j = 0; j < 15; ++j) {
			printf("%c ", g[i][j]);
		}
		puts("");
	}
}
bool win(int x, int y, char c) {
	int c1 = 0, c2 = 0, c3 = 0, c4 = 0;
	for (int i = -2; i <= 2; ++i) if (x + i >= 0 && x + i < 15) {
		c1 += g[x + i][y] == c;
	}
	for (int i = -2; i <= 2; ++i) if (y + i >= 0 && y + i < 15) {
		c2 += g[x][y + i] == c;
	}
	for (int i = -2; i <= 2; ++i) if (y + i >= 0 && y + i < 15 && x + i >= 0 && x + i < 15) {
		c3 += g[x + i][y + i] == c;
	}
	for (int i = -2; i <= 2; ++i) if (x + i >= 0 && x + i < 15 && y - i <= 0 && y - i < 15) {
		c4 += g[x + i][y - i] == c;
	}
	return c1 == 5 || c2 == 5 || c3 == 5 || c4 == 5;
}
bool check() {
	for (int i = 0; i < 15; ++i) {
		for (int j = 0; j < 15; ++j) if (g[i][j] != '*') {
			if (win(i, j, g[i][j])) {
				return false;
			}
		}
	}
	return true;
}
int main() {
	memset(g, '*', sizeof g);
	print();
	int idx = 0, px = 1, py = 1;
	while (check()) {
		printf("\33[%d;%dH", px + 1, py * 2 + 2);
		while (true) {
			int get = getch() - 183;
			if (get + 183 == 10) {
				if (g[px][py] != '*') {
					print();
					printf("该位置上已经落子,请重下\n");
					continue;
				}
				g[px][py] = '0' + idx % 2;
				print();
				break;
			} else {
				px += dx[get], py += dy[get];
				if (px < 0) px = 0;
				if (py < 0) py = 0;
				if (px > 15) px = 14;
				if (py > 15) py = 14;
			}
			printf("\33[%d;%dH", px + 1, py * 2 + 2);
		}
		idx += 1;
	}
	if (idx % 2 == 1) {
		printf("黑子赢啦,共用%d步\n", idx / 2 + 1);
	} else {
		printf("白子赢啦,共用%d步\n", idx / 2);
	}
}

标签:arr,函数,int,void,C语言,标准,printf,返回值
From: https://www.cnblogs.com/sleeeeeping/p/18173609

相关文章

  • 标准C语言3
    一、数组什么是数组:​ 数组就是变量的组合,是一种批量定义变量的方式如何定义数组:类型名数组名[数量]; intarr[8];// 相当于定义了8个int类型的变量 inta1,a2,a3,...;访问数组中的变量:数组名[下标]; 下标从0开始,范围0~数量-1遍历数组:与for循环配合,使用循环变量作......
  • 对C语言符号的一些冷门知识运用的剖析和总结
    符号目录符号注释奇怪的注释C风格的注释无法嵌套一些特殊的注释注释的规则建议反斜杠'\'反斜杠有续行的作用,但要注意续行后不能添加空格回车也能起到换行的作用,那续行符的意义在哪?反斜杠的转义功能单引号和双引号字面值,字符串,字符,字符变量的大小为什么sizeof('1')的大小是4?c......
  • 标准C语言2
    二、常量(了解)​ 常量就是程序运行过程中不能改变的量,C语言中常量有:字面值常量、宏常量、枚举常量。字面值常量100 int100l long100ll longlong100u unsignedint100lu unsignedlong100llu unsignedlonglong定义一个宏常量表示100年总共有多少秒,不考虑闰平年 #defin......
  • C语言 子进程段错误后变成僵尸进程
    空指针获取首元素时出现段错误,子进程异常退出,父进程没有处理。#include<stdio.h>#include<unistd.h>intmain(){pid_tpid;pid=fork();if(pid>0){printf("fatherprocessisPID:%d\n",getpid());while(1){......
  • 标准C语言1
    一、C语言介绍​ 丹尼斯.里奇和肯.汤普逊在1971~1973年美国贝尔实验室,在开发UNIX操作系统时,在BCPL语言的基础上(newB语言),发明第一款高级编程语言,取BCPL第二个字母作为名字,所以叫C语言​ BCPL->newB->C->UNIX->Minix->Linux​ 它是为了开发操作系统而研发的一款编程语言,它特......
  • C语言 父子进程不能共享全局变量
    父子进程不能共享全局变量。父子进程中的任何一方修改了全局变量,只是修改了副本,只对自己可见,对另一方不可见。C语言中即使加了static也不行。#include<stdio.h>#include<unistd.h>//初始值是0intflag;intmain(){pid_tpid;//父进程和子进程执行相同代码即......
  • Go-标准库秘籍(全)
    Go标准库秘籍(全)原文:zh.annas-archive.org/md5/F3FFC94069815F41B53B3D7D6E774406译者:飞龙协议:CCBY-NC-SA4.0前言感谢您给予本书机会!本书是一本指南,带您了解Go标准库的可能性,其中包含了许多开箱即用的功能和解决方案。请注意,本书涵盖的解决方案主要是对标准库实现的简......
  • C语言转写成MIPS指令集汇编以及MIPS指令集汇编中函数调用时栈的变化
    一、问候语欢迎你来到我的博客!二、C语言代码分析  这段C语言代码共有3个函数组成。set_array函数传入1个int类型的变量num,并创建了1个int类型临时变量i和1个临时int类型数组array,里面含有10个单位,此函数主要目的是调用compare函数,并将num和i传入该函数中,得到其函数返回值......
  • 05. C语言数组
    数组用于将多个数据集中存储,方便管理,此文将集中存储任何类型数据的语句都称为数组,数组根据存储数据的类型和方式分为同型数组、结构体、共用体、枚举。 【同型数组】同型数组也直接称为数组,用于存储多个类型相同的数据,数组内的数据称为数组元素,数组元素占用连续的虚拟地址,每个......
  • 浙大版C语言程序设计习题11-17
    点击查看代码typedefstructNODE{intdata;structNODE*next;}NODE,*Linkedlist;//初始化头节点voidInit(Linkedlist&L){L=(NODE*)malloc(sizeof(NODE));L->next=NULL;}//尾插法创建链表LinkedlistCreateFromRear(LinkedlistL){NODE*rear=L;for......