分支语句习题
1.下面代码的执行结果
#include <stdio.h>
int main()
{
int i = 0;
for (i = 0; i < 10; i++)
{
if (i = 5)
printf("%d", i);
}
return 0;
}
输出:死循环输出5
分析:i=0时,进行循环判断部分i=0<10,执行循环语句,将i赋值为5并打印输出i,进入循环调整部分:i++ ,6 进入循环判断部分 6<10 ,执行循环语句将i赋值为5并打印输出i,进入循环调整部分:i++ ,6,一直这样5,6死循环下去,所以死循环输出5
2.if语句中0表示假,1表示真
偏颇的不够准确的说法 正确说法:0表示假,非0表示真
3.switch中的default子句可以放到任意位置 正确
分析:顺序的问题。case语句项与default子句(所有的case语句项不能匹配下执行default子句)顺序可以调换 (这里的任意位置并不是指随意乱放,不是指放到Switch外部。在不能打破原有任务的逻辑下任意调换)
switch中case后表达式只能是整形常量表达式 正确
分析:'a' , char也属于整型的一种 因为字符存储时存的是ascii码值,归类时char也会归类到整型中去
4.下面代码的执行结果
#include <stdio.h>
int fun(int a)
{
int b;
switch (a)
{
case 1:
b = 30;
case 2:
b = 20;
case 3:
b = 10;
default:
b = 0;
}
return 不;
}
int main()
{
printf("%d",fun(1));
return 0;
}
输出: 0
分析:a=1,进入case 1语句项执行b=30因为后面没有遇到break语句,就进入case 2 执行b=20,没有遇到break语句,再进入 case 3执行b=10,没有遇到break语句,再进入default子句执行b=0,执行完最后一条语句退出Switch语句,返回b=0 ,所以输出b=0
5.switch(c) 其中c不可以是什么类型:
A .int B.long C.char D.float 答案:D
6.写代码实现: 三个整数从大到小输出
#include <stdio.h>
void swap(int *px, int *py)
{
int c = 0;
c = *px;
*px = *py;
*py = c;
}
int main()
{ //三个整数从大到小输出
int a = 0, b = 0, c = 0;
//输入
scanf("%d %d %d", &a, &b, &c);
//调整 其他方法:1.排序 2.swap()
int tmp = 0;
if (a < b)
{
/* tmp = a;
a = b;
b = tmp;*/
swap(&a, &b);
}
if (a < c)
{
/*mp = a;
a = c;
c = tmp;*/
swap(&a, &c);
}
if (b < c)
{
/*tmp = b;
b = c;
c = tmp;*/
swap(&b, &c);
}
//输出
printf("%d %d %d\n", a, b, c);
return 0;
}
7.写代码实现打印1~100中3的倍数
#include <stdio.h>
int main()
{
int i = 0;
for (i = 1; i <= 100; i++) //法一
{
if (i % 3 == 0)
{
printf("%d ", i);
}
}
for (i = 3; i <= 100; i += 3) //法二
{
if (i % 3 == 0)
{
printf("%d ", i);
}
}
return 0;
}
8.求两个数的最大公约数
#include <stdio.h>
int main()
{ //最大公约数
int a = 0;
int b = 0;
scanf("%d %d", &a, &b);
//求最大公约数:
//暴力求解: 一个一个试除 不够高效
// eg;6和9的最大的公约数:不会超过6 找<=6的所有数字
//从大到小试除直到找到第一个能被这两个数同时整除的数字:最大公约数
int m = (a < b) ? a : b; //找出较小值
while (1)
{
if (a % m == 0 && b % m == 0)
{
break;
}
m--;
}
printf("%d\n", m);
//辗转相除法 效率高
// eg 24和18的最大公约数 a(24)%b(18)=c(6) a(a=b)(18)%b(b=c)(6)=c(0) 最大公约数:6 即a%b等于0时b的值 速度很快
// 输入18 24还满足?18%24=18 a=b=24 b=c=18 发现又交换回来了
int c = 0;
while (c = a % b) //优化:省略赋值,直到c=0 退出循环
{
// int c = a % b;
a = b;
b = c;
}
printf("%d\n", b);
return 0;
}
//递归?
引申:最小公倍数 ? 暴力求解:从两个数里面较大值为起点不断加1试 同时整除的第一个数值,
max%a==0&&max%b==0//暴力求解的核心
效率更高的做法:a*b/最大公约数=最小公倍数
循环语句习题
1.
分析:先判断再执行循环体 答案B
2.以下程序输出的结果是:
#include <stdio.h>
int main()
{
int a=0,b=0;
for(a=1,b=1;a<=100;a++)
{
if(b>=20) break;
if(b%3==1)
{
b=b+3;
continue;
}
b=b-5;
}
printf("%d\n",a);
return 0;
}
输出:8
分析:先进入for循环初始化部分,再进入for循环判断部分,a<=100,执行循环语句,b%3==1满足进入第二个分支语句,b=4,continue,跳过本次循环后面的代码来到调整部分,a++,a=2,再继续进入for循环判断部分,以此类推,由上分析,b+=3执行完之后才会来到a++部分,又因为b>=20就可以跳出循环,即b=1+3*7时跳出循环,也就说b+=3执行了7次,那么a++也会执行7次1+1*7=8
3.写代码实现:求1~100中所有整数出现多少个数字9?
#include <stdio.h>
int main()
{ // 1~100中整数出现数字9的个数 十位上数字9 个位上数字9
int i = 0;
int count = 0; //计数
for (i = 1; i <= 100; i++)
{
if (i % 10 == 9) //个位上是否为数字9
count++;
if (i / 10 == 9) //十位上是否为数字9
count++;
}
printf("count = %d", count);//输出count = 20
return 0;
}
注意:写成 if else if这种形式只是一个多分支的if语句,只会选择一个分支进去,只会进去一次 i=99,只计了个位的9,十位9不会进去判断了,就会漏值,所以还是写两个if语句,两个都会进去判断,不会出现差漏
4.分数求和,计算:1/1-1/2+1/3-1/4+1/5+......+1/99-1/100
#include <stdio.h>
int main()
{
int i = 0;
double sum = 0;
int flag = 1; //实现正负交替
for (i = 1; i <= 100; i++)
{
sum = sum + flag * (1.0 / i);
flag = -flag;
}
printf("%lf\n", sum);
return 0;
}
5.求10个整数中的最大值
#include <stdio.h>
int main()
{ //求10个整数中的最大值
// int arr[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; //初始化预设十个数
int arr[10] = {0};
// 写成arr[]={0} 等价于 arr[1]={0} 输入多个数字会出现数组越界
int j = 0;
for (j = 0; j < 10; j++)
{
scanf("%d", &arr[j]); //输入10个值
}
int max = arr[0];
int i = 0;
for (i = 1; i < 10; i++)
{
if (max < arr[i])
{
max = arr[i];
}
}
printf("%d\n", max);
return 0;
}
6.打印9*9乘法表
#include <stdio.h>
int main()
{ //打印9*9乘法表
int i = 0;
int j = 0;
for (i = 1; i <= 9; i++) //打印9行
{
for (j = 1; j <= i; j++) //打印每一项
{
printf("%d*%d=%2d ", i, j, i * j); //%2d打印两位整数(只有一位整数用空格补齐)
//%2d两位右对齐 %-2d两位左对齐
}
printf("\n");
}
return 0;
}
函数习题
1.
分析:
A return (3,4); (3,4)被当作一个逗号表达式(从左向右依次计算,整个表达式结果是最后一个表达式结果) 只会返回4(最后一个表达式结果)
B int arr[ ]本质上是 int* arr(arr是一个指针变量,存放的是数组首元素的地址) arr[0]等价于*(arr+0) , arr[1]等价于*(arr+1) (arr指向第一个元素 arr+1指向第二个元素)如下图观察调试结果也显示可以将3,4返回到主函数
C
#include<stdio.h>
void test(int *px, int *py)
{
*px = 3;
*py = 4;
}
int main()
{
int a = 0, b = 0;
test(&a, &b);
printf("%d %d\n",a,b);
return 0;
}
D
#include<stdio.h>
int a = 0, b = 0;
void test()
{
a=3;
b=4;
}
int main()
{
test();
printf("%d %d\n",a,b);
return 0;
}
2.打印n*n乘法表 (函数实现;能指定行和列)
#include <stdio.h>
void print_table(int n)
{
int i = 0;
int j = 0;
for (i = 1; i <= n; i++) //打印n行
{
for (j = 1; j <= i; j++) //打印每一项
{
printf("%d*%d=%2d ", i, j, i * j); //%2d打印两位整数(只有一位整数用空格补齐)
//%2d两位右对齐 %-2d两位左对齐
}
printf("\n");
}
}
int main()
{ //打印n*n乘法表 1.函数实现 2.能指定行和列
int n = 0;
scanf("%d", &n);
print_table(n);
return 0;
}
递归习题
1.字符串逆序(递归实现)
编写一个函数 reverse(char * str) (递归实现)
- 实现: 将參数字符申中的字符反向排列,不是逆打
- 要求: 不能使用C函数库中的字符串操作函数
- 比如:char arr[]="abcdef" 逆序之后数组的內容变成: fedcba
方法一:迭代实现
#include <stdio.h>
#include <string.h>
//字符串逆序 迭代实现
void reverse(char arr[])
{
int left = 0;
int right = strlen(arr) - 1;
// sz-2
while (left < right) //第n个和倒数n个交换 >=没有可交换的了
{ //循环 迭代
int tmp = arr[left];
arr[left] = arr[right];
arr[right] = tmp;
left++;
right--;
}
}
int main()
{ //字符串反向排序(字符串数组存储内容反向) 函数实现
char arr[] = "abcdef";
reverse(arr);
printf("%s\n", arr);
return 0;
}
方法二:递归实现(只有一个参数)
#include <stdio.h>
#include <string.h>
//只有一个参数 递归实现
int my_strlen(char *str)
{
int count = 0;
while (*str != '\0')
{
count++;
str++;
}
return count;
}
// 字符串逆序
//字符串反向排序(字符串数组存储内容反向) 递归实现
void reverse(char *str)
{ //逆序 abcdef ->交换af+逆序bcde ->交换af 交换be+逆序cd -> 交换af 交换be 交换cd
// 1.tmp=a a=f (暂时不把a放到f处)2.f=\0(让从b开始向后组成一个字符串)3.逆序bcde 4.f=tmp
char tmp = *str;
int len = my_strlen(str);
*str = *(str + len - 1); //这里不能sizeof求字符串字符串大小,这里数组没有传过来,传的是地址
*(str + len - 1) = '\0';
if (my_strlen(str + 1) >= 2) //中间剩一个字符就不用逆序了
reverse(str + 1); //要加限制条件否则会死递归
*(str + len - 1) = tmp;
}
int main()
{
char arr[] = "abcdef";
reverse(arr);
printf("%s\n", arr);
return 0;
}
方法三:递归实现(多参数) 以下代码是错误示范
#include <stdio.h>
//多参数(arr right left)递归实现
//逆序abcdef :先用left和right锁定的a和f进行交换 逆序bcde (left+1 right-1 再让新left和新right锁定的字符be进行交换 逆序cd)
//直到left >=right 中间没有可以交换元素
//不需要\0找结束位置,直接用left right 限制范围
void reverse(char arr[], int left, int right)
{
char tmp = arr[left];//元素交换了之后,再判断left<right,满足再次逆序中间的元素
arr[left] = arr[right];
arr[right] = tmp;
if (left < right)
reverse(arr, left + 1, right - 1);
}
int my_strlen(char *str)
{
int count = 0;
while (*str != '\0')
{
count++;
str++;
}
return count;
}
int main()
{
char arr[] = "abcdef";
int left = 0;
int right = my_strlen(arr) - 1;
reverse(arr, left, right); //将arr中left锁定的元素和right的元素之间的字符串进行逆序
printf("%s\n", arr);
return 0;
}
发现cd无法逆序,为什么?同时,当字符串是奇数个字符时又会逆序正确,偶数个字符则会逆序错误?
void reverse(char arr[], int left, int right)
{
char tmp = arr[left];//元素交换了之后,再判断left<right,满足再次逆序中间的元素
arr[left] = arr[right];
arr[right] = tmp;
if (left < right)
reverse(arr, left + 1, right - 1);
}
分析:先进行交换,在判断是否有中间元素,有就把中间元素逆序,这个代码思路感觉没有错,用实例来代入一下:
eg “ab"
第一次进入reverse():得到的参数:&arr[0] left=0 right=1 先进行元素交换(left和right指向的元素进行交换),交换完为:“ba”,此时left=0 right=1(从main中接收过来一直没有改变left和right的值)满足判断条件,又递归进入reverse() left + 1, right - 1
第二次进入reverse():得到的参数: &arr[0] left=1 right=0,先进行元素交换,交换完为:“ab”,再进行条件判断,此时left=1 ,right=0递归结束
所以全程一共交换了两次,相当于没有逆序
eg"abc"
第一次进入reverse():得到的参数:&arr[0] left=0 right=2 先进行元素交换,交换完为:“cba”,此时left=0 right=2 满足递归判断条件,又递归进入reverse() left + 1, right - 1
第二次进入reverse():得到的参数: &arr[0] left=1 right=1,先进行元素交换,因为此时left和right都指向了同一个元素,交换完还是为:“cba”,再进行条件判断,此时left=1 ,right=1 递归结束
eg"abcd"
第一次进入reverse():得到的参数:&arr[0] left=0 right=3 先进行元素交换,交换完为:“dbca”,此时left=0 right=3 满足递归判断条件,又递归进入reverse() left + 1, right - 1
第二次进入reverse():得到的参数: &arr[0] left=1 right=2,先进行元素交换,交换完还是为:“dcba”,此时left=1 ,right=2 满足递归判断条件,又递归进入reverse() left + 1, right - 1
第三次进入reverse():得到的参数:&arr[0] left=2 right=1,先进行元素交换,交换完为:“dbca”,再进行条件判断,此时left=2 ,right=1递归结束
中间那个的bc没有逆序
小结:left<right时中间才有元素进行交换,但是上面的程序却在left>=right时仍然进行了一次交换,所以出错了,奇数最后一次交换的是一个元素,相当于没有交换,所以逆序结果还是正确的,偶数是最中间的两个元素交换了两次,所以逆序结果出错
改进:元素进行交换时也放在left<right判断条件下,避免多余的交换
void reverse(char arr[], int left, int right)
{
if (left < right)
{
char tmp = arr[left];//元素交换了之后,再判断left<right,满足再次逆序中间的元素
arr[left] = arr[right];
arr[right] = tmp;
reverse(arr, left + 1, right - 1);
}
}
2.计算一个数的每位之和(递归):输入非负整数,返回组成它的数字之和
#include <stdio.h>
//#include <stdio.h>
//计算一个数的每位之和(递归)
int DigitSum(unsigned int n) // 1234
{ // DigitSum(1234)->DigitSum(123)+4->DigitSum(12)+3+4->DigitSum(1)+2+3+4
if (n > 9) //两位数及以上才进行拆分 一位数不用拆
return DigitSum(n / 10) + n % 10;
else
return n;
}
int main()
{
unsigned int n = 0;
scanf("%u", &n);
int sum = DigitSum(n);
printf("%d\n", sum);
return 0;
}
int DigitSum(unsigned int n) // 1234
{ // DigitSum(1234)->DigitSum(123)+4->DigitSum(12)+3+4->DigitSum(1)+2+3+4
if (n > 9) //两位数及以上才进行拆分 一位数不用拆
return DigitSum(n / 10) + n % 10;
else
return n;
}
int main()
{
unsigned int n = 0;
scanf("%u", &n);
int sum = DigitSum(n);
printf("%d\n", sum);
return 0;
}
3.递归实现N的K次方
#include <stdio.h>
//递归实现N的K次方
double Pow(int n, int k)//不要用pow避免与库函数冲突
{ // Pow(n,k)->n*Pow(n,k-1) (k>0)
// k=0 1 k>0 Pow(n,k) k<0 1.0/Pow(n,-k) 小数
if (k > 0)
return Pow(n, k - 1) * n;
else if (0 == k)
return 1;
else
return 1.0 / Pow(n, -k);
}
int main()
{
int n = 0;
int k = 0;
scanf("%d %d", &n, &k);
double ret = Pow(n, k);
printf("%lf\n", ret);
return 0;
}
4.小乐乐上课需要走n阶台阶,因为他腿比较长,所以每次可以选择走一阶或者走两阶,那么他一共有多少种走法?
输入描述:输入包含一个整数n (1 ≤ n ≤ 30)
输出描述:输出一个整数,即小乐乐可以走的方法数。
分析:n=1 fib(n)=1 n=2 fib(n)=2 n>2 fib(n)=fib(n-1)+fib(n-2) ( fib(n)表示计算走n个台阶的走法 ) 走一个台阶:只有一种走法 走两个台阶:只有两种走法(一次走一步,一次走两步) 走10个台阶有 fib(10) 种走法,第一步只走一步,还剩下9阶台阶,有fib(9)种步法;第一步走两步,还剩下8阶台阶,有fib(8)种步法。一共有fib(8)+fib(9)种步法=======> 走n个台阶,有fib(n)种走法,按第一步走一步和第一步走两步两种情况,一共有fib(n-1)+fib(n-2)种步法
#include <stdio.h>
int fib(int n)
{
if (n <= 2)
return n;
else
return fib(n - 1) + fib(n - 2);
}
int main()
{
int n = 0;
scanf("%d", &n);
int m = fib(n);
printf("%d", m);
return 0;
}
数组习题
1.
分析:答案:C a[10]=2 数组a[10]只有10 个元素下标0~9,此处越界访问了
2.
分析:(3,4)逗号表达式 从左向右依次计算,整个表达式的结果是最后一个表达式结果 (3,4)= 4 答案:B
int arr[] = {1,2,4,5};//{1,2,(3,4),5} 4*4=16byte
补充:
int num = 10; //num类型是int
int arr[10] = {0}//数组arr类型是int [10](去掉数组名剩下的部分)
//两种等价的写法
printf("%d\n", sizeof(arr)); //数组名 40
printf("%d\n", sizeof(int [10]));//数组的类型 40
//注意10不能省略掉 10也是类型的一部分
printf("%d\n", sizeof(int [5])); //20 换个数字就是另外一个数组的类型
3.
char str[]="hello world";
printf("%d\n",sizeof(str));//12 h e l l o _ w o r l d \0
printf("%d\n",strlen(str));//11 h e l l o _ w o r l d
sizeof是一个操作符,是用来变量或类型(类型不占空间的,还是看的这个类型所创建出来的变量)所占内存空间的大小,不关注内存中存放的具体内容。 单位是字节
strlen()是一个库函数,是专门求字符串长度的,只能针对字符串,从参数给定的地址向后一直找\0,统计\0之前出现的字符的个数
4.
分析:不是字符串长度,acY没有\0字符串长度是不确定的,可以大于或等于acX 数组长度:数组的元素个数 答案:C
注意:
- 随着数组下标由小变大,数组地址由低到高变化
- int arr[][3]={{0,2},{},{3,4,5}};//错误初始化 中间不能加一个空的{}
5.交换数组:将数组A和数组B的内容进行交换
#include <stdio.h>
int main()
{ //交换数组 (内容进行交换) 两个数组一样大
int arr1[] = {1, 3, 5, 7, 9};
int arr2[] = {2, 4, 6, 8, 0};
/* //错误的示范
int tmp[] = {0};
//1.tmp中就一个元素空间不够
//2.数组名是首元素地址 地址是一个常量值 不是空间 无法进行交换
tmp = arr1;
arr1 = arr2;
arr2 = tmp;*/
int i = 0;
int sz = sizeof(arr1) / sizeof(arr1[0]);
for (i = 0; i < sz; i++)
{
int tmp = arr1[i];
arr1[i] = arr2[i];
arr2[i] = tmp;
}
for (i = 0; i < sz; i++)
{
printf("%d ", arr1[i]);
}
printf("\n");
for (i = 0; i < sz; i++)
{
printf("%d ", arr2[i]);
}
return 0;
}
6.数组操作:创建一个整型数组,完成对数组的操作
- 实现init()初始化数组为全0
- 实现print() 打印数组的每个元素
- 实现reverse() 完成数组元素的逆置
#include <stdio.h>
//数组操作
//初始化函数 初始化为0
//打印函数
//逆置函数
void init(int arr[], int sz)
{
int i = 0;
for (i = 0; i < sz; i++)
{
arr[i] = 0;
}
}
void print(int arr[], int sz)
{
int i = 0;
for (i = 0; i < sz; i++)
{
printf("%d ", arr[i]);
}
printf("\n");
}
void reverse(int arr[], int sz)
{
int left = 0;
int right = sz - 1;
while (left < right)
{
int tmp = arr[left];
arr[left] = arr[right];
arr[right] = tmp;
left++;
right--;
}
}
int main()
{
int arr[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 0};
int sz = sizeof(arr) / sizeof(arr[0]);
print(arr, sz); //初始化前
reverse(arr, sz);
print(arr, sz); //逆序后
init(arr, sz);
print(arr, sz); //初始化后
return 0;
}
7.有一个整数序列(可能有重复的整数),现删除指定的某一个整数,输出删除指定数字之后的序列,序列中未被删除数字的前后位置没有发生改变。
输入描述:
- 第一行输入一个整数(0≤N≤50)。
- 第二行输入N个整数,输入用空格分隔的N个整数。
- 第三行输入想要进行删除的一个整数。
输出描述:输出为一行,删除指定数字之后的序列。
#include <stdio.h>
int main()
{
int n;
scanf("%d", &n);
int arr[n];//支持c99
// int arr[50] = {0};
int i = 0;
for (i = 0; i < n; i++)
{
scanf("%d", &arr[i]);
}
int del = 0;
scanf("%d", &del);
int j = 0;
//j作为下标锁定的位置就是用来存放不删除的数据的
//不需要创建新数组存放
for (i = 0; i < n; i++)
{
if (arr[i] != del)
{
// arr[j]=arr[i];
//j++; //两种写法等价
arr[j++] = arr[i];
}
}
for (i = 0; i < j; i++)
{
printf("%d ", arr[i]);
}
return 0;
}
8.输入n个成绩,换行输出n个成绩中最高分数和最低分数的差。
输入描述:
- 两行,第一行为n,表示n个成绩,不会大于10000。
- 第二行为n个成绩(整数表示,范围0~100),以空格隔开。
输出描述:一行,输出n个成绩中最高分数和最低分数的差。
方法一:
#include <stdio.h>
int main()
{
int n = 0;
scanf("%d", &n);
int arr[n];
int i=0;
for(i=0;i<n;i++)
{
scanf("%d",&arr[i]);
}
int max=arr[0];
for(i=0;i<n;i++)
{
if(arr[i]>max)
{
max=arr[i];
}
}
int min=arr[0];
for(i=0;i<n;i++)
{
if(arr[i]<min)
{
min=arr[i];
}
}
printf("%d",max-min);
return 0;
}
方法二://代码优化
#include <stdio.h>
int main()
{
int n = 0;
scanf("%d", &n);
int arr[n];
int i = 0;
int max = 0;
int min = 100;
for (i = 0; i < n; i++)
{
scanf("%d", &arr[i]);
if (arr[i] > max)
max = arr[i];
if (arr[i] < min)
min = arr[i];
}
printf("%d", max - min);
return 0;
}
操作符习题
1.下面代码的结果是( )
答案:B
分析:
c=++a;//先++再使用 a=a+1=6 c=a=6
b=++c,c++,++a,a++;
//=优先级大于逗号表达式
//b=++c c=c+1=7 b=c=7
//c++ c=c+1=8 ++a a=a+1=7 a++ a=a+1=8
b+=a++ + c;
//b=b+(a++)+c=7+8+8=23 a++ a=a+1=9
//a=9 b=23 c=8
2.统计二进制中1的个数,写一个函数返回参数二进制中1的个数
#include <stdio.h>
//方法1
/*int count_1(unsigned int n)
{ // 10 二进制:1010 十进制 %10 /10取出十进制每一位 1234 二进制:%2 /2 得到二进制每一位
// 10%2=0 10/2=5 5%2=1 5/2=2 2%2=0 2/2=1 1%2=1 1/2=0
//取出二进制的每一位就是取模的值 从最后一位开始
int count = 0;
while (n)
{
if (n % 2 == 1)
count++;
n /= 2;
}
return count;
}*/
//问题:输入负整数出错
// eg -1
// 10000000 00000000 00000000 00000001原码
// 11111111 11111111 11111111 11111110 反码
// 11111111 11111111 11111111 11111111 补码
//补码中32个1 按理说应该会输出32 结果却输出0
//改进:形参设置为无符号类型 将传递过来的-1 的补码看成很大的正数(第一位不再看成符号位)
//方法2 负数正数都行
/*int count_1(int n)
{
int count = 0, i = 0;
for (i = 0; i < 32; i++)
{
if ((n >> i) & 1 == 1)
//把数字n的二进制数的每一位移到到最低位 &1判断1/0
count++;
}
return count;
}*/
//法1法2效率不高
//方法3
// n=15
// n=n&(n-1)
//1111 n
//1110 n-1
//1110 n
//1101 n-1
//1100 n
//1011 n-1
//1000 n
//0111 n-1
//0000 n 发现每进行一次按位与就会消失一个1 统计1的个数,可以看这个表达式执行几次即可
//只关注1的个数 效率高
int count_1(int n)
{
int count = 0;
while (n)
{
n = n & (n - 1);
count++;
}
return count;
}
//如果想判断一个数是否为2^n
//2^1 2 0010
//2^2 4 0100
//2^3 8 1000 发现2^n中二进制序列始终只有一个1
//if(n&(n-1)==0) ===>n就是2^n (n&(n-1)执行一次去掉一个1,而2^n只有一个1)
int main()
{ //统计二进制中1的个数
int n;
scanf("%d", &n);
int m = count_1(n);
printf("%d\n", m);
return 0;
}
3.求两个数二进制中不同的个数
#include <stdio.h>
// 两个int 二进制序列中不同的位数的统计
//方法1
/*int count_diff(int m, int n)
{
int count = 0, i = 0;
for (i = 0; i < 32; i++)
{
if (((m >> i) & 1) != ((n >> i) & 1))
{
count++;
}
}
return count;
}*/
//方法2
int count_diff(int m, int n)
{
int num = m ^ n;
//相同为0 相异为1 只关注相异的
int count = 0;
while (num)
{
num = num & (num - 1);
count++;
}
return count;
}
int main()
{
int m = 0, n = 0;
scanf("%d %d", &m, &n);
int ret = count_diff(m, n);
printf("%d", ret);
return 0;
}
4.打印整数二进制的奇数位和偶数位,获取整数的二进制序列中的所有的偶数位和奇数位,分别打印出二进制序列
//假设最低位为第1位
//10
//00000000 00000000 00000000 00001010
#include <stdio.h>
int main()
{
//获取奇数位数字 第N位来到最低位移动N-1
int num = 0;
scanf("%d", &num);
int i = 0;
//第31位移动30位到最低位 第1位移动0位到最低位
for (i = 30; i >= 0; i-=2)
{
printf("%d ", ((num >> i) & 1));
}
printf("\n");
//获取偶数位数字
// 第32位移动31位到最低位 第2位移动1位到最低位
for (i = 31; i >= 1; i-=2)
{
printf("%d ", ((num >> i) & 1));
}
return 0;
}
5.
答案:D 分析:vs:4+4+4=12 linux:3+3=6 6+4=10 问题代码
6
//全局变量 静态变量都是放在静态区的
//全局变量 静态变量不初始化的时候,默认会被初始化为0
//局部变量放在栈区不初始化默认会被初始化为随机值
//sizeof这个操作符计算返回的结果是size_t类型的,是无符号整型的
//表达式中有int和unsigned int会进行算术转换 int -> unsigned int
//有符号int:-1-->
//无符号int:11111111 11111111 11111111 11111111 看成一个很大的正整数
//10000000 00000000 00000000 00000001
//11111111 11111111 11111111 11111110
//11111111 11111111 11111111 11111111 补码
//答案:
7 打印X形图案
输入描述: 多组输入,一个整数(2~20),表示输出的行数,也表示组成“X”的反斜线和正斜线的长度。
输出描述: 针对每行输入,输出用“*”组成的X形图案。
#include <stdio.h>
int main()
{
int i = 0, j = 0, num = 0;
while (scanf("%d", &num) != EOF)
{
for (i=0;i<num;i++)
{
for(j=0;j<num;j++)
{
if(j==i) printf("*");
else if(j==num-1-i) printf("*");
else printf(" ");
}
printf("\n");
}
}
return 0;
}
指针习题
1.下面代码的结果是
分析:short*类型指针的特点,解引用一次可以访问两个字节 +1一次可以跳过两个字节 数据在内存中存放时,有一个顺序的问题:大小端字节序
整型数据在内存中存放时是倒着存放的
输出00345
2
输出:6 12 答案:C
3
答案:C 分析: D指针有关系运算可以比较大小
4
分析:整数在内存中是倒序存放
任何一个变量/表达式都有两个属性:值属性 类型属性
int a=3;
a+4.5——>值属性:7.5 类型属性double(int算术转换为double+double)
a=3——>值属性:3 类型属性:int
&a——>值属性:a的地址 类型属性:int*
答案:C
5 使用指针打印数组内容
6 字符串逆序
使用scanf(),遇到空格就不读取了所以不用scanf()用gets()
第一个和最后一个交换,以此类推
#include <stdio.h>
#include <string.h>
int main()
{
char arr[10001] = {0};
//接收字符串有空格 使用scanf(),遇到空格就不读取了
gets(arr);
int left = 0;
int right = strlen(arr) - 1;
while (left < right)
{
char tmp = arr[left];
arr[left] = arr[right];
arr[right] = tmp;
left++;
right--;
}
printf("%s\n", arr);
return 0;
}
7
#include <stdio.h>
int main()
{ //求Sn=a+aa+aaa+aaaa+aaaaa 前5项之和
int a = 0;
int n = 0;
scanf("%d %d", &a, &n);//a代表每一项数字 n:项数
int i = 0;
int sum = 0;
int k = 0;//每一项代表的数字
for (i = 0; i < n; i++)
{
k = k * 10 + 2;
sum += k;
}
printf("%d\n", sum);
return 0;
}
8 求0~100000的水仙花数并输出:n位数字的各位数字的n次方之和等于本身eg:153=13+53+33
//这里的水仙花数不是严格意义上的水仙花数(水仙花数一般指三位自幂数)
//12345
#include <stdio.h>
#include <math.h>
//方法一
int main()
{
int i = 0;
for (i = 0; i <= 100000; i++)
{
//1.计算i是几位数 ->n 2.得到i的每一位 计算n次方之和
//认为任何数至少是一位数n从1开始
int n = 1;
int tmp = i;
//避免在循环内部改变循环变量 而且下面还要计算i的每一位n次方之和
while (tmp / 10)
{
n++;
tmp /= 10;
}
tmp = i;
int sum = 0;//每个i都要进行计算不能放到循环外面去
while (tmp)
{
sum += pow(tmp % 10, n);//pow返回类型为double型,会有算术转换造成精度丢失 但是我们知道这里是整数没有误差的
tmp /= 10;
}
if (sum == i)
{
printf("%d ",i);
}
}
return 0;
}
//方法二:函数
#include <stdio.h>
#include <math.h>
int if_narcissistic_number(int i)
{
//1.计算i是几位数 ->n 2.得到i的每一位 计算n次方之和
//认为任何数至少是一位数n从1开始
int n = 1;
int tmp = i;
//避免在循环内部改变循环变量 而且下面还要计算i的每一位n次方之和
while (tmp / 10)
{
n++;
tmp /= 10;
}
tmp = i;
int sum = 0;//每个i都要进行计算不能放到循环外面去
while (tmp)
{
sum += pow(tmp % 10, n);//pow返回类型为double型,放到int造成精度丢失 但是我们知道这里是整数没有误差的
tmp /= 10;
}
/*if (sum == i)
{
return 1;
}
else
{
return 0;
}*/
//优化
return sum == i;
}
int main()
{
int i = 0;
for (i = 0; i <= 100000; i++)
{
if (if_narcissistic_number(i))//_+小写字母的书写习惯
{
printf("%d ",i);
}
}
return 0;
}
9 打印菱形
//上+下 上面有line行 下面line-1行
#include <stdio.h>
int main()
{
//上
int i = 0;
int line = 0; //打印上半部分的行数
scanf("%d", &line);
for (i = 0; i < line; i++)
{
//打印每一行
int j = 0;
//打印空格
for (j = 0; j < line - 1 - i; j++)
{
printf(" ");
}
//打印*
for (j = 0; j < 2 * i + 1; j++)
{
printf("*");
}
printf("\n");
}
//下
for (i = 0; i < line - 1; i++)
{
//打印每一行
int j = 0;
//打印空格
for (j = 0; j <= i; j++)
{
printf(" ");
}
//打印*
for (j = 0; j < 2 * (line - 1 - i) - 1; j++)
{
printf("*");
}
printf("\n");
}
return 0;
}
10
答案:A 分析:int(*arr)[10]:arr是一个数组指针(指向了[10]),指向数组的指针*arr arr与*组合表示arr是指针;数组arr[10] arr与[10]结合表示arr是数组名
结构体习题
1
答案:B 分析:优先级高于* 不加()就不行 p.a 本身就是错的解引用又用在了a上也是错的
2
分析:输出:wang
3.喝汽水问题
#include <stdio.h>
int main()
{
int money = 0;
scanf("%d", &money);
/*int total = money;//方法一
int empty = money;
//置换
while (empty >= 2)
{
total += empty / 2;
empty = empty % 2 + empty / 2;
}
printf("%d\n", total);*/
//规律 2*money-1 方法二
if (money > 0)
printf("%d\n", 2 * money - 1);
else
printf("%d\n", 0);
return 0;
}