C语言经典程序

1、输入一行字符统计单词个数

  1. 输入一行字符串,统计其中有多少单词,单词之间用空格符号隔开
#include<stdio.h>
int main() {
	printf("请输入一行字符串:");
	int i = 0, word = 0;
	char str[81];
	gets_s(str);

	while (str[i] != '\0') {
		if (str[i] == ' ') {
			//跳过所有空白字符
			for (i++; str[i] == ' '; i++);
		}
		else {
			word++;
			//跳过所有非空格,即一个单词
			for (i++; str[i] != ' ' && str[i] != '\0'; i++);
		}
	}
	printf("字符串单词数量:%d", word);
	return 0;
}

1、字符串以'\0'作为结束标志
2、for循环内的 第一部分的i++ 类似开关,使得下标能指向下一位元素进行判断



2、输出不重复三位数

- 有0、1、2、3、4共5个数字 能组成多少个互不相同且无重复数字的3位数?并输出这些数

#include<stdio.h>
int main() {
	int i, j, k, count = 0;
	for (i = 1; i < 5; i++) {
		for (j = 0; j < 5; j++) {
			for (k = 0; k < 5; k++) {
				if (i != j && i != k && j != k) {

					printf("%d ", i * 100 + j * 10 + k);
					count++;
				}
				if (count % 5 == 0) {
					printf("\n");
				}
			}
		}
	}
	printf("\n3位数总个数=%d\n", count);
}

1、枚举列出所有情况,再从其中进行筛选
2、无重复数字 =( i != j && i != k && j != k)
3、注意百位不包括数字0



3、水仙花数

3.1 方法一:枚举法

#include<stdio.h>
#include<math.h>//使用三次方函数pow
int main() {
	int i, j, k,count=0,number;
	for (i = 1; i < 9; i++) {
		for (j = 0; j < 9; j++) {
			for (k = 0; k < 9; k++) {
				number = i * 100 + j * 10 + k;
				//153 = 1的三次方 +5的三次方 +3的三次方
				if ( number==(pow(i,3) +  pow(j,3) + pow(k,3)) ){
					printf("%d ",number);
					count++;
				}
			}
		}
	}
	printf("\n水仙花数个数=%d\n",count);
}

3.2 方法二:取出各个位数

#include<stdio.h>
#include<math.h>//使用三次方函数pow
int main() {
	int ge, shi, bai,count=0;
	for (int i = 100; i < 1000; i++) {
		ge = i % 10;
		shi = i / 10 % 10;;
		bai = i / 100;
		if (i == pow(bai, 3) + pow(shi, 3) + pow(ge, 3)) {
			printf(" %d", i);
			count++;
		}
	}
	printf("\n水仙花数个数: %d", count);
}

1、方法二的使用更加广泛,在应对求更大范围的水仙花数时更加实用



4、完数

方法一:枚举法

#include<stdio.h>
//找出一万以内的完数 完数:6=1+2+3, 28=1+2+4+7+14  本身等于其因子之和
int main() {
	int i, j, sum,count=0;
	//列出所有数
	for (i = 1; i < 10000; i++) {
		sum = 0;//注意每次要先清空上一次的因子之和
		for (j = 1; j < i; j++) {
			//选出其中所有的的因子
			if (i % j == 0) {
				sum += j;
			}
		}
		//本身等于因子之和
		if (sum == i) {
			printf("%d ", sum);
			count++;
		}
	}
	printf("\n一万以内完数的个数:%d", count);
}

方法二:算法

书本P156 有提升性能的算法 以根号i作为一个分水岭,因子关于其对称,当出现两边因子相同则要减去一个



5、判断整数重复数字

  • 输入一个不超过9位数的无符号整数,判断该整数中是否存在重复数字
#include<stdio.h>
//输入一个不超过9位数的无符号整数,判断该整数中是否存在重复数字
int main() {
	int num,n,i;
	int count[10]={0};//统计数字出现次数
	printf("请输入一个正整数:");
	scanf("%d", &num);
	n = num;
	//分类数字的个位,统计每个数字出现的次数
	while (n != 0) {
		count[n % 10]++;
		n = n / 10;
	}

	//遍历查找数组的记录的值
	for (i = 0; i < 10; i++) {
		if (count[i] > 1) {
			break;
		}
	}
	if (i < 10 ) {
		printf("%d存在重复数字", num);
	}
	else
	{
		printf("%d不存在重复数字", num);
	}
}

用一个数组通过每次截取个位数,实现记录每位数字出现的次数。这种思想要学会



6、插入升序数组,使插入后还是升序

#include<stdio.h>
#define N 10
int main() {
	//多预留了一位空位置用于放插入数据
	int arr[N] = { 1,2,10,13,20,32,40,67,80 },*p=arr+N-2,in;//使指针指向最后数组最后一位
	printf("请输入要插入的数字:");
	scanf("%d",&in);
	//进行反向扫描
	while (p >= arr) {
		if (*p > in) {
			//将值移动到右边
			*(p + 1) = *p;
			p--;
		}
		else{
			break;
		}
	}
	//循环结束后指针移动到了比待插入数字要小的数字处  在其右边插入
	*(p + 1) = in;
	printf("插入后的数组:");
	for (int i = 0; i < 10; i++) {
		printf("%d ", arr[i]);
	}
}

指针倒序扫描找到待插入位置,在其右侧插入



7、字符串中提取整数

  • 假设输入的字符串中有数字和非数字字符(如"a123x456 17960? 302tab799“), 编写程序找出字符串中所有由连续的数字字符组成的整数(如123、456、19960、302、6799),并统计共找到多少个整数
#include<stdio.h>
//假设输入的字符串中有数字和非数字字符(如"a123x456		17960?	302tab799“)
int main() {
	char str[81],*p=str;//将数组的首地址给指针p,用于便利每一个字符
	int count=0, num, i;//count:记录次数,num:每个数字,i:控制循环
	printf("请输入一行字符:");
	gets_s(str);
	while (*p) { // '\0'的ASCll为0,扫描到末尾则跳出循环
		//遇到数字
		if (*p > '0' && *p < '9') {
			//遇到连续的数字
			for (num = 0; *p > '0' && *p < '9' ;p++) {
				num = num * 10 + (*p - '0');
			}
			count++;
			printf("NO %d:%d\n", count, num);
		}
		//遇到非数字,跳过
		else {
			//跳过所有非数字,这里可有可无
			if(*p != '\0' && ( * p > '0' || *p < '9')) {
				p++;
			}
		}
	}

}


8、两个升序数组合并成一个

#include<stdio.h>

//数组名本身就是首元素的地址,即指向首元素的指针
void merge_sort(int *x, int lenx,int *y, int leny,int* z) {
	int i=0, j=0, k=0;
	//只要小于数组长度就继续比较
	//比较后较小的数组会消失,留下两数组的差值部分没有比较,直接存入
	while (i < lenx && j < leny) {
		if (x[i] < y[j]) {
			z[k++] = x[i++]; //等价于  z[k[ = x [i];   k++;  i++;
 		}else{
			z[k++] = y[j++];
		}
	}
	//如果其中一个数组还有剩余,则按顺序依次存入
	while (lenx > i) {
		z[k++] = x[i++];
	}
	while (leny > j) {
		z[k++] = y[j++];
	}
}

//两个升序数组合并成一个
int main() {
	int a[10] = { 0,3,6,9,10,18,23,25,30,35 };
	int b[8] = { -5,-1,1,2,5,11,28,40 };
	int i, c[18];
	printf("原始数组a:");
	for (i = 0; i < 10; i++) {
		printf("%d ", a[i]);
	}
	printf("\n原始数组b:");
	for (i = 0; i < 8; i++) {
		printf("%d ", b[i]);
	}
	merge_sort(a,10,b,8,c);
	printf("\n合并后的新数组c:");
	for (i = 0; i < 18; i++) {
		printf("%d ", c[i]);
	}
}

运用数组下标和本身就是升序的特性将两个旧数组进行比较存储,余下的再按顺序存储



9、字符串匹配

  • 设主串数组名为S,子串数组名为T,找出子串T在主串S中第一次出现的位置
#include<stdio.h>
#include<string.h>
//字符串匹配
//设主串数组名为S,子串数组名为T,找出子串T在主串S中第一次出现的位置
int index(char *s,char *t,int start) {
	int i = start, j = 0; //i作为母串的起始位置  j为子串的起始位置  都用于便利字符串
	int m = strlen(s), n = strlen(t);//m:母串长度,n:子串长度
	if (start<0 || n == 0 || start + n>m) {
		return -1;
	}
	while (i < m && j<n ) {
		//相同则移动到下一位继续比较
		if (s[i] == t[j]) {
			i++;
			j++;
		}
		//不同则将子串清空,母串从不相同元素的下一位开始
		else {
			i = i-j + 1;
			j = 0;
		}
	}
	//如果比较出来的子串长度等于原长度,说明母串中存在子串
	if (n == j) {
		return(i - n);//子串在母串中的起始位置
	}
	else {
		return -1;
	}
}
int main() {
	char S[] = "abcdegdefg", T[] = "def";
	//成功返回子串在主串的起始位置,失败返回-1
	int num = index(S, T, 1);
	printf("子串在主串的起始位置:%d", num+1);//下标从0开始,返回的位置是6
}

运用下标逐个比较,注意不相符的比较需要将 主串的起始位置移动到主串的下一位 子串从头开始 再次进行逐个比较



10、学生加权平均成绩

  • 4个学生,每个学生有3门课程的成绩,每门课程的学分不一样。请计算每一个学生的加权成绩
#include<stdio.h>

//传入每一个学生的成绩和每门课程的学分
float aver(int x[], int y[]) {
	int i,sum1=0,sum2=0;//sum1记录成绩*学分,sum2记录总学分
	for (i = 0; i < 3; i++) {
		sum1 += x[i] * y[i];
		sum2 += y[i];
	}
	return ((float)sum1 / sum2);
}

//4个学生,每个学生有3门课程的成绩,每门课程的学分不一样。请计算每一个学生的加权成绩
int main() {

	int scores[4][3] = { {81.92,88},{99,88,98},{95,86,90},{90,90,90} };
	int credit[3] = { 3,4,2 };
	float p;
	for (int i = 0; i < 4; i++) {
		//传入每个学生各自的成绩,和成绩对应的学分
		p = aver(scores[i], credit);
		printf("第%d个学生的加权成绩:%.2f\n", i + 1, p);
	}
	return 0;
}


11、字符串中找出字符

#include<stdio.h>
char* strch(char* s, char ch) {
	//跳过不匹配的字符
	while (*s && *s != ch) {
		s++;
	}
	//如果不是读到了末尾,则返回当前匹配的字符指针
	if (*s) {
		return s;
	}
	return NULL;
}

//在一串字符串中找出某一个字符
int main() {
	char str[81] = "abcdefg", ch = 'h', * p = str,*s;
	s= strch(p,ch);

	if (s == NULL) {
		printf("字符串中不存在该字符!");
	}
	printf("从字符串中找出的字符:%c", *s);
}

运用指针,对字符串中的每个字符依次比较,相同则将指针移动一位直至比到相同的元素,返回指向其的指针



12、折半查找某数是否在升序数组中

#include<stdio.h>
//p指向一维数组,n是数组长度,key为查找关键字  找到返回元素下标,否则返回-1
int search(int* p, int n, int key) {
	int low = 0, high = n-1, mid,result=-1;
	while(high > low) {
		//折半查找
		mid = (low + high) / 2;
		if (p[mid] == key) {
			result = mid;
			break;
		}
		else if (p[mid] > key) {//待查找数字小于中间数,即在左边,需要缩小最大值
			high = mid - 1;
		} 
		else {//在右边,需要放大最小值
			low= mid + 1;
		}
	}
	return result;
}

//用折半查找法找某数是否在给定的升序数组中
int main() {
	int arr[10] = {1,2,3,4,5,6,7,8,9,10};
	int result = search(arr, 10, 8);
	printf("查找结果位于的下标:%d", result);
}