C语言入门习题如何解决?

2026-04-28 02:381阅读0评论SEO资源
  • 内容介绍
  • 相关推荐

本文共计7570个文字,预计阅读时间需要31分钟。

C语言入门习题如何解决?

分支语句习 题 1. 下面代码的执行结果:

分支语句习题

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.charD.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函数库中的字符串操作函数
  • 比如:chararr[]="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.数组操作:创建一个整型数组,完成对数组的操作

  1. 实现init()初始化数组为全0
  2. 实现print() 打印数组的每个元素
  3. 实现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

分析:整数在内存中是倒序存放

C语言入门习题如何解决?

任何一个变量/表达式都有两个属性:值属性 类型属性

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; }

本文共计7570个文字,预计阅读时间需要31分钟。

C语言入门习题如何解决?

分支语句习 题 1. 下面代码的执行结果:

分支语句习题

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.charD.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函数库中的字符串操作函数
  • 比如:chararr[]="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.数组操作:创建一个整型数组,完成对数组的操作

  1. 实现init()初始化数组为全0
  2. 实现print() 打印数组的每个元素
  3. 实现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

分析:整数在内存中是倒序存放

C语言入门习题如何解决?

任何一个变量/表达式都有两个属性:值属性 类型属性

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; }