目录
- 细节语法问题
- 基础阶段
- 一,判断闰年
- 二,大小写字母转换
- 三,面积计算
- 四,加密问题
- 五,判断素数
- 六,计算a+aa+aaa......
- 七,求和:阶乘分之一,科学计数法
- 八,回文素数
- 九,有序数组插入元素
- 十,水仙花数(取各位的方法)
- 十一,斐波那契数列
- 十二,统计单词数
- 十三,逆序输出(递归)
- 十四,输出菱形
- 十五,完数(公数)问题
- 十六,孪生素数
- 十七,回文数
- 十八,求勾股数
- 十九,判断回文字符串
- 二十,删除星号
- 二十一,strlen函数
- 二十二,atoi函数
- 二十三,itoa函数
- 二十二,strcat函数
- 二十二,strncat函数
- 二十二,strcpy函数
- 二十二,strcnpy函数
- 二十二,strcmp函数
- 二十二,strncmp函数
- 二十二,梯形法求面积
- 二十三,空间点距离
- 二十四,日期计算
- 二十五,读取文件统计
- 二十六,大小写转换并写入文件
- 二十七,递归求阶乘
- 二十八,字符串排序
细节语法问题
结构体定义
只能用数字定义数组
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}
1∗10−10;用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 2∗i−1,空格数目计算公式为: ( 2 ∗ n − 1 ) − ( 2 ∗ i − 1 ) (2*n-1)-(2*i-1) (2∗n−1)−(2∗i−1),总的占位数-该层的数,余下的就是空格数
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
2∗i−1,则中间层,即列数为
2
∗
(
n
+
1
)
/
2
−
1
=
n
2*(n+1)/2-1=n
2∗(n+1)/2−1=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;
}