C语言:练习

C语言:练习_第1张图片

 

题一:直接交换


交换两个变量(不创建临时变量)
不允许创建临时变量,交换两个整数的内容

情况如下:

按位异或(相同为0,不相同未1):"  ^ ";

a ^ a = 0;
a ^ 0 = a;

//就有

3 ^ 5 ^3 = 5;


#include 

int main()
{
	int a = 0;
	int b = 0;
	scanf("%d %d", &a, &b);
	a = a ^ b;
	b = a ^ b;
	a = a ^ b;

	printf("%d %d\n", a, b);

	return 0;
}

题二:计算二进制数个数


输入一个整数 n ,输出该数32位二进制表示中1的个数。其中负数用补码表示。

#include 

int main()
{
	int n = 0;
	int sum = 0;
	scanf("%d", &n);
	
	
	while (n != 0)
	{
		n = n & (n - 1);//n为00101000;n - 1得到00100111;n & (n - 1)得到00100000
                        //就会去掉一个1
		sum++;

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

	return 0;
}

更好的详细解题:

/*
方法一:
思路:
循环进行以下操作,直到n被缩减为0:
   1. 用该数据模2,检测其是否能够被2整除
   2. 可以:则该数据对应二进制比特位的最低位一定是0,否则是1,如果是1给计数加1
   3. 如果n不等于0时,继续1
*/
int count_one_bit(int n)
{
	int count = 0;
	while(n)
	{
		if(n%2==1)
			count++;
		n = n/2;
	}
	return count;
}


/*
上述方法缺陷:进行了大量的取模以及除法运算,取模和除法运算的效率本来就比较低。
方法二思路:
一个int类型的数据,对应的二进制一共有32个比特位,可以采用位运算的方式一位一位的检测,具体如下
*/
int count_one_bit(unsigned int n)
{
	int count = 0;
	int i = 0;
	for(i=0; i<32; i++)
	{
		if(((n>>i)&1) == 1)
			count++;
	}
	return count;
}


/*
方法二优点:用位操作代替取模和除法运算,效率稍微比较高
  缺陷:不论是什么数据,循环都要执行32次
  
方法三:
思路:采用相邻的两个数据进行按位与运算
举例:
9999:‭10 0111 0000 1111‬
第一次循环:n=9999   n=n&(n-1)=9999&9998= 9998
第二次循环:n=9998   n=n&(n-1)=9998&9997= 9996
第三次循环:n=9996   n=n&(n-1)=9996&9995= 9992
第四次循环:n=9992   n=n&(n-1)=9992&9991= 9984
第五次循环:n=9984   n=n&(n-1)=9984&9983= 9728
第六次循环:n=9728   n=n&(n-1)=9728&9727= 9216
第七次循环:n=9216   n=n&(n-1)=9216&9215= 8192
第八次循环:n=8192   n=n&(n-1)=8192&8191= 0


可以观察下:此种方式,数据的二进制比特位中有几个1,循环就循环几次,而且中间采用了位运算,处理起来比较高效
*/
int count_one_bit(int n)
{
	int count = 0;
	while(n)
	{
		n = n&(n-1);
		count++;
	}
	return count;
}

题三:打印二进制奇偶位

打印整数二进制的奇数位和偶数位
获取一个整数二进制序列中所有的偶数位和奇数位,分别打印出二进制序列


#include 

int main()
{
	int n = 0;
	scanf("%d", &n);
	int i = 0;
	//奇数位
	for (i = 0; i < 32; i += 2)
	{
		printf("%d ",(n >> i) & 1);
	}
	printf("\n");
	//偶数位
	for (i = 1; i <= 31; i += 2)
	{
		printf("%d ", (n >> i) & 1);
	}
	return 0;
}

题四:二进制不同个数

输入两个整数,求两个整数二进制格式有多少个位不同


#include 

int main()
{
	int a = 0;
	int b = 0;
	int n = 0;
	int i = 0;
	int count = 0;
	scanf("%d %d",&a, &b);
	n = a ^ b;
	for (i = 0; i < 32; i++)
	{
		if (((n >> i) & 1) == 1)
			count++;
	}
	printf("%d\n",count);

	return 0;
}

更好的方法:

/*
思路:
1. 先将m和n进行按位异或,此时m和n相同的二进制比特位清零,不同的二进制比特位为1
2. 统计异或完成后结果的二进制比特位中有多少个1即可
*/
#include 
int calc_diff_bit(int m, int n)
{
	int tmp = m^n;
	int count = 0;
	while(tmp)
	{
		tmp = tmp&(tmp-1);
		count++;
	}
	return count;
}


int main()
{
 int m,n;
 while(scanf("%d %d", &m, &n) == 2)
 {
     printf("%d\n", calc_diff_bit(m, n));
 }
 return 0;
}

题五:序列合并

输入两个升序排列的序列,将两个序列合并为一个有序序列并输出。

#include 

int main()
{
	int a = 0;
	int b = 0;
	scanf("%d %d", &a ,&b);
	int arr1[1000] = {0};
	int arr2[1000] = {0};
	int i = 0;
	for (i = 0;i < a;i++)
	{
		scanf("%d",&arr1[i]);
	}
	for (i = 0; i < b; i++)
	{
		scanf("%d", &arr2[i]);
	}
	int q = 0;
	int j = 0;
	int n = 0;
	int arr3[1000] = { 0 };
	i = 0;
	while (j < a && n < b)
	{
		if (arr1[j] < arr2[n])
		{
			arr3[i] = arr1[j];
			i++;
			j++;
		}
		else
		{
			arr3[i] = arr2[n];
			i++;
			n++;
		}
	}
	if (j == a && n < b)
	{
		for (; n < b; n++)
		{
			arr3[i] = arr2[n];
			i++;
		}
	}
	else
	{
		for (; j < a; j++)
		{
			arr3[i] = arr1[j];
			i++;
		}
	}
	q = i;
	for (i = 0; i < q; i++)
	{
		printf("%d ",arr3[i]);
	}

	return 0;
}

题六:序列排序

输入一个整数序列,判断是否是有序序列,有序,指序列中的整数从小到大排序或者从大到小排序(相同元素也视为有序)。

#include 


int main()
{
	int count1 = 0;
	int count2 = 0;
	int n = 0;
	scanf("%d", &n);
	int i = 0;
	int arr[50] = { 0 };
	for (i = 0; i < n; i++)
	{
		scanf("%d ",&arr[i]);
	}
	
	for (i = 0; i < n-1; i++)
	{
		
		if (arr[i] >= arr[i + 1])
		{
			count1++;
		}
		if (arr[i] <= arr[i + 1])
		{
			count2++;;
		}
	}
	if (count1 == n - 1)
	{
		printf("sorted");
	}
	else if (count2 == n - 1)
	{
		printf("sorted");
	}
	else
	{
		printf("unsorted");
	}

	return 0;
}

题七:计算月份天数

KiKi想获得某年某月有多少天,请帮他编程实现。输入年份和月份,计算这一年这个月有多少天。
多组输入,一行有两个整数,分别表示年份和月份,用空格分隔。
针对每组输入,输出为一行,一个整数,表示这一年这个月有多少天

#include 

int is_year(int year)
{
	return (year % 4 == 0 && year % 100 != 0 || year % 400 == 0);
	
}

int main()
{
	int year = 0;
	int month = 0;
	int sum = 0;
	
	

	while (scanf("%d %d", &year, &month) == 2)
	{
		int day[] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };
		sum = is_year(year);
		if (sum == 1)
		{
			day[2] = 29;
		}
		printf("%d\n",day[month]);
	}



	return 0;
}

题八:数组打印


使用指针打印数组内容
写一个函数打印arr数组的内容,不使用数组下标,使用指针。
arr是一个整形一维数组。

#include 
#include 

void print(int* arr,int len)
{
	int i = 0;
	for (i = 0; i < len; i++)
	{
		printf("%d ",*(arr+i));
	}
}


int main()
{
	int arr[10] = { 0,1,2,3,4,5,6,7,8,9 };
	int len = 0;
	len = sizeof(arr) / sizeof(arr[0]);
	print(arr,len);
	

	return 0;
}

题九:颠倒字符串

将一个字符串str的内容颠倒过来,并输出

int main()
{
    char str[10000] = { 0 };
    gets(str);
    int sz = strlen(str);
    /*print(str, sz);*/
    int i = 0;
    for (i = 0; i < sz; i++)
    {
        char tmp = 0;
        tmp = str[i];
        str[i] = str[sz - 1];
        str[sz-- - 1] = tmp;
        
    }
    printf("%s\n", str);
    return 0;
}

题十:打印图案

用C语言在屏幕上输出以下图案:

C语言:练习_第2张图片

#include 

int main()
{
	int line = 0;
	scanf("%d", &line);
	int i = 0;
	int j = 0;
	//上半部分
	for (i = 0; i <= line/2; i++)
	{
		for (j = 0; j < (line-2*i)/2; j++)
		{
			printf(" ");
		}
		for (j = 0; j < 2 * i + 1; j++)
		{
			printf("*");
		}
		printf("\n");
		
	}

	//下半部分
	for (i = 1; i <= line / 2; i++)
	{
		for (j = 0; j <= i-1; j++)
		{
			printf(" ");
		}
		for (j = 0; j < (line - (2 * i)); j++)
		{
			printf("*");
		}
		printf("\n");
	}


	return 0;
}

题十一:变种水仙花

求出0~100000之间的所有“水仙花数”并输出。
“水仙花数”是指一个n位数,其各位数字的n次方之和确好等于该数本身,
如 : 153=1 ^ 3+5 ^ 3+3 ^ 3,则153是一个“水仙花数”。

#include 
#include 

int Daffodil(int i)
{
	int sum = 0;
	int n = 1;
	int tmp = i;
	while (tmp / 10)
	{
		n++;
		tmp /= 10;
	}
	tmp = i;
	while (tmp)
	{
		sum =(int)pow(tmp % 10,n) + sum;
		tmp = tmp / 10;
	}
	return sum == i;
}


int main()
{
	int i = 0;
	for (i = 0; i < 100000; i++)
	{
		if (Daffodil(i))
		{
			printf("%d ", i);
		}
	}
	return 0;
}

题十二:计算五项和

求Sn = a + aa + aaa + aaaa + aaaaa的前5项之和,其中a是一个数字,
例如:2 + 22 + 222 + 2222 + 22222

#include 

int Sn(int a)
{
	int sum = 0;
	int i = 0;
	int n = a;
	for (i = 0; i < 5; i++)
	{
		sum = a + sum;
		a = n + a * 10;
	}

	return sum;
}


int main()
{
	int a = 0;
	int sum = 0;
	scanf("%d", &a);
	sum = Sn(a);
	printf("%d\n", sum);

	return 0;
}

写错的选择题

下面代码的结果是:

#include 
int i;
int main()
{
    i--;
    if (i > sizeof(i))
    {
        printf(">\n");
    }
    else
    {
        printf("<\n");
    }
    return 0; 
}

A.>

B.<

C.不输出

D.程序有问题

C语言中,0为假,非0即为真。

全局变量,没有给初始值时,编译其会默认将其初始化为0。

i的初始值为0,i--结果-1,i为整形,sizeof(i)求i类型大小是4,按照此分析来看,结果应该选择B,但是sizeof的返回值类型实际为无符号整形,因此编译器会自动将左侧i自动转换为无符号整形的数据,-1对应的无符号整形是一个非常大的数字,超过4或者8,

下列程序段的输出结果为( )

unsigned long pulArray[] = {6,7,8,9,10};
unsigned long *pulPtr;
pulPtr = pulArray;
*(pulPtr + 3) += 3;
printf("%d,%d\n",*pulPtr, *(pulPtr + 3));
unsigned long pulArray[] = {6,7,8,9,10};
unsigned long *pulPtr;
pulPtr = pulArray; // 数组名代表数组首元素地址,因此pulptr指向的是数组中第一个元素的位置
*(pulPtr + 3) += 3; // pulptr+3访问的是数组中第三个元素(数组下标从0开始),故将9改为9+3=12
printf("%d,%d\n",*pulPtr, *(pulPtr + 3)); // 打印第一个和第三个元素,因此:打印6和12

经典题目

下面关于指针运算说法正确的是:( )

A.整形指针+1,向后偏移一个字节

B.指针-指针得到是指针和指针之间的字节个数

C.整形指针解引用操作访问4个字节

D.指针不能比较大小

注意:此题是有问题的,说法不严谨,如果将整形指针理解成int*类型的指针,那么一下说法解析如下

A:错误,整形指针+1,向后便宜一个整形类型的大小,即4个字节

B:错误,两个指针相减,指针必须指向一段连续空间,减完之后的结构代表两个指针之间相差元素的个数

C:正确,整形指向的是一个整形的空间,解引用操作访问4个字节

D:指针中存储的是地址,地址可以看成一个数据,因此是可以比较大小的

你可能感兴趣的:(C语言练习,c语言,算法,前端)