从0开始学c语言-38-题目练习

本文提供了九个C语言编程题目,包括打印X图形、求平均分、判断位段等,每个题目都有思路解析,适合C语言学习者进行练习和提高。
摘要由CSDN通过智能技术生成

上一篇:从0开始学c语言-37-文件随机读写、文本文件和二进制文件、判定文件结束、文件缓冲区_阿秋的阿秋不是阿秋的博客-CSDN博客

目录

题目1:多组输入打印x图形

题目2:求平均分(去掉最高、最低分)

题目3:打印某年某月的天数

题目4:有序序列插入一个数

题目5:位段判断

题目6:模拟实现atoi函数

 题目7:寻找只出现一次的两个数字

题目8:模拟实现strncpy函数

题目9:模拟实现strncat函数


题目1:多组输入打印x图形

放一下效果图,可以自己尝试写一下。

int main()
{
	int i, j, n = 0;
 //因为要多组输入,所以我们加了这个条件
 //多组输入就是输入后还能输入
	while (scanf("%d", &n) != EOF)
	{
		for (i = 0; i < n; i++)
		{
			for (j = 0; j < n; j++)
			{
				if ((i == j) || (i + j == n - 1))
					printf("*");
				else
					printf(" ");
			}
			printf("\n");
		}
	}
	return 0;
}

题目2:求平均分(去掉最高、最低分)

         思路1:数组中排序(qsort函数),循环时候去掉最高最低分求平均分。

#include <stdlib.h>
int cmp(const void* elem1, const void* elem2)
{
	return *(int*)elem1 - *(int*)elem2;
}

//求平均分
int main()
{
	int arr[7] = { 0 };
	int i = 0;
	for (i = 0; i < 7; i++ )
	{
		scanf("%d", &arr[i]);
	}
	qsort(arr, sizeof(arr)/sizeof(arr[0]), sizeof(arr[0]), cmp);
	int sum = 0;
	for (i = 1; i < 6; i++)
	{
		sum += arr[i];
	}
	double output = sum / 5.0;
	printf("%.2f\n", output);
	return 0;
}

        思路2:循环输入的同时,每次输入进行最大、最小数的判断并存储到相应的变量中,循环完后去掉最高最低分,计算平均分。

int main()
{
	int num = 7;
	int i = 0;
	float score = 0;
	float max = 0;
	float min = 0;
	float sum = 0;
	for (i = 0; i < num; i++)
	{
		scanf("%d", &score);
		if (score > max)
			max = score;
		else
			min = score;
		sum += score;
	}
	float output = sum - max - min;
	printf("%.2f\n", (output/5.0));
	return 0;
}

题目3:打印某年某月的天数

        思路1:用结构体储存不同的天数,根据闰年和月份进行分类并打印。

enum
{
	Spe_month1 = 28,
	Spe_month2,
	Sml_month,
	Big_month
};
int main()
{
	int year = 0;
	int month = 0;
	while (scanf("%d %d", &year, &month) != EOF)
	{
		//判断是不是2月
		if (month == 2)
		{
			//是闰年,则2月29天
			if ((year % 4 == 0 && year % 400 != 0) || (year % 400 == 0))
					printf("day:%d\n", Spe_month2);
			else
			//不是,28天
				printf("day:%d\n", Spe_month1);
		}
		//其他月份和闰年不闰年没关系
		//4 6 9 11 -30
		else if (month == 4 || month == 6 || month == 9 || month == 11)
				printf("day:%d\n", Sml_month);
		//其他情况,1 3 5 7 8 10 12 - 31天
		else
			printf("day:%d\n", Big_month);
	}
	return 0;
}

        思路2:只有闰年2月的月份需要天数+1,其他天数的月份都一样,把这些天数放到数组里。

int main()
{
	int y = 0;
	int m = 0;
	int days[] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };
	while (scanf("%d %d", &y, &m) != EOF)
	{
		int day = days[m];
		//只有闰年的2月需要天数+1
		if (m == 2)
			if ((y % 4 == 0 && y % 400 != 0) || (y % 400 == 0))
				day += 1;
		printf("%d\n", day);
	}
	return 0;
}

题目4:有序序列插入一个数

int main()
{
	int num = 0;
	//要求0<N<=50,意味着最多有51个,因为会插进来一个数字
	int arr[51]; //所以数组是51
	int i = 0;
	scanf("%d", &num); //第一行
	for (i = 0; i < num; i++)
		scanf("%d", &arr[i]);  //第二行
	scanf("%d", &arr[i]);  //第三行
	int insert = arr[i];
	for (i = 0; i < num + 1; i++)
	{
		if( (insert <= arr[i])|| (insert > arr[num]))
		{
			int tmp = arr[i];
			arr[i] = insert;
			insert = tmp;
		}
		printf("%d ", arr[i]);
	}
	return 0;
}

         注意我设置的交换条件,如果小于数组中第i位的数字或者大于数组中最后一个数字,就进行交换。这是我自己假设了一个数组探索出来的条件,没啥好讲的。不懂就假设一个有序数组,慢慢推程序运行原理。

if( (insert <= arr[i])|| (insert > arr[num]))

题目5:位段判断

不会的看文章。

从0开始学c语言-32-自定义类型:结构体,枚举,联合_阿秋的阿秋不是阿秋的博客-CSDN博客

int main()
{
  unsigned char puc[4];
  struct tagPIM
  {
    unsigned char ucPim1;
    unsigned char ucData0 : 1;
    unsigned char ucData1 : 2;
    unsigned char ucData2 : 3;
  }*pstPimData;
  pstPimData = (struct tagPIM*)puc;
  memset(puc,0,4);
  pstPimData->ucPim1 = 2; 
  pstPimData->ucData0 = 3;
  pstPimData->ucData1 = 4;
  pstPimData->ucData2 = 5;
  printf("%02x %02x %02x %02x\n",puc[0], puc[1], puc[2], puc[3]);
  return 0;
}

       结构体占用两个字节的空间,按照位段要求的bit位存放数据,结果如绿框中所示。

         绿框中的数字转换为十六进制输出正好是02 29 00  00 。

        顺便探索了一下十六进制%x的输出,注意10位包含0x在内的,以及不能去掉010中的第一位0,否则会是图2的效果。

题目6:模拟实现atoi函数

顺便补充:字符串转换整型 atoi、sscanf,整型转换为字符串sprintf

                atoi函数是把字符串的数字转换为整型输出,我的思路是寻找数字字符,找不到数字字符的时候,就留一个指针在最后一个数字字符,然后进行整型输出(运用了指针-指针=指针之间的元素个数知识)。

int my_atoi(char* p)
{
	assert(p);
	//考虑什么时候读取结束
	//考虑返回值是返回的谁
	//考虑怎么转换为int

	char* end = p;
	while (*end >= '0' && *end <= '9')
	{
		end++;
	}
	--end;
	int ret = 0;
	int i = 1;
	while (p <= end)
	{
	//注:直接*访问到的int值是ASCII 值,减去‘0’字符的ASCII码值正好是数字本身
		ret += (*end-'0') * i; 
		i *= 10;
		end--;
	}
	return ret;
}
int main()
{
	char* p = "1234";
	int ret = my_atoi(p);
	printf("%d\n", ret);
	return 0;
}

         上面这个函数还是考虑不周全。

        完善一下这个函数。进行空字符检查、空符号的跳过,正负号的判断。以及要知道isdigit函数和isspace函数的作用,在注释中有写。

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <ctype.h>
//isdigit函数,检查字符是否为十进制数字
//isspace函数,检查字符是否有空白

int my_atoi(const char* str)
{
	//空指针检查
	assert(str);
	//空字符检查
	if (*str == '\0')
	{
		return 0;
	}
	//跳过空白字符
	while (isspace(*str))//isspace函数,检查字符是否有空白
	{
		//' ' '\t' '\n' '\v' '\f' '\r'
		str++;
	}
	int flag = 1;
	//跳过正负号
	if (*str == '+')
	{
		str++;
	}
	else if (*str == '-')
	{
		flag = -1;
		str++;
	}
	//开始转换
	long long ret = 0; //因为可能超出int范围,所以进行了判断
	while (isdigit(*str))
	{
		ret = ret * 10 + flag * (*str - '0');
		//判断范围
		if (ret > INT_MAX)
		{
			ret = INT_MAX;
			return (int)ret;
		}
		else if (ret < INT_MIN)
		{
			ret = INT_MIN;
			return (int)ret;
		}
		str++;
	}
	//来到这里的有两种情况
	//1·遇到\0
	//2·遇到数字以外的字符
	return (int)ret;
}

int main(void)
{
	char a[] = "    -1212abcd";
	int i = atoi(a);
	printf("   atoi = %d\n", i);

	int j = my_atoi(a);
	printf("my_atoi = %d\n", j);

	return 0;
}

 题目7:寻找只出现一次的两个数字

        在一个数组中,只有两个数字是出现了一次,其他数字都出现了两次,请找出这两个数字。

两个方法写一起了。

//方法1:两个循环遍历比对
void Find1(int* arr, int sz, int* px, int* py)
{
	int tmp[2] = { 0 };
	int i,j,flag,p = 0;
	for (i = 0; i < sz; i++)
	{
		for (j = 0; j < sz; j++)
		{
			flag = 1;
			if( (i != j) && (arr[i] == arr[j]))
			{
				flag = 0;
				break;
			}
		}
		//如果没有相等的数字
		if (flag)
		{
			tmp[p++] = arr[i];
		}
	}
	*px = tmp[0];
	*py = tmp[1];
}

//根据相同数字异或为0原则思考
//把第pos位数字相同的分到一组
void Find2(int arr[], int n, int* px, int* py)
{
	int i;
	int sum = 0;
	//先找到两个只出现一次的数,得到他们互相异或的结果
	for(i = 0; i < n; i++)
	{
		sum ^= arr[i];
	} 
	//再找到不一样的二进制数字位,在这一位上,两个数一定是一个1一个0
	int pos;
	for (i = 0; i < 32; i++)
	{
//求最低位不同还有两种:ret=ret&(-ret)或ret=ret&(~ret-1) 
//这两种我没有验证,只是有人说而已
		if (sum & 1 << i)
		{
			pos = i;
			break;
		}
	}
	//假设倒数第5位的二进制数字不一样
	//那就是根据这个倒数第五位进行分组
	//把能够异或为0的放在一起
	//把两个不同数字分在两个组
	*px = *py = 0;
	for (i = 0; i < n; i++)
	{
		if (arr[i] & 1 << pos)
		{
			*px ^= arr[i]; //这一位是1的,放在数1里
		}
		else
		{
			*py ^= arr[i]; //这一位是0的,放在数2里
		}
	}
}
int main()
{
	int arr[] = { 1,1,2,2,3,3,4,4,5,6 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	int x, y;
	/*Find1(arr, sz, &x, &y);*/
	Find2(arr, sz, &x, &y);
	printf("%d %d", x, y);
	return 0;
}

题目8:模拟实现strncpy函数

        当字符串复制的时候,判断 需要赋值字符串 是否到了\0的位置,以及 是否到达了复制字符串的制定个数,如果指定复制的字符个数还未到就到了\0的位置,那么需要给字符串中加上\0字符。

char * mystrncpy(char * dst, const char * src, size_t n)
{
	int i;
  for (i = 0; src[i] && i < n; i++)
  {
    dst[i] = src[i];
  }
   
  if (i < n)
  {
  	dst[i] = 0;
  }
  return dst;
}

题目9:模拟实现strncat函数

        进行字符串追加的时候,先要找到第一个字符串中最后一个字符的位置,也就是\0的位置,然后进行字符串的追加,当第二个字符串未到达\0位置以及追加字符个数未达到时候,便继续追加,最后需要我们手动加一个\0结束字符。

char * mystrncat(char * dst, const char * src, size_t n)
{
	char * tmp = dst;
   
  while (*dst)
  {
    dst++;
  }
   
  int i;
  for (i = 0; src[i] && i < n; i++)
  {
    dst[i] = src[i];
  }
   
  dst[i] = 0;
  return tmp;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值