Loading

1002C语言入门专题篇

1.C语言简介及开发环境配置

  • 为什么要学习C语言

C语言诞生于美国的贝尔实验室,是一门面向过程的、抽象化的通用程序设计语言,广泛应用于底层开发。

创始时间:1972年。

创始人:丹尼斯·里奇,C语言之父,UNIX之父。

  • C语言应用领域

系统软件

驱动程序

数据库

图像处理/办公软件

嵌入式软件开发

游戏软件开发

  • 学习C语言的好处

物联网开发、嵌入式软件开发

Linux系统内核开发

Linux驱动与应用开发

研究算法、数据结构必学语言

学习C++/Java/Python等入门语言

  • Hello World
#include <stdio.h>  // C语言标准输入输出头文件

int main()  // 程序的入口函数
{
	printf("Hello World!\n");  // 输出字符串

	return 0;
}
# linux平台下
cd ~/Desktop
mkdir 2022
cd 2022
vim helloworld.c
#include <stdio.h>

int main()
{
	printf("Hello World!\n");

	return 0;
}
# 保存退出
gcc helloworld.c -o helloworld
./helloworld  # 执行

2.C语言基础语法及程序结构

  • 简单C程序结构

预处理命令

变量,语句

表达式

注释:(块注释/**/,行注释//)

#include <stdio.h>  /* 预处理命令 */

int main()  // 主函数,程序就是从此开始执行
{
	int x = 10;  // 定义x为整型变量,且赋值为10

	printf("x=%d\n", x);  // 输出x变量的值

	x = 89;

	printf("x=%d\n", x);

	// 以分号结尾的都称为语句

	x = x + 100;

	printf("x=%d\n", x);

	return 0;  // 返回值,终止main()函数标记
}
  • C语言标识符

C语言标识符命名规则:C语言标识符是用来标识变量、函数或任何其他用户自定义项目的名称。一个标识符只能以字母A-Z或a-z、数字和下划线组成,第一个字符必须字母或下划线开头。

C语言区分大小写字母。

  • C语言关键字

C语言中的保留字共计32个,这些保留字不能作为常量名、变量名或其他标识符名称。C99新增5个,C11新增7个。

auto break case char const continue default do double else enum 
extern float for goto if int long register return short signed 
sizeof static struct switch typedef unsigned union void volatile while
#include <stdio.h>

int main()
{
	int iNumber = 120;

	printf("结果:%d\n", iNumber);

	return 0;
}

/*
int      %d
long     %ld
float    %f
double   %lf
char     %c
*/
// C99新增关键字
_Bool _Complex _Imaginary inline restrict
// C11新增关键字
_Alignas _Alignof _Atomic _Generic _Noreturn _Static_assert _Thread_local

3.C语言数据类型及输入输出函数

  • C语言数据类型

所谓类型,就是对数据分配存储单元的安排,包括存储单元的长度(占多少字节)以及数据的存储形式不同的类型分配不同的长度和存储形式。

C语言允许使用的数据类型

基本类型:

整型类型:基本整型、短整型、长整型、双长整型、字符型、布尔型

浮点类型:单精度浮点型、双精度浮点型、复数浮点型

C语言允许使用的数据类型:

基本类型、枚举类型、空类型

派生类型:

指针类型、数组类型、结构体类型、共用体类型、函数类型

整型数据类型的分类:

基本整型(int型):占2个或4个字节

短整型(short int):VC++6.0中占2个字节

长整型(long int):VC++6.0中占4个字节

双长整型(long long int):C99新增的

#include <stdio.h>

int main()
{
	// 求字节
	printf("int=%d\n", sizeof(int));  // 4

	printf("short int=%d\n", sizeof(short));  // 2

	return 0;
}

整型变量的符号属性:

整型变量的值的范围包括负数到正数

可以将变量定义为“无符号”类型

扩充的整型类型:

有符号基本整型 [signed] int;

无符号基本整型 unsigned int;

有符号短整型 [signed] short [int];

无符号短整型 unsigned short [int];

有符号长整型 [signed] long [int];

无符号长整型 unsigned long [int];

有符号双长整型 [signed] long long [int];

无符号双长整型 unsigned long long [int];

字符型数据

字符是按其代码(整数)形式存储的,C99把字符型数据作为整数类型的一种,字符型数据在使用上有自己的特点。

字符与字符代码:大多数系统采用ASCII字符集

#include <stdio.h>

int main()
{
	// 输出对象ASCII码
	printf("%d\n", 'A');

	printf("%c\n", 49);  // 1

	return 0;
}

字符'1'只是代表一个形状为'1'的符号,在需要的时候按原样输出,在内存中以ASCII码形式存储于,占1个字节。

整数1是以整数存储方式(二进制补码方式)存储的,占2个或4个字节。

字符变量:

char定义字符变量

浮点型数据:

浮点型数据是用来表示具有小数点的实数

float型(单精度浮点型),编译系统为float型变量分配4个字节,数值以规范化的二进制指数形式存放

double型(双精度浮点型),编译系统为double型变量分配8个字节,15位有效数字

long double(长双精度)型

怎样确定常量的数据类型:

字符常量:由单引号括起来的单个字符或转义字符

整型常量:不带小数点的数值,系统根据数值的大小确定是int型还是long型

浮点型常量:凡是以小数形式或指数形式出现的实数,C编译系统把浮点型常量都按照双精度处理,分配8个字节

  • 输入输出函数

几乎每一个C程序都包含输入输出,输入输出是程序中最基本的操作之一

所谓输入输出是以计算机为主体而言的

C语言本身不提供输入输出语句

在使用输入输出函数时,要在程序文件的开头用预编译指令#include <stdio.h>#include "stdio.h"

在C程序中用来实现输出和输入的,主要是printf函数和scanf函数

常用格式符:d格式符用来输出一个有符号的十进制整数、c格式符用来输出一个字符、s格式符用来输出一个字符串、f格式符用来输出实数,以小数形式输出,指定数据宽度和小数位数。用%m.nf,输出的数据向左对齐,用%-m.nf,float型数据只能保证6位有效数字,double型数据能保证15位有效数字、e格式符:指定以指数形式输出实数,VC++给出小数位数为6位,指数部分占5列,小数点前必须有而且只有1位非零数字

#include <stdio.h>

int main()
{
	int x = 89, y = 90;

	printf("x=%d, y=%d\n", x, y);

	printf("%10d\n", x);

	printf("%s\n", "ABCD");

	printf("%6.3f\n", 2.01);
    
    printf("%e\n", 12.3521);

	return 0;
}

scanf函数的一般形式:scanf(格式控制,地址列表),地址列表可以是变量的地址,或字符串的首地址

#include <stdio.h>

int main()
{
	int aa, bb, cc;

    // 从vc++2005开始,VS系统提供了scanf_s()
	scanf_s("aa=%d,bb=%d,cc=%d", &aa, &bb, &cc);  

	printf("aa=%d, bb=%d, cc=%d", aa, bb, cc);
    
	printf("aa=%d, bb=%d, cc=%d", aa, bb, cc);

	return 0;
}

字符数据的输入输出

用putchar函数输出一个字符

#include <stdio.h>

int main()
{
	putchar('B');
	putchar('O');
	putchar('Y');

	char c1, c2, c3;

	c1 = getchar();
	c2 = getchar();
	c3 = getchar();

	printf("\n%c%c%c\n", c1, c2, c3);

	return 0;
}

4.C语言常量与变量

  • 变量

即在程序运行过程中,其值可以改变的量,称为变量。

C语言变量其实是程序可操作的存储区的名称。C语言中每个变量都有特定的类型,类型决定变量存储的大小和布局,该范围内的值都可以存储在内存中,运算法可应用于变量上。

变量的命名规则:由字母、数字和下划线组成,必须以字母或下划线开头。大写字母和小写字母是不同的,因为C是大小写敏感的。

#include <stdio.h>

int main()
{
	int x1, x2, sum;

	x1 = 78;
	
	x2 = 90;

	sum = x1 + x2;

	printf("sum=%d\n", sum);

	return 0;
}
  • 常量

在程序运行过程中,其值不能改变的量,称为常量。

常量可以是任何的基本数据类型,比如整数常量、浮点常量、字符常量或字符串字面值,也有枚举常量。

整数常量:

整数常量可以是十进制、八进制或十六进制的常量,前缀指定基数:0x或0X表示十六进制,0表示八进制,不带前缀则默认表示十进制

整数常量可以带一个后缀,后置U和L的组合,U表示无符号整数(unsigned),L表示长整数(long)。后缀可以是大写,也可以是小写,U和L的顺序任意。

浮点常量:

浮点常量是由整数部分、小数点、小数部分和指数部分组成。您可以使用小数形式或指数形式来表示浮点常量。

当使用小数形式表示时,必须包含整数部分、小数部分,或者同时包含两者。当使用指数形式表示时,必须包含小数点、指数。带符号的指数是用e或E引入的。

字符常量:

字符常量是括在单引号中,字符常量可以是一个普通的字符,也可以是一个转义序列,例如\t

字符串常量:

字符串字面值或常量是括在双引号中的,一个字符串包含类似于字符常量的字符:普通的字符、转义序列和通用的字符。

定义常量:

#define预处理器:使用#define预处理器定义常量的形式:#define identifier value

const关键字:使用const前缀声明指定类型的changlaing:const type variable=value;

#include <stdio.h>

#define PI 3.14159

const int ivar = 1000;

int main()
{
	double r = 10, s = 0;

	s = PI * r * r;

	printf("s=%lf\n", s);

	printf("ivar=%d\n", ivar);

	return 0;
}

5.运算符及存储类型

  • 运算符

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

算术运算符

关系运算符

逻辑运算符

位运算符

赋值运算符

其它运算符

算术运算符:

+ - * / % ++ --

#include <stdio.h>

int main()
{
	/*
	算术运算符:+ - * / % ++ --
	++在变量前面,先加1后运算,否则先运算后加1
	*/

	int x = 5, y = 6;

	printf("x+y=%d\n", x + y);
	printf("x-y=%d\n", x - y);
	printf("x*y=%d\n", x * y);
	printf("x/y=%d\n", x / y);  // 0
	printf("y/x=%d\n", y / x);  // 1,整数与整数算术除法运算,整除
	printf("y%%x=%d\n", y % x);
	printf("x%%y=%d\n", x % y);

	int a = 10;

	printf("a=%d\n", a++);
	printf("a=%d\n", ++a);
	printf("a=%d\n", a);

	int k = 6;
	printf("k=%d\n", k--);
	printf("k=%d\n", --k);
	printf("k=%d\n", k);
	return 0;
}

关系运算符:

== != > < >= <=

#include <stdio.h>

int main()
{
	/*
	关系运算符
	== != > < >= <=
	*/

	printf("4 == 4结果为:%d\n", 4 == 4);  // 1
	printf("4 != 4结果为:%d\n", 4 != 4);  // 0
	printf("4 > 4结果为:%d\n", 4 > 4);  // 0
	printf("4 < 4结果为:%d\n", 4 < 4);  // 0
	printf("4 >= 4结果为:%d\n", 4 >= 4);  // 1
	printf("4 <= 4结果为:%d\n", 4 <= 4);  // 1
	return 0;
}

关系运算符:

&& || !

#include <stdio.h>

int main()
{
	/*
	逻辑运算符
	&& || !
	*/

	printf("3 > 5 && 4 < 9Result=%d\n", 3 > 5 && 4 < 9);
	printf("3 > 5 || 4 < 9Result=%d\n", 3 > 5 || 4 < 9);
	printf("! (3 > 5)Result=%d\n", ! (3 > 5));

	return 0;
}

位运算符:

& | ^ ~ << >>

#include <stdio.h>

int main()
{
	/*
	位运算符
	& | ^ ~ << >>
	*/

	printf("3 & 5 Result=%d\n", 3 & 5);
	printf("3 | 5 Result=%d\n", 3 | 5);
	printf("3 ^ 5 Result=%d\n", 3 ^ 5);
	printf("~ 3 Result=%d\n", ~ 3);
	printf("3 << 1 Result=%d\n", 3 << 1);
	printf("3 >> 1 Result=%d\n", 3 >> 1);

	return 0;
}

赋值运算符:

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

其它运算符:

sizeof()返回变量的大小

&返回变量的地址

*指向一个变量

?条件表达式,如果条件为真?则值为X : 否则值为Y

#include <stdio.h>

int main()
{
	/*
	其他运算符
	sizeof * & ?
	*/

	int c = 60;
	int *d_c = &c;
	printf("占据字节为:%d\n", sizeof(c));
	printf("占据字节为:%d\n", sizeof(double));
	printf("a在内存中的地址为:%p\n", &a);
	printf("d_c为:%p\n", d_c);  // 00EFFD04
	printf("*d_c为:%d\n", *d_c);  // 60
	printf("40 > 30 ? 100 : 200 Result:%d\n", 40 > 30 ? 100 : 200);
	return 0;
}
  • 存储类型

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

auto

register

static

extern

auto存储类:

auto存储类是所有局部变量默认的存储类,auto只能用在函数内,即auto只能修饰局部变量。

{

​ int a; // 可省略auto

​ auto int b;

}

register存储类:

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

{

​ register int a;

}

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

static存储类:

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

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

全局声明的一个static变量或方法可以被任何函数或方法调用,只要这些方法出现在static变量或方法同一个文件中。

extern存储类:

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

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

#include <stdio.h>

void FuncTest();
static int k = 10;  // 全局变量 static是默认的

void FuncTest()
{
	static int x = 5;  // 如果不加static修饰,每次调用x都是5
	x++;
	printf("x=%d, k=%d\n", x, k);
}

int main()
{
	while (k--)
	{
		FuncTest();
	}

	return 0;
}
#include <stdio.h>

extern int count;
void func()
{
	printf("count is : %d\n", count);
}
#include <stdio.h>

int count;
extern void func();

int main()
{
	count = 10;
	func();

	return 0;
}

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

6.if语句及switch语句

  • if语句
#include <stdio.h>


int main()
{
	// 判断一个数字是否大于等于0

	int x;

	printf("请输入x的值:\n");

	scanf_s("%d", &x);

	if (x >= 0)
		printf("x大于等于0\n");

	// 判断你是否成年
	
	int age;

	printf("请输入你的年龄:\n");

	scanf_s("%d", &age);

	if (age >= 18)
		printf("成年\n");
	else
		printf("未成年\n");

	if (age >= 18)
	{
		printf("成年\n");
		printf("多条语句使用花括号\n");
	}
	else
	{
		printf("未成年\n");
		printf("多条语句使用花括号\n");
	}

	// 从键盘输入一个字符,然后判断这个字符是大写字母还是小写字母,或者数字
	char c;

	printf("请输入c的值:\n");

	/*
	表面上看这段程序是没有错的,也可以运行,但运行过程中到第二个scanf输入值给ch2时,
	程序不会停止,而是直接运行到最后一个printf !       
	原来scanf是从标准输入缓冲区中读取输入的数据,而%c的字符输入格式会接收回车字符,
	在输入第一个scanf时输入字符后按回车结束,输入缓冲中保存了这个回车符,
	遇到第二个scanf时,它自动把这个回车符赋给了ch2。
	而如果第二个scanf的输入格式不是%c时,由于格式不匹配,这个回车符会被自动忽略,
	所以只有在连续输入两个scanf且第二个是%c的格式时才会出现这样的问题!
	*/
	fflush(stdin);  // 清空缓冲区
	scanf_s(" %c", &c, 1);

	if (c < 32)
		printf("这是一个控制符\n");
	else if (c >= '0' && c <= '9')
		printf("这是一个数字\n");
	else if (c >= 'a' && c <= 'z')
		printf("这是一个小写字母\n");
	else if (c >= 'A' && c <= 'Z')
		printf("这是一个大写字母");
	else
		printf("其他字符\n");
	printf("main函数结束\n");

	return 0;
}
  • switch语句
#include <stdio.h>

int main()
{
	// 使用switch语句实现,从键盘输入1-7分别输出星期一到星期日英文单词

	int x;

	printf("请输入星期数字1-7:\n");

	scanf_s("%d", &x);

	switch (x)
	{
	case 1:printf("Monday\n"); break;
	case 2:printf("Tuesday\n"); break;
	case 3:printf("Wednessday\n"); break;
	case 4:printf("Thursday\n"); break;
	case 5:printf("Friday\n"); break;
	case 6:printf("Saturday\n"); break;
	case 7:
	{
		printf("Sunday\n");
		printf("多行\n");
		break;
	}
	default:
		printf("输入错误 \n");
	}

	return 0;
}

7.while循环与for循环

  • while语句
#include <stdio.h>

int main()
{
	int i = 1, sum = 0;

	while (i <= 5)
	{
		sum += i;
		if (i == 3)
			break;
		i++;
	}

	printf("结果为:%d\n", sum);

	do
	{
		printf("%d\n", i);
		sum += i;
		i++;
		if (i == 8)
			continue;
	} while (i <= 10);

	printf("结果为:%d\n", sum);

	return 0;
}
  • for语句
#include <stdio.h>

int main()
{
	int i = 1, sum = 0;

	for (; i <= 100; i++)
	{
		sum += i;
	}

	printf("结果为%d\n", sum);

	int sum2 = 0;

	for (int j = 0; j <= 100; j++)
	{
		if (j == 50)
			continue;
		if (j == 99)
			break;
		for (int k = 0; k <= 3; k++)
		{
			printf("%d\n", k);
			if (k == 2)
				break;
		}
		sum2 += j;
	}

	printf("结果为%d\n", sum2);

	return 0;
}

8.数组

  • 一维数组

数组是一组有序数据的集合。数组中各数据的排列是有一定规律的,下标代表数据在数组中的序号。用一个数组名和下标唯一确定数组中的元素,数组中的每一个元素都属于同一个数据类型。

定义一维数组的一般形式为:类型符 数组名[常量表达式]int a[10]

int n = 10;

int a[n]; // 不合法,定义的时候必须是常量表达式

在定义数组并对其各元素赋值后,就可以引用数组中的元素,注意:只能引用数组元素而不能一次整体调用整个数组的全部元素的值。

#include <stdio.h>

int main()
{
	int a[10];  // 定义一个一维数组

	for (int i = 0; i < 9; i++)
		printf("a[%d]的地址为:%p\n", i, &a[i]);

	// int b[5] = { 10, 20, 30, 40, 50 };
	// int b[] = { 10, 20, 30, 40, 50 };
	// int b[5] = { 0 };
	// int b[5] = { 10, 20 };  // { 10, 20, 0, 0, 0 }
	int b[5];  // {-858993460, -858993460, -858993460, -858993460, -858993460}

	for (int j = 0; j < 4; j++)
	{
		printf("%p\n", b);  // 我们打印输出数组名,就是输出整个数组首地址
		printf("b[%d]的为:%d\n", j, b[j]);
		printf("b[%d]的地址为:%p\n", j, &b[j]);
	}

	return 0;
}
#include <stdio.h>
int main()
{
	int a[5] = { 0 };

	printf("请输入数组a的值:\n");

	for (int i = 0; i < 5; i++)
	{
		scanf_s("%d", &a[i]);
	}

	printf("输出数组a的元素值:\n");

	int max_num = 0;

	for (int i = 0; i < 5; i++)
	{
		if (a[i] > max_num)
			max_num = a[i];
		printf("%5d", a[i]);
	}
		
	printf("\n");
	printf("最大值为:%d\n", max_num);

	return 0;
}
  • 二维数组

二维数组定义的一般形式为:

类型符 数组名[常量表达式][常量表达式] float a[3][4]

二维数组可被看作是一种特殊的一维数组:它的元素又是一个一维数组。

#include <stdio.h>

int main()
{
	// 二维数组的初始化
	int a[3][4] = { {1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12} };
	int b[3][4] = { {1}, {5}, {9} };  // 等价于 { {1, 0, 0, 0} , {5, 0, 0, 0}, {9, 0, 0, 0} }
	int c[3][4] = { {1}, {5, 6} };  // 等价于{ {1}, {5, 6}, {0} }
	int d[3][4] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 };  // 等价于int d[][4] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};

	return 0;
}
#include <stdio.h>
int main()
{
    // 行列互换
	int a[2][3] = { 10, 20, 30, 40, 50, 60 };
	int b[3][2];
	
	for (int i=0; i < 2; i++)
	{
		for (int j = 0; j < 3; j++)
		{
			b[j][i] = a[i][j];
		}
	}

	for (int k = 0; k < 3; k++)
	{
		for (int v = 0; v < 2; v++)
		{
			printf("%5d", b[k][v]);
		}
		printf("\n");
	}

	return 0;
}
  • 字符数组

用来存放字符数据的数组是字符数组,字符数组中的一个元素存放一个字符。定义字符数组的方法与定义数值类型数组的方法类似。char c[10]

字符串和字符串结束标志:

在C语言中,是将字符串作为字符数组来处理的,关心的是字符串的有效长度而不是字符数组的长度,为了测定字符串的实际长度,C语言规定了字符串结束标志'\0',代表ASCII码为0的字符。

从ASCII码表可以查到,ASCII码为0的字符不是一个可以显示的字符,而是一个空操作符,即它什么也不做,用它作为字符串结束标志不会产生附加的操作或增加有效字符,只起一个供辨别的标志。

字符数组的输入输出:

字符数组的输入输出可以有两种方法:逐个字符输入输出(%c),整个字符串一次输入输出(%s)。

输出的字符串中不包括结束符'\0',用%s输出字符串时,printf函数中的输出项是字符数组名,不是数组元素名,如果一个字符数组中包含多个'\0',则遇第一个'\0'时输出就结束。

可以使用scanf_s函数输入一个字符串,scanf_s函数中的输入项c是已定义的字符数组名,输入的字符串应短于已定义的字符数组的长度。

char c[6];

scanf_s("%s", c); // China,系统会自动在China后面加一个'\0'

#include <stdio.h>

int main()
{
	char s[10] = { 'I', ' ', 'a', 'm', '.' };

	for (int i = 0; i < 10; i++)
		printf("%c", s[i]);

	printf("\n");

	return 0;
}
#include <stdio.h>

int main()
{
	char s[50] = "I am Happy.";

	printf("%s\n", s);

	for (int i = 0; i < 50; i++)
		printf("%c", s[i]);

	printf("\n");

	return 0;
}
#include <stdio.h>
#include <string.h>

int main()
{
	char s[50];
	s[49] = '\0';  // 消除可能没有为字符串"XXX"添加字符串零终止符的警告

	printf("请输入字符串s:\n");

	scanf_s("%s", s, strlen(s));

	printf("输入的字符串为:%s\n", s);

	return 0;
}

字符串处理函数:

在C语言函数库中提供了一些专门用来处理字符串的函数,使用方便。

puts函数:输出字符串的函数,puts(字符数组)

gets函数:输入字符串的函数,gets(字符数组)

strcat函数:字符串连接函数,strcat(字符数组1, 字符数组2),程序头添加#include <string.h>

strcpy和strncpy函数:字符串复制,strcpy(字符数组1, 字符串2),将字符串2复制到字符数组1中

strcmp函数:字符串比较函数(ASCII码进行比较),strcmp(字符串1, 字符串2)

strlen函数:计算字符串长度的函数,strlen(字符数组),它计算的是字符串长度中的实际长度。

strlwr函数:转换为小写的函数,strlwr(字符串)

strupr函数:转换为大写的函数,strupr(字符串)

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

int main()
{
	char s[50] = {0};
	gets_s(s, strlen(s)-1);  // 已经添加1个字符串零终止符
	puts(s);

	char s2[50] = {0};
	gets_s(s2, strlen(s2)-1);
	puts(s2);

	return 0;
}
#include <stdio.h>
#include <string.h>

int main()
{
	char s1[50] = "I am ";
	char s2[10] = "a student";

	// strcat_s第二个参数的计算,该参数是拼接后的字符串大小,并非原字符串大小或者目标字符串大小
	// 问题出现在对strlen()的使用,这个函数计算的字符串长度是不包括'\0’的,所以在设置第二个参数(缓冲区长度)时,就会出现异常
	strcat_s(s1, strlen(s1) + strlen(s2) + 1, s2);

	printf("拼接结果为:%s", s1);

	return 0;
}
#include <stdio.h>
#include <string.h>

int main()
{
	char s1[50] = "I am ";
	char s2[10] = "a student";

	strcpy_s(s1, strlen(s2)+1, s2);

	printf("复制结果为:%s", s1);

	return 0;
}
#include <stdio.h>
#include <string.h>

int main()
{
	char s1[50] = "I am ";
	char s2[10] = "a student";

	strcpy_s(s1, strlen(s2)+1, s2);

	strncpy_s(s1, strlen(s2), s2, 5);

	printf("复制结果为:%s", s1);

	return 0;
}
int main()
{
	char s1[50] = "I am  ";
	char s2[10] = "I am ";

	/*
	字符串1 < 字符串2    -1
	字符串1 > 字符串2    1
	字符串1 = 字符串2    0
	*/

	printf("%d", strcmp(s1, s2));
    
    printf("字符串长度%d\n", strlen(s1));
    
    printf("字符数组占据空间%d\n", sizeof(s1));
    
	return 0;
}
int main()
{
	char s3[50] = "dsadasASdA";
	_strlwr_s(s3, strlen(s3)+1);
	printf("%s\n", s3);

	_strupr_s(s3, strlen(s3) + 1);
	printf("%s\n", s3);

	return 0;
}

9.函数

  • 函数的定义与调用

C语言要求,在程序中用到的所有函数,必须”先定义 ,后使用“。

指定函数名字、函数返回值类型、函数实现的功能以及参数的个数与类型,将这些信息通知编译系统。

指定函数的名字,以便以后按名调用。指定函数类型,即函数返回值的类型。指定函数参数的名字和类型,以便在调用函数时向它们传递数据。指定函数的功能,这是最重要的,这是在函数体中解决的。

对于库函数,程序设计者只需用#include指定将有关的头文件包含到本文件模块中即可,程序设计者需要在程序中定义自己想用的而库函数并没有提供的函数。

定义无参函数:

类型名 函数名()

{

​ 函数体

}

定义有参函数:

类型名 函数名(形式参数列表)

{

​ 函数体

}

定义空函数:先用空函数站一个位置,以后逐步扩充,好处:程序结构清楚,可读性好,以便以后扩充新功能方便,对程序结构影响不大。

类型名 函数名()

{

}

函数调用:

函数名(实参列表)

如果是调用无参函数,则“实参列表”可以没有,但括号不能省略。如果实参列表包含多个实参,则各参数间用逗号隔开。

函数调用的过程:

在定义函数中指定的形参,在未出现函数调用时,它们并不占内存中的存储单元,在发生函数调用时,函数的形参被临时分配内存单元。

1)函数的返回值是通过函数中的return语句获得的

2)函数值的类型,应当在定义函数时指定函数值的类型

3)在定义函数时指定的函数类型一般应该和return语句中的表达式类型一致

#include <stdio.h>

void func1(void)
{
	printf("Hello world!\n");
}

int func2(int x, int y)
{
	printf("sum=%d\n", x + y);

	return x + y;
}

int main()
{
	// 调用无参函数
	func1();

	// 调用有参函数
	int sum = func2(25, 45);

	printf("sum=%d\n", sum);

	return 0;
}
  • 函数的嵌套调用

C语言的函数定义是互相平行、独立的,即函数不能嵌套定义,但可以嵌套调用函数,即调用一个函数的过程中,又可以调用另一个函数

#include <stdio.h>

int maxx(int a, int b, int c, int d);
int maxy(int x, int y);

int main()
{
	int a, b, c, d, m;

	printf("请输入四个整数:\n");

	scanf_s("%d%d%d%d", &a, &b, &c, &d);

	m = maxx(a, b, c, d);

	printf("最大值为:%d\n", m);

	return 0;
}

int maxx(int a, int b, int c, int d)
{
	int m;
	m = maxy(a, b);
	m = maxy(m, c);
	m = maxy(m, d);

	return m;
}

int maxy(int x, int y)
{
	return x > y ? x : y;
}
  • 函数的递归调用

在调用一个函数的过程中又出现直接或间接地调用该函数本身,称为函数的递归调用。C语言的特点之一就在于允许函数的递归调用。

#include <stdio.h>

int ageFunc(int n)
{
	int age = 0;
	if (n == 1)
		return 10;
	else
		return ageFunc(n - 1) + 2;
}

int main()
{
	printf("第5个人的年龄为:%d\n", ageFunc(5));

	return 0;
}
  • 数组作为函数参数

除了可以用数组元素作为函数参数外,还可以用数组名作为函数参数(包括实参和形参)

用数组元素作实参时,向形参变量传递的是数组元素的值

用数组名作函数实参时,向形参传递的是数组首元素的首地址

#include <stdio.h>

double averageFunc(double a[10])
{
	double aver, sum = a[0];

	for (int i = 1; i < 10; i++)
		sum += a[i];

	aver = sum / 10;

	return aver;
}


int main()
{
	double score[10], aver = 0;

	printf("请输入10个学生的成绩:\n");

	for (int i = 0; i < 10; i++)
		scanf_s("%lf", &score[i]);

	printf("\n");

	aver = averageFunc(score);

	printf("平均成绩为:%lf", aver);

	return 0;
}
  • 局部变量与全局变量

定义变量可能有三种情况:

在函数的开头定义:

在一个函数内部定义的变量只在本函数范围内有效

在函数内的复合语句内定义:

在复合语句内定义的变量只在本复合语句范围内有效

在函数的外部定义:

在函数内部或复合语句{}内部定义的变量称为“局部变量”

在函数内定义的变量时局部变量,而在函数之外定义的变量称为外部变量。

外部变量时全局变量,也成全程变量。

全局变量可以为本文件中其他函数所共用。

有效范围为从定义变量的位置开始到本文件结束。

  • 内部函数

如果一个函数只能被本文件中其他函数所调用,它称为内部函数。在定义内部函数时,在函数名和函数类型的前面加static,即static 类型名 函数名(形参列表)

内部函数又称静态函数,因为它是用static声明的;

通常把只能由本文件使用的函数和外部变量放在文件的开头,前面都冠以static使之局部化,其他文件不能引用,提高了程序的可靠性。

  • 外部函数

如果在定义函数时,在函数首部的最左端加上关键字extern,则此函数是外部函数,可供其他文件调用。

extern int func(int a, int b)

如果在定义函数时省略extern,则默认为外部函数。

// outer.c
#include <stdio.h>

void funcExternTest2(char a[50])
{
	printf("%s\n", a);
}
// demo.c
#include <stdio.h>
#include <string.h>

extern void funcExternTest2(char a[50]);

int main()
{
	char s[50] = {'\0'};

	printf("请输入任意一句话:\n");

	scanf_s("%s", &s, strlen(s)-1);

	funcExternTest2(s);

	return 0;
}
posted @ 2022-12-18 11:01  lotuslaw  阅读(13)  评论(0编辑  收藏  举报