C语言练习——基础篇

细节语法问题

结构体定义

只能用数字定义数组
在这里插入图片描述
在这里插入图片描述

return可以带括号吗?

可以带
在这里插入图片描述

初始化变量

不可以同时给两个变量初始化并赋值
在这里插入图片描述

字符串输出

printf("%s", A);直接输入数组名,使用%s即可输出。
在这里插入图片描述

string头文件

get() gets() put() puts()是包含在stdio.h中
而其他的字符串函数,如strlen()等,是包含在string.h中

scanf()与gets()

输入“Hello world!”,scanf()函数取数据遇到回车、空格、TAB就会停止,一旦出现空格,后面的数据就会舍弃残留在缓冲区中。

gets()函数则可以接受空格,所以如果要读入一个带空格符的字符串时因该用gets(), 而不宜用scanf().

对于输出而言puts() printf()都可以输出带空格的字符。

结尾的逗号

结构体要加逗号结尾,函数可加可不加。
在这里插入图片描述

数字分解到数组

C语言用scanf()只能接收一个数字,而不能一次接收一次键盘输入。
如输入“1234”,接收到的就是1234;而不能将1、2、3、4直接依次接收到数组中。要对其进行分解。代码如下:

scanf("%d",&n);
A[0]=m%10;//取个位
A[1]=n%100/10;//先取最后两位,再取十位
A[2]=n%1000/100//先取最后三位,再取百位
A[3]=n/1000;//直接取最高位(n%10000/1000)

基础阶段

一,判断闰年

闰年有两种:4的倍数,但不是100的倍数;400的倍数。代码如下
a%b==0 b能被a整除、b是a的因子(约数)、a是b的倍数
而闰年的计算中,只涉及到倍数,由此只需要用%计算。

if((i%4==0&&i%100!=0)||i%400==0)
{
	printf("%d是闰年",i);
}

二,大小写字母转换

n-‘a’+‘A’,先减去a,代表是第几个字母,然后从A开始往后加,转换为对应的大写字母。

printf(n-'a'+'A');//小写转大写
printf(n-'A'+'a');//大写转小写

字符:类似’a’,只包含一个字母的。区别于字符串。

三,面积计算

计算三角形面积

三角形面积等于对于平行四边形面积的一半,也就是叉积的一半。
在这里插入图片描述
叉积的面积带有的了方向信息,根据正负值判断是左右系。
在这里插入图片描述
在这里插入图片描述

代码
#include<stdio.h>
#include<math.h>

//定义三角形结构体
typedef struct {
	double x;
	double y;
}triangle;

double Area(triangle A[]) {
	double Area = 0;
	Area = fabs((A[0].x - A[1].x)*(A[2].y -A[1].y) - (A[2].x - A[1].x) * (A[0].y - A[1].y));
	return Area / 2;
}
//坐标必须按顺时针输入,否则要加绝对值
int main() {
	triangle a1[3] = { { 2, 0 }, { -2, 0 }, { 0, 8 }};
	printf("A1 Area:%f\n", Area(a1));
	return 0;
}

计算多边形面积

Sp1p2p3=pp2p3+pp3p1-pp1p2(面积取负值,必须顺时针输入坐标)
以后计算的时候直接取原点,简化计算步骤
在这里插入图片描述
从1开始加到n,最后一次n直接到1,减去了面积
在这里插入图片描述

代码

编写程序计算以下节点围成的两个多边形的面积
在这里插入图片描述

#include<stdio.h>
//定义多边形结构体
typedef struct {
	double x;
	double y;
}polygon;

double Area(polygon A[], int n) {
	double Area = 0;
	for (int i = 0; i < n; ++i) {
		if (i < n - 1)
			Area += A[i].x * A[i + 1].y - A[i + 1].x * A[i].y;
		else
			Area += A[n - 1].x * A[0].y - A[0].x * A[n - 1].y;
	}
	
	return Area / 2;
}
//坐标必须按顺时针输入,否则要加绝对值
int main() {
	polygon p1[6] = { { 4, 6 }, { -4, 6 }, { -4, -8 }, { 8, -8 }, { 8, -4 }, { 4, -4 } };
	polygon p2[5] = { { 3, 4 },{ 5, 6 } , { 9, 5 }, { 12, 8 }, { 5, 11 } };

	printf("P1 Area:%f\n", Area(p1, 6));
	printf("P2 Area:%f\n", Area(p2, 5));
	return 0;
}

四,加密问题

输入一个由字母组成的字符串,加密:用原字母后第四个字母代替原字母。
1,用数组处理字符串
2,处理越界问题:z加密后变为d
对z求余,使得+4越界的字母转换为从a开始计数
对a求余,使得没有越界的也转换为从啊开始计数
最后统一+a,即可全部转换
a[i] = ((a[i] + 4) % ‘z’ % ‘a’) + ‘a’;
a[i] = ((a[i] + 4) % ‘Z’ % ‘A’) + ‘A’;
3,用putchar和printf输出
两者都可以输出,前者一次只能输出一个字符。
在这里插入图片描述

#include<stdio.h>

int main()
{
	char a[5];
	printf("请输入字母\n");
	int  i;
	for (i = 0; i < 5; ++i)
	{
		scanf_s("%c", &a[i]);
		if (a[i] >= 'a' && a[i] <= 'z')
			a[i] = ((a[i] + 4) % 'z' % 'a') + 'a';
		else if (a[i] >= 'A' && a[i] <= 'Z')
			a[i] = ((a[i] + 4) % 'Z' % 'A') + 'A';
		else {
			printf("输入错误!\n");
			--i;
		}
	}
	for (i = 0; i < 5; ++i)
		printf("%c ", a[i]);
	for (i = 0; i < 5; ++i)
		putchar(a[i]);
	return 0;
}

五,判断素数

素数(质数)是指在大于1的自然数中,除了1和它本身以外不再有其他因数的自然数。
1,素数必须大于1
2,素数n不能被2-n-1之间的数整除

#include<stdio.h>
int judge_prime(int n)
{
	if (n <= 1)//素数必须大于1
		return 0;
	for (int i = 2; i < n; ++i)//素数不能被2-n-1的数整除
		if (n % i == 0)
			return 0;
	return 1;
}

int main()
{
	int  i, n;
	do {//循环判断
		printf("请输入一个数,退出请输入-1\n");
		scanf_s("%d", &n);
		if (n == -1)return 0;//退出条件
		if (judge_prime(n))
			printf("%d是素数\n", n);
		else
			printf("%d不是素数\n", n);
	} while (1);
}

六,计算a+aa+aaa…

使用temp保存一阶a,然后每次相加后,a=a*10+temp
在这里插入图片描述

#include<stdio.h>
int main()
{
	int a, n, i, temp, sum = 0;
	printf("要计算a+aa+aaa+...;输入a和项数n\n");
	scanf_s("%d%d", &a, &n);
	temp = a;//保存一阶a
	for (i = 0; i < n-1; ++i) {//计算前n-1项和
		sum += a;
		printf("%d+", a);
		a = a * 10 + temp;//第n项等于前一项*10+一阶a
	}
	printf("%d=%d", a, sum + a);//输出
	return 0;
}

七,求和:阶乘分之一,科学计数法

科学记数法的形式是由两个数的乘积组成的。表示为a×10^b(aEb),其中:1≤|a|<10。
1e-10是科学计数法,表示: 1 ∗ 1 0 − 10 1*10^{-10} 11010;用printf输出可以看见是一个非常小的数。
在这里插入图片描述
在这里插入图片描述

#include<stdio.h>
#define f1 1e-10
int main()
{
	double n, E, i;
	n = E = i = 1;
	E = E + 1 / n;
	while (1/n > 1e-10) {//当最后一项小于1e-10时结束,代表这一项已经相加。
		n = n * (++i);//先计算阶乘,再相加
		E = E + 1 / n;
	}
	printf("%f", E);//输出
	return 0;
}

八,回文素数

1,判断是不是素数
2,判断回文
要求数大于10
从左读与从右读一样:原数与逆序一样
执行逆序

统计a的位数,依次尝试i=10、100、1000…直到a/i==0

	while (a / i)
	{
		i = 10*i;
		++n;
	}

基于位数执行逆序

//temp暂存数据进行中转
//%10取最低位,乘以10^n-1转为最高位
///10删去最低位,循环处理
A = A + (temp % 10) * (pow(10, n - 1));
temp = temp / 10;

代码

#include<stdio.h>
#include<math.h>
int judge_prime(int n)
{
	if (n <= 1)//素数必须大于1
		return 0;
	for (int i = 2; i < n; ++i)//素数不能被2-n-1的数整除
		if (n % i == 0)
			return 0;
	return 1;
}

int judge_palindrome(int a)
{
	int A = 0, i, n, temp;
	i = 10;
	n = 1;
	while (a / i)//统计a的位数,依次尝试i=10、100、1000...直到a/i==0
	{
		i = 10*i;
		++n;
	}
	temp = a;//暂存a的值
	while (n > 0)//将a逆序
	{
		A = A + (temp % 10) * (pow(10, n - 1));//%10取出最低位,乘以10^n-1;转为最高位
		temp = temp / 10;//删去最低位
		--n;//循环直到所有的位都处理
	}
	if (A == a)return 1;//逆序与原始数对比
	else return 0;
}

int main()
{
	int  i, j;
	for (i = 1; i < 1000; ++i) {
		if (judge_prime(i) && i > 10) {
			if (judge_palindrome(i))
				printf("%d ", i);
		}
	}
	return 0;
}

九,有序数组插入元素

数组按升序排序,按升序规则插入一个元素。

#include<stdio.h>
void Insert(int a[], int n, int x)
{
	int i;
	if (a[n - 1] <= x) a[n] = x;
	else {
		for (i = n - 1; i >= 0 && a[i] > x; --i)//不断后移,直到a[i]<=x就插在a[i]后面
			a[i + 1] = a[i];
		a[i + 1] = x;
	}
}

int main() {
	int a[10] = { 1,2,5,8 }, i;
	printf("原数数组为: ");
	for (i = 0; i < 4; ++i)
		printf("%d ", a[i]);
	Insert(a, 4, 3);
	printf("\n插入后数组为: ");
	for (i = 0; i < 5; ++i)
		printf("%d ", a[i]);
	return 0;
}

十,水仙花数(取各位的方法)

1,三位数取各位数:利用%和/交替执行

	a = i % 10;
	b = i / 10 % 10;
	c = i / 100;

2,n位数取各位数:
用temp暂存数
循环处理temp:用%取最后一位,然后/删去最后一位;循环直到temp为0

temp = i;
sum = 0;
while (temp) {
		sum += pow(temp%10, 3);
		temp = temp / 10;
	}
#include<stdio.h>
#include<math.h>
int main() {
	int i, temp, sum, a, b, c;
	for (i = 100; i < 1000; ++i) {
		temp = i;
		sum = 0;
		while (temp) {
			sum += pow(temp%10, 3);
			temp = temp / 10;
		}
		if (sum == i)
			printf("%d ", i);
	}
	printf("\n");
	for (i = 100; i < 1000; ++i) {
		a = i % 10;
		b = i / 10 % 10;
		c = i / 100;
		sum = pow(a, 3) + pow(b, 3) + pow(c, 3);
		if (sum == i)
			printf("%d ", i);
	}
	return 0;
}

十一,斐波那契数列

用递归的话则浪费了很多的算力,最好用循环解决问题。

#include<stdio.h>
int Fibonacci(int n) {
	if (n < 2) {
		return 1;
	}
	else
		return Fibonacci(n - 1) + Fibonacci(n - 2);
}

void Fibonacci1(int n) {
	int f1=1;
	int f2=1;
	for (int i = 0; i < n/2; ++i)
	{
		printf("%d %d ", f1, f2);
		f1 = f1 + f2;
		f2 = f1 + f2;
	}
}
int main()
{
	int i;
	for (i = 0; i < 20; ++i) {
		printf("%d ", Fibonacci(i));
	}
	Fibonacci1(20);
	return 0;
}

十二,统计单词数

I LOVE YOU.
遇到空格单词数就加1,但是空格总比单词数少1。
则利用flag,遇到空格flag为记为真,从而单词数加1;而flag初始化为真,这样自动默认第一个输入的字符为一个单词,以后遇到空格就是代表遇到下一个单词。

如果在循环结束后手动+1,那么如果不输入任何字符也会输出1。故不可取。

#include<stdio.h>
int main()
{
	printf("输入一行文字:\n");
	char ch;
	int i, count = 0, flag = 0;
	while ((ch=getchar())!='\n')
	{
		if (ch == ' ')
			flag = 0;
		if (flag == 0) {
			flag = 1;
			count++;
		}
	}
	printf("%d", count);
	return 0;
}

十三,逆序输出(递归)

数组与指针的关系

a:数组名代表数组首元素地址
*:取值,获取地址对应的值

[]:下标运算符,等于*(a+i)取a的第i+1个元素
a+1:地址向后移一个单位,相当于&a[i+1]
&:取址,获取变量的地址&a[i+1]

示例:
在这里插入图片描述

在这里插入图片描述
实际上,数组可以理解为指针:*取值,&取址。而指针也可以用[]来输出。
在这里插入图片描述
在这里插入图片描述

代码思路

两次递归思路,都是通过/运算,每次删除一个最低位,递归出口为n只剩最高位。如下所示:
123456
12345
1234
123
12
1

然后递归回溯,通过%运算,将高位从后往前插入数组,实现逆序。如下所示:
1 取1插在A[5]
12 取2插在A[4]
123 取3插在A[3]
1234 取4插在A[2]
12345 取5插在A[1]
123456 取6插在A[0]

唯一不同的是:第一个算法借助i记录位数,每递归一次i++;回溯就自动i–;第二个算法则是利用A+1,将地址后移一位,回溯就自动前移地址

#include<stdio.h>
//借助i记录位次,高位插在最后。
void reverse(int A[], int n, int i) {
	if (n / 10)
		reverse(A, n / 10, i + 1);
	A[i] = n % 10;
}

void reverse(int A[], int n) {
//每次递归,A都向后移一位,当n/10==0时,A移的位数等于n的位数。
	if (n / 10)
		reverse(A+1, n / 10);
	//从后向前,从高位向低位放置元素。
	*A = n % 10;
}

int main()
{
	int A[6] = { 1,2,3,4,5,6 };
	reverse(A, 123456);
	return 0;
}

十四,输出菱形

我的代码

1,输入n为层数,转换为上半层(含中间层)数目

2,数目计算公式为: 2 ∗ i − 1 2*i-1 2i1,空格数目计算公式为: ( 2 ∗ n − 1 ) − ( 2 ∗ i − 1 ) (2*n-1)-(2*i-1) (2n1)(2i1),总的占位数-该层的数,余下的就是空格数

3,上半层打印是从i=1遍历到n;下半层等于从i=n-1到1;如下图所示:
在这里插入图片描述
4,注意区分输入的层数,不能为偶数,最少为3层。

#include<stdio.h>
#include<math.h>
int main() {
	int i, j, k, n, num, z;
	printf("输入层数(基数)\n");
	scanf_s("%d", &n);
	//防止输入偶数
	if (n % 2 == 0 || n < 3) {
		printf("输入错误");
		return 0;
	}
	//转换为上半层数量
	n = (n + 1) / 2;
	z = 2 * n - 1;//占位数,*和空格最多占多少位
	//对上半层遍历,含中间层
	for (i = 1; i <= n; ++i) {
		for (j = 0; j < (z - 2 * i + 1) / 2; ++j) printf(" ");//左半空格,等于占位数-*数,然后除以2
		for (j = 0; j < 2 * i - 1; ++j) printf("*");//*
		for (j = 0; j < (z - 2 * i + 1) / 2; ++j) printf(" ");//右半空格
		printf("\n");
	}
	//对下半层遍历,不含中间层
	for (i = n-1; i >0; --i) {
		for (j = 0; j < (z - 2 * i + 1) / 2; ++j) printf(" ");
		for (j = 0; j < 2 * i - 1; ++j) printf("*");//下半层是递减的,故i=n-1,计算公式与上半层一样
		for (j = 0; j < (z - 2 * i + 1) / 2; ++j) printf(" ");
		printf("\n");
	}
	return 0;
}

书中代码

1,层数与列数的关系:相等
数目计算公式为: 2 ∗ i − 1 2*i-1 2i1,则中间层,即列数为 2 ∗ ( n + 1 ) / 2 − 1 = n 2*(n+1)/2-1=n 2(n+1)/21=n

2,每一层的要打印次数都一样;只是打印*还是空格数目的不同。

for(int i=0;i<line;++i)
{
	if(i<(line+1)/2+1)//遍历上半层
	{
		for(int j=1;j<=colum;j++)//逐个打印每个*和空格
		{
			......
		}
	}
	else//遍历下半层
	{
		for(int j=1;j<=colum;j++)//逐个打印每个*和空格
		{
			......
		}
	}
}

3,打印时机

首先确定中间星号的位置为(column+1)/2; 且对于第i层,中间的星号左右各有i-1个星号。
则打印的范围在(column+1)/2-(i-1)到(column+1)/2+(i-1)
其余打印空格
在这里插入图片描述
下半层也类似,只是换成了递减:中间的星号左右各有line-i个星号。
则打印
的范围在(column+1)/2-(line-i)到(column+1)/2+(line-i)
其余打印空格
在这里插入图片描述

十五,完数(公数)问题

如果一个数等于因子之和,即为公数。如果a/n=一个整数,则n是a的因子。
判断方法:
1,对a不断进行a+a相加操作,如果能等于n,则为n的因子。
2,n%a==0;a为n的因子(a*整数等于n,相减余数为0)

#include<stdio.h>
int is_factor(int n,int i)
{
	int temp = i;
	while (temp <= n)
	{
		if (temp == n)
			return 1;
		temp = temp + i;
	}
	return 0;
}
int main()
{
	int n, sum;
	for (n = 2; n <= 200; ++n)
	{
		sum = 0;
		for (int i = 1; i < n; ++i)//i遍历到n-1,因子不是n本身。
		{
			//if (is_factor(n, i))
			if (n % i == 0)
				sum += i;
		}
		if (sum == n)
			printf("%d\t", n);
	}
	
	return 0;
}

十六,孪生素数

我的代码是找到一个素数,然后从这个素数往后遍历找到第二个素数,如果能找到,就进行相减操作,等于2就输出。
课本代码,找到一个素数,就验证其后两位是不是素数,如果是就输出。少了一层遍历。

int main()
{
	int i, j;

	for (i = 3; i <= 1000; ++i) {
		if (judge_prime(i)) {
			for (j = i + 1; j <= 1000; ++j) {
				if (judge_prime(j)) {
					if (j - i == 2)printf("%d-%d\n", i, j);
					break;
				}
			}
		}
	}

	for (i = 3; i <= 998; ++i) {//保证n在3-1000	if (judge_prime(i)&&judge_prime(i+2)){
			printf("%d-%d\n", i, i+2);
		}
	}
}

十七,回文数

1,之前的思路
对的进行逆序,然后对比如果逆序后的数和原始数一致就是回文。
先确定该数的位数
然后依次取出最低位,转为最高位。

int judge_palindrome(int a)
{
	int A = 0, i, n, temp;
	i = 10;
	n = 1;
	while (a / i)//统计a的位数,依次尝试i=10、100、1000...直到a/i==0
	{
		i = 10*i;
		++n;
	}
	temp = a;//暂存a的值
	while (n > 0)//将a逆序
	{
		A = A + (temp % 10) * (pow(10, n - 1));//%10取出最低位,乘以10^n-1;转为最高位
		temp = temp / 10;//删去最低位
		--n;//循环直到所有的位都处理
	}
	if (A == a)return 1;//逆序与原始数对比
	else return 0;
}

2,现在的思路
用temp暂存原始数,对其执行操作,取出对低位转换为最高位,然后删除掉最低位(对中转值进行破坏性逆序)
然后对比原始值和逆序值。

int judge_palindrome(int n)
{
	int temp = n, a = 0;
	while (temp) {
		a = a * 10 + temp % 10;
		temp = temp / 10;
	}
	if (a == n)return 1;
	else return 0;
}

十八,求勾股数

勾股数的要求
1,题目要求:三个都为100以内正整数
2,直角性质: a 2 + b 2 = c 2 a^{2}+b^{2}=c^{2} a2+b2=c2
3,三角形三边要求:任意两边和大于第三边

思路:对a b边进行双层1-100遍历(注意j从i开始遍历,防止重复),根据 a 2 + b 2 = c 2 a^{2}+b^{2}=c^{2} a2+b2=c2,计算出每个c。对c进行检查:c为正整数,c<=100,任意两边和大于第三边。

判断一个数是不是正整数
对该数执行–,若能减为0就是正整数。

int judge_int(double n) {
	int temp = n;
	while (temp >= 0)
	{
		if (temp == 0) return 1;
		--temp;
	}
	return 0;
}

或者使用强制类型转换,用int型接收double,若截去小数后仍然等于原数,则为正整数。

int judge_int(double n) {
	int temp = n;
	if (temp == n)//强制类型转换,存疑
		return 1;
	return 0;
}

易错点:
1,双层遍历中,j要从i开始遍历,否则会出现重复(a=1 b=2;a=2 b=1)。
2,k <= 100,即三条边都小于等于100
3,任意两边和大于第三边

#include<stdio.h>
#include<math.h>

int main()
{
	int i, j;
	double k;
	for (i = 1; i <= 100; ++i)
	{
		for (j = i; j <= 100; ++j)//为什么j==i
		{
			k = sqrt((i * i) + (j * j));
			if (k > 100)
				break;
			if (judge_int(k) && k <= 100 && i + j > k && k + j > i && k + i > j)//任意两边之和小于第三边
				printf("a=%d,b=%d,c=%.0f\n", i, j, k);
		}
	}
	return 0;
}

十九,判断回文字符串

1,字符串处理:用scanf("%s", A);或gets(A);接收一串字符到数组中;

2,对字符数组,遍历0-n/2;处理i和对称的n-1-i元素;如果两者不同就不是回文数。

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>

int judge_huiwen(char A[],int n)
{
	int i;
	for (i = 0; i < n / 2; ++i) {//遍历到前半段,不含中位数
		if (A[i] != A[n - 1 - i])//不同说明就不是回文数
			return 0;
	}
	return 1;
}
int main()
{
	int i , n=0;
	char A[100];
	printf("输入单词:\n");
	gets_s(A);
	//scanf("%s", A);//%s接受字符串,最后为/0
	while (A[n]) {//计算字符长度
		++n;
	}
	if (judge_huiwen(A, n))
		printf("A是回文字符串");
	else
		printf("A不是回文字符串");
	return 0;
}

易错点:
1,while(A[n])最后会在’\0’处停止,长度为n(元素数+1);由此在判断回文的时候条件为if (A[i] != A[n - 1 - i])

二十,删除星号

对字符串"*** HE*LL**O **";删除字母内部的保留外部的

结果为"*** HELLO ***"

1,遍历字符串,标记字母的起始下标和终点下标f1 f2。
f1为第一个不为*的元素下标

f2则跟随遍历不断更新不为*的元素下标,直到最后一个字母

2,对字母范围内的元素处理,即从f1+1遍历到f2-1;遇到*就把所有后面的元素前移,然后元素长度减1,相应的字母范围也会前移,即f2–;i–是因为后面元素移动过来了,要重新检查该下标

易错点:
1,f1,f2起始为-1;否则当第一个元素就是字母的时候会出现误判

2,’\0’,不需要单独设置这个
遍历到了字母中间的星号,就将之后的元素全部前移,最后一次A[j] = A[j + 1];就是将’\0’赋给了A[j]

3,重新检查i
后面的元素前移后,要重新检查i位置,防止后面的为星号。

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>

void delete_xh(char A[])
{
	int i = 0, f1, f2;
	f1 = f2 = -1;
	//找到字母的起始下标
	while (A[i]) {
		if (A[i] != '*') {
			if (f1 == -1)
				f1 = i;
			f2 = i;
		}
		++i;
	}
	//对字母范围内的元素处理,即从f1+1遍历到f2-1
	i = f1 + 1;
	while (i<f2)
	{
		//遇到*就把所有后面的元素前移,然后元素长度减1,相应的字母范围也会前移,即f2--
		if (A[i] == '*') {
			int j = i;
			while (A[j])
			{
				A[j] = A[j + 1];
				j++;
			}
			//A[j - 1] = '\0';不需要,因为最后A[j] = A[j + 1];就是将'\0'赋给了A[j]
			--i;//i--是因为后面元素移动过来了,要重新检查该下标
			--f2;
		}
		++i;
	}
}
int main()
{
	int i, n = 0;
	char A[] = "***HE*LL**O***";
	puts(A);
	delete_xh(A);
	puts(A);
	return 0;
}

二十一,strlen函数

求字符串的长度

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

int strlen(char *string)
{
	int i = 0;
	while (*string++ !='0') {
		++i;
	}
	return i;
}

int main()
{
	char A[337];
	gets_s(A);
	printf("%s\n", A);
	printf("%d", strlen(A));
	return 0;
}

二十二,atoi函数

字符串转为整数,应该注意带有正负号,以及字符串为空的情况。

#include<stdio.h>
int atoi(char* A) {
	int i = 0, temp = 0, sign = 1;
	if (A == NULL)
		return 0;
	while (A[i]) {
		if (A[i] == '-')
			sign = -1;
		else if (A[i] == '+')
			sign = 1;
		else if (A[i] < '0' || A[i]>'9')
			return 0;
		else
			temp = temp * 10 + (A[i] - '0');
		++i;
	}
	return sign * temp;
}

int main()
{
	char a[] = "21431513";
	int a1 = atoi(a);
	printf("%d", a1);
	return 0;
}

二十三,itoa函数

整数转换为字符,同样考虑负数

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>

void itoa(int a,char A[]) {
	int i = 0, temp, n = 0;
	char sign;
	if (a < 0)//根据正负确定第一个字符符号
	{
		sign = '-';
		a = -a;//负数要去掉a的负号,便于后续计算
		temp = a;
	}
	else
	{
		sign = '+';
		temp = a;
	}
	while (temp) {
		temp = temp / 10;
		++n;
	}
	A[n + 1] = '\0';
	A[0] = sign;
	for (i = n; i>0; --i) {
		A[i] = a % 10 + '0';//数字+0的ASCII码才等于对应的数字字符!
		a = a / 10;
	}
}

int main()
{
	int num = -100;
	char str[25];
	itoa(num, str);
	printf_s("The number 'num' is %d and the string 'str' is %s. \n",
		num, str);
	return 0;
}

也可以采用逆序方式,将最低位从左向右插入数组,最后输出

void itoa1(int a, char A[]) {
	int i = 0, sign = a;
	if (sign < 0) {
		a = -a;
	}
	for (i = 0; a > 0; ++i) {
		A[i] = a % 10 + '0';//数字+0的ASCII码才等于对应的数字字符!
		a = a / 10;
	}
	if (sign < 0)
		A[i++] = '-';
	A[i] = '\0';
	for (i=i-1 ; i >= 0; --i)
		printf("%c", A[i]);
}

二十二,strcat函数

实现两字符串的连接,注意字符串为空的验证

#include<stdio.h>

/*
1,正常将B的复制到A
2,B没有就不执行操作,或者假操作
3,相加溢出则报错,但是不预先检测是否会溢出
*/


char* strcat(char* A,const char* B)//使用const关键字对指针加以限定,指针所指向的数据是只读的,也就是 B可以指向不同的数据,但B指向的数据不能被修改。
{
	if (A == NULL || B == NULL)
		return NULL;
	int i = 0, j = 0;
	while (A[i])++i;
	while ((A[i++] = B[j++]) != '\0');
	return A;
}

int main()
{
	char A[12] = "xza";
	char B[11] = "11111112";
	char *C=strcat(A, B);
	return 0;
}

指针实现,需要增加一个指针C记录头结点位置,后续连接后返回C,否则无法从头遍历连接后的数据
使用const关键字对指针加以限定,指针所指向的数据是只读的,也就是 B可以指向不同的数据,但B指向的数据不能被修改。

char* strcat(char* A, const char* B)//使用const关键字对指针加以限定,指针所指向的数据是只读的,也就是 B可以指向不同的数据,但B指向的数据不能被修改。
{
	if (A == NULL || B == NULL)
		return NULL;
	int i = 0, j = 0;
	char* C = A;//相当于链表遍历的时候,头结点不动
	while (*A) {
		A++;
	}
	while ((*A++ = *B++) != '\0');
	return C;//必须返回头结点,后续才能正确遍历
}

二十二,strncat函数

将B所指的前n个字符,连接到A后面。注意验证:数组B长度不能小于n,否则会越界

#define  _CRT_SECURE_NO_WARNINGS
#include<string>

#include<stdio.h>
/*
1,将B前n个字符复制到A结尾
2,B没有就不执行操作,或者假操作
3,不预先检测是否会溢出,B元素是否不足n个
*/

char* strncat(char* A,const char* B,int n)
{
	if (A == NULL || B == NULL) {
		return NULL;//为空时连接失败,返回空
	}
	int i = 0, j = 0;
	while (A[i])++i;
	while (j < n && B[j] != '\0')//数组B长度不能小于n,否则会越界
	{
		A[i++] = B[j++];
	}
	return A;
}

int main()
{
	char A[11] = "xza";
	char B[40] = "162423";
	char* C = strncat(A, B, 5);
	return 0;
}

指针实现

char* strncat(char* A,const char* B, int n)
{
	if (A == NULL || B == NULL) {
		return NULL;//为空时连接失败,返回空
	}
	int i = 0, j = 0;
	char* C = A;
	while (*A)++A;
	while (n-- && *B != '\0')//必须n--,不然会少连接
	{
		*A++ = *B++;
	}
	*A == '\0';//连接n个字符最后应该补上'\0'结尾
	return C;
}

二十二,strcpy函数

将B中字符复制到A,覆盖A原来的字符。

/*
将B中字符复制到A,覆盖A原来的字符。
若B长度小于A,剩余字符为'/0',故无需手动加'/0'
*/

#include<stdio.h>
char* strcpy(char* A,const char* B)
{
	if (A == NULL || B == NULL) {
		return NULL;//为空时连接失败,返回空
	}
	int i = 0, j = 0;
	while ((A[i++] = B[j++]) != '\0');
	return A;//返回的未接收,数组名直接修改的
}

int main()
{
	char A[10] = "XZA";
	char B[] = "iloveyou";
	strcpy(A, B);
	return 0;
}

指针实现

char* strcpy(char* A,const char* B)
{
	if (A == NULL || B == NULL) {
		return NULL;//为空时连接失败,返回空
	}
	char* C = A;
	while ((*A++ = *B++) != '\0');
	return C;//返回的未接收,数组名直接修改的
}

二十二,strcnpy函数

将B中字符中前n个复制到A,覆盖A原来的字符。

/*
将B中字符中前n个复制到A,覆盖A原来的字符。
若B长度小于A,剩余字符为'/0'
#define  _CRT_SECURE_NO_WARNINGS
#include<string>
*/

#include<stdio.h>
char* strncpy(char* A,const char* B,int n)
{
	if (A == NULL || B == NULL) {
		return NULL;//为空时连接失败,返回空
	}
	int i = 0, j = 0;
	while (j < n && B[i])
	{
		A[i++] = B[j++];
	}
	A[i] = '\0';
	return A;
}

int main()
{
	char A[5] = "XZA";
	char B[] = "il513";
	strncpy(A, B, 4);
	return 0;
}

指针实现

char* strncpy(char* A, const char* B, int n)
{
	if (A == NULL || B == NULL) {
		return NULL;//为空时连接失败,返回空
	}
	char* C = A;
	while (n-- && *B)
	{
		*A++ = *B++;
	}
	*A = '\0';
	return C;
}

二十二,strcmp函数

对比A、B两个字符串

#include<stdio.h>
/*
逐项对比A、B两个字符串
1,如果从头到尾元素都相等,返回0
2,如果出现不等,返回A-B
*/
int strcmp(const char* A,const char* B)
{
	int i, j;
	i = j = 0;
	while (A[i] && B[j] && A[i] == B[j])//不是在不相等的时候返回,而是在相等时遍历,直到遇到不相等的情况,或者遍历到最后
	{
		++i;
		++j;
	}
	return A[i] - B[j];//返回相减的值,等于0就是遍历到最后
}
int main()
{
	char A[] = "AAAA";
	char B[] = "AAAA";
	printf("%d", strcmp(A, B));
	return 0;
}

指数实现

int strcmp(const char* A,const char* B)
{
	while (*A && *B && *A == *B)
	{
		++A;
		++B;
	}
	return *A - *B;
}

二十二,strncmp函数

#include<stdio.h>
/*
逐项对比A、B前n项两个字符串
1,如果从头到n-1元素都相等(j>=n),返回0
2,如果出现不等,返回A-B
3,如果B字符不足,j<n一直满足,最后A会和B末尾的/0对比,不相等,A[i] - '/0';
4,如果A字符不足,此时j<n,返回A[i]-B[j]
*/
int strncmp(char* A,const char* B, int n)
{
	int i, j;
	i = j = 0;
	while (--n && A[i] && B[j] && A[i] == B[j])//初始0已经算一次了,故--n
	{
		++i;
		++j;
	}
	return A[i] - B[j];
}
int main()
{
	char A[] = "ABC";
	char B[] = "AB";
	printf("%d", strncmp(A, B, 3));
	return 0;
}

指数实现

int strncmp(char* A, const char* B, int n)
{
	while (--n && *A && *B && *A == *B)//初始0已经算一次了,故--n
	{
		++A;
		++B;
	}
	return *A - *B;
}

二十二,梯形法求面积

将区间[A,B]划分为n个区间,定积分面积可以近似的看成梯形面积。问题转换为计算n个梯形的面积和。
注意封装函数

#define  _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<math.h>
double function(double x)
{
	return (x * x * x) + (3 * x * x) - x + 2;

}

double definite_integral(double a, double b,int n)
{
	double AREA = 0;
	double H = (b - a) / n;
	for (; a <= b; a = a + H) {
		AREA = AREA + ((function(a) + function(a + H)) / 2 * H);
		printf("%f\n", AREA);
	}
	return AREA;
}

int main()
{
	double a, b, n, AREA;
	printf("请输入a,b和梯形数量n:");
	scanf_s("%lf%lf%lf", &a, &b, &n);
	AREA = definite_integral(a, b, n);
	printf("%f", AREA);
	return 0;
}

二十三,空间点距离

计算两点空间距离,注意封装。

/*
p1(x1,y1,z1) p2(x2,y2,z2)
则|p1p2|=sqrt(pow((x1-x2),2)+pow((y1-y2),2)+pow((z1-z2),2))
*/
#include<stdio.h>
#include<math.h>
typedef struct
{
	double x;
	double y;
	double z;
}point;

double dist(point p1, point p2)
{
	double x, y, z, distance;
	x = pow(p1.x - p2.x, 2);
	y = pow(p1.y - p2.y, 2);
	z = pow(p1.z - p2.z, 2);
	distance = sqrt(x + y + z);
	return distance;
}

int main()
{
	point p1 = { 3,222,3 }, p2 = { 9,5,4 };
	double distance = dist(p1, p2);
	printf("%f", distance);
	return 0;
}

二十四,日期计算

*
1,某天是某年的第几天
2,某年一共多少天
3,两天之间间隔多少天
4,计算是周几

*/
#include<stdio.h>
//定义日期结构体
typedef struct {
	int y;
	int m;
	int d;
}date;

//判断一年是否为闰年
int is_Leap(int d) {
	if ((d % 4 == 0 && d % 100 != 0) || (d % 400 == 0)) {
		return 1;
	}
	return 0;
}

//判断某年某天是该年的第多少天
int day_of_year(date d) {
	int num = 0;
	for (int i = 1; i < d.m; ++i) {//遍历每个月
		switch (i)//根据月份确定天数
		{
		case 1:
		case 3:
		case 5:
		case 7:
		case 8:
		case 10:
		case 12:
			num += 31;
			break;
		case 2:
			if (is_Leap(d.y))
				num += 29;
			else
				num += 28;
			break;
		default:
			num += 30;
			break;
		}
	}
	num += d.d;
	return num;
}

//根据闰年非闰年,返回一年的天数
int year_days(int y) {
	if (is_Leap(y))
		return 366;
	else
		return 365;
}

//根据年月日判断两个日期大小,精确到天
int compact_year(date d1, date d2)
{
	if (d1.y - d2.y == 0) {
		if (d1.m - d2.m == 0) {
			if (d1.d - d2.d == 0)
				return 0;
			else
				return d1.d - d2.d;
		}
		else
			return d1.m - d2.m;
	}
	else
		return d1.y - d2.y;
}

//判断两个日期之间有多少天
int inter_day(date d1,date d2) {
	date y_start, y_end;
	int num = 0, year;
	//根据日期对比结果,将较早的日期设为start
	if (compact_year(d1, d2) > 0) {
		y_start = d2;
		y_end = d1;
	}
	else if (compact_year(d1, d2) < 0) {
		y_start = d1;
		y_end = d2;
	}
	else
		return 0;
	//统计start到end的前一年天数
	year = y_start.y;
	while (year < y_end.y) {
		num += year_days(year);
		++year;
	}
	//统计减去start多余的天数,和end未统计的天数
	num = num - day_of_year(y_start) + day_of_year(y_end);//减去d1,加上d2
	return num;
}
int main() {
	date d1 = { 2010,9,20 };
	date d2 = { 2010,12,20 };
	
	printf("%d\n", day_of_year(d1));
	printf("%d\n", year_days(d1.y));
	printf("%d\n", year_days(d2.y));
	printf("%d\n", inter_day(d1,d2));
	return 0;
}

二十五,读取文件统计

#define  _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int* getcharNum(char* filename, int* totalNum)
{
	char ch;//读取的每个字符
	int isLastBlank = 1;
	int line_char = 0, line_word = 0;
	FILE* fp = NULL;
	if ((fp = fopen(filename, "r")) == NULL) {
		perror(filename);
		return NULL;
	}
	totalNum[0] = 1;
	printf("line\twords\tchars\n");//打印表头
	while ((ch = getc(fp)) != EOF)//getc读取完之后就继续后移,必须用ch先接着
	{
		printf("%c", ch);
		if (ch == '\n' || ch == '\r') {//遇到换行时
			if (isLastBlank == 0) line_word++;//给最后一个单词统计上去
			isLastBlank = 1;//初始化空格键
			printf("%d\t%d\t%d\n", totalNum[0], line_word, line_char);
			totalNum[0]++;//累加数据
			totalNum[1] += line_word;
			totalNum[2] += line_char;
			line_word = line_char = 0;
		}
		else if (ch == ' ' || ch == '\t') {//遇到空格
			if (isLastBlank == 0) line_word++;
			isLastBlank = 1;
		}
		else{//遇到字符
			line_char++;
			isLastBlank = 0;
		}
	}
	return totalNum;
	fclose(fp);

}
int main()
{
	char ch;
	int totalNum[3] = { 0,0,0 };
	char filename[] = "test.txt";
	if ((getcharNum(filename, totalNum) != NULL)) {
		printf("all line num:%d\tword num:%d\tchar num:%d\n", totalNum[0], totalNum[1], totalNum[2]);
	}	
	else
	{
		printf("ERROR!");
	}
	return 0;
}

二十六,大小写转换并写入文件

#define  _CRT_SECURE_NO_WARNINGS
#include <stdio.h>

int main()
{
	char ch[100];
	int i = 0;
	printf("请输入字符:\n");
	gets_s(ch);
	FILE* fp = NULL;
	fp = fopen("test.txt", "w");
	while (ch[i]) {
		if (ch[i] >= 'a' && ch[i] <= 'z') {
			ch[i] = ch[i] - 'a' + 'A';
		}
		else if (ch[i] >= 'A' && ch[i] <= 'Z') {
			ch[i] = ch[i] - 'A' + 'a';
		}
		fputc(ch[i], fp);
		++i;
	}
	fclose(fp);
	return 0;
}

二十七,递归求阶乘

#include<stdio.h>
int factorial(int n) {
	if (n == 1)
		return 1;
	else
		return factorial(n - 1) * n;
}
int main()
{
	printf("%d", factorial(10));
	return 0;
}

二十八,字符串排序

利用复制函数和比较函数解决问题的;先比较大小,然后使用复制函数进行交换。只需对比三次即可。

#include<stdio.h>
char* strcpy(char* A, const char* B)
{
	if (A == NULL || B == NULL) {
		return NULL;//为空时连接失败,返回空
	}
	char* C = A;
	while (((*A++) = (*B++)) != '\0');
	return C;//返回的未接收,数组名直接修改的
}

int strcmp(const char* A, const char* B)
{
	while (*A && *B && *A == *B)
	{
		++A;
		++B;
	}
	return *A - *B;
}

void swap(char* p1, char* p2) {
	char temp[20];//必须建立实体数据,不能是指针
	strcpy(temp, p1);
	strcpy(p1, p2);
	strcpy(p2, temp);
}

int main()
{
	char p1[20] = "AAAAB";//空间大小必须一致,不然无法复制
	char p2[20] = "AAAA";
	char p3[20] = "AAAADAJIAO";
	if (strcmp(p1, p2) > 0) {
		swap(p1, p2);
	}
	if (strcmp(p1, p3) > 0) {
		swap(p1, p3);
	}
	if (strcmp(p2, p3) > 0) {
		swap(p2, p3);
	}
	printf("排序后:\n");
	printf("%s\n%s\n%s\n", p1, p2, p3);
	return 0;
}

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

燕南路GISer

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值