C基础:45道练习题汇总(初学者加油)

一、基础练习

练习1:输入两个数,实现两个数的交换

 法1:三杯水交换(常规的方式)

#include <stdio.h>

int main(int argc, const char *argv[]){
    int a = 0;
    int b = 0;
    int temp = 0; //定义一个临时变量

    printf("输入两个数字:");
    scanf("%d%d",&a,&b); //10  20

    temp = a;
    a = b;
    b = temp;
    printf("a = %d, b = %dn", a, b);//20  10
    return 0;
}

法2:如何不使用额外的内存空间,实现两个交换(没有空杯子了)

 三次异或实现交换  (异或:不同为1,相同为0

#include <stdio.h>
                 
int main(int argc, const char *argv[])
{
    int a = 0;
    int b = 0;
    printf("请输入两个数字:");
    scanf("%d%d",&a,&b); //10 20  --> 二进制分别为 a: 0000 1010 b: 0001 0100 

    a = a ^ b;  
       a: 0000 1010   
       b: 0001 0100
       a= 0001 1110    <--现在的a被赋值成这个值

    b = a ^ b;
       a: 0001 1110
       b: 0001 0100
       b= 0000 1010    <--现在的b被赋值成这个值
     
    a = a ^ b; 
        a: 0001 1110
        b: 0000 1010
        a= 0001 0100   <--现在的a被赋值成这个值

    printf("a = %d b = %dn", a, b);   //20 10   
    return 0;
}

练习2:改变灯的状态

 灯的编号顺序 8 7 6 5 4 3 2 1,进行如下操作。

1. 有8个led灯,分别在8个不同的教室

2. 8个灯初始状态未知

3. 点亮第 1 3 5 7 号灯

4. 把5号灯熄灭

5. 把4号灯点亮

6. 把除了4号灯的其他灯全熄灭

#include <stdio.h>
                 
int main(int argc, const char *argv[])
{   
    unsigned char led = 0; //使用无符号char(1个字节= 8bit)类型来表示八个灯的状态

    //点亮第1 3 5 7号灯
    led = led | 0x55;  //这样不会影响2 4 6 8 原有的状态
                       //若直接赋值,把1 3 5 7 点亮的同时,把其他灯熄灭了

    //把5号灯熄灭
    led = led & ~(1<<4);
    printf("led = %#xn", led);//0x55

    
    //把4号灯点亮
    led = led | (1<<3);
    printf("led = %#xn", led);//0x4d

    //把除了4号灯的其他灯全熄灭
    led = led & (1<<3);
    printf("led = %#xn", led);//0x08
             
    return 0;
}

二、分支控制语句练习题:if..else 语句

练习3:从终端输入一个字符:

如果是大写的 转换成小写,如果是小写的 转换成大写,如果是 0-9 按照 %d 输出对应整型的 0-9,其他字符 转换成 #,并输出

#include <stdio.h>
                 
int main(int argc, const char *argv[])
{
    printf("请输入一个字符:");

     //法1:输入字符方式
    char ch = getchar(); //getchar 表示在终端获取一个字符
    getchar(); //清理垃圾字符 回车

    //法2:输入字符方式
    char ch = 0;
    scanf("%c",&ch);

    if(ch >='A' && ch <='Z'){
        ch = ch + ('a'-'A');
        printf("%cn",ch); 
    }else if(ch >='a' && ch <='z'){
        ch = ch -('a'-'A');
        printf("%cn",ch); 
    }else if(ch >= '0' &&ch <= '9'){
        ch = ch - '0';
        printf("%dn",ch); 
    }else{
        ch = '#';
        printf("%cn",ch); 
    }
   
    return 0;
}

 练习4输入一个年份 判断是平年还是闰年。

(闰年: 能被4整除且不能被100整除 或者能被400整除)提示:整除: 没有余数 year%4==0

2000 闰年、2004 闰年、2022 平年、1900 平年

#include <stdio.h>
                 
int main(int argc, const char *argv[])
{
    int year = 0;
    printf("输入一个年份:");
    scanf("%d",&year);
    
    if(year%4 == 0 && year%100 != 0 || year%400 == 0){
        printf("闰年n");
    }else{
        printf("平年n");
    }

    return 0;
}

练习5:输入三角形的三边长,判断能否构成三角形

如果能,输出是什么三角形(等边、等腰、直角、普通)。如果不能,输出不能

#include <stdio.h>
                 
int main(int argc, const char *argv[])
{
    int a = 0, b = 0, c = 0;
    printf("请输入三角形的三边长:");
    scanf("%d%d%d",&a,&b,&c);  

    if( a+b>c && b+c>a && a+c>b){   //构成三角形:任意两边大于第三边
        printf("能构成三角形n");
        if(a == b && b == c && a==c){
            printf("等边三角形n");
        }else if(a==b || b==c || a==c){
            printf("等腰三角形n");
        }else if(a*a + b*b == c*c ||a*a + c*c == b*b || a*a + c*c == b*b ){
                          //上面判断不能用a^2 + b^2 = c^2 ,在c语言中"^" 是异或 

        printf("直角三角形n");  
        }else{
            printf("普通三角形n");
        }
    }else{
        printf("不能构成三角形n");
    }   

    return 0;
}

练习6:求孩子身高

每个做父母的都关心自己孩子成人后的身高,据有关生理卫生知识与数理统计分析表明,影响小孩成人后身高的因素有遗传、饮食习惯与坚持体育锻炼等。小孩成人后身高与其父母身高和自身性别密切相关。父亲、母亲、孩子 身高都用double,设faHeight为其父身高,moHeight为其母身高,基础身高预测公式为:

        男性成人时身高 = (faHeight + moHeight) * 0.54(cm)

        女性成人时身高 = (faHeight * 0.923 + moHeight) / 2(cm)

此外,如果喜爱体育锻炼,那么可在基础身高上增加身高 2%

如果有良好的卫生饮食习惯,那么可在基础身高上增加身高1.5%

程序要求:父亲的身高与母亲的身高、小孩的性别、是否喜爱体育锻炼和是否有良好的卫生饮食习惯也从键盘上输入,最终输出预测的身高。

提示:

小孩性别的输入方式,可在屏幕给出提示“请输入小孩的性别(男孩输入1,女孩输 0):”,

然后通过if语句来判断从键盘输入的字符是 1 还是 0。是否喜爱体育锻炼也可以通过类似的方式实现。

测试:

        180 160 男 体 习 --->190.026   %.3f

#include <stdio.h>
                 
int main(int argc, const char *argv[])
{
    double faHeight = 0;
    double moHeight = 0;
    double childHeight = 0;
    double dpe = 0;   //体育增量
    double dfood = 0; //习惯增量
    int sex = 0; //1 男 0 女
    int pe = 0;  //1 喜欢 0 不喜欢
    int food = 0;//1 喜欢 0 不喜欢
    printf("请输入父亲的身高与母亲的身高:");
    scanf("%lf%lf", &faHeight, &moHeight);

    printf("请输入孩子的性别(1 男, 0 女):");
    scanf("%d",&sex);

    printf("是否喜爱体育锻炼(1 喜爱, 0 不喜爱):");
    scanf("%d",&pe);

    printf("是否有良好的卫生饮食习惯(1 有, 0 没有):");
    scanf("%d",&food);

    if(sex == 1){
        childHeight = (faHeight + moHeight) * 0.54;
    }else if(sex = 0){
        childHeight = (faHeight*0.923 + moHeight) / 2;
    }

    if(pe == 1){
        dpe = childHeight *0.02;  //若pe = 0时,表示 dpe 还为初始值0
    }

    if(food == 1){               //若food = 0时,表示 dfood 还为初始值0
        dfood = childHeight *0.015;
    }

    childHeight = childHeight + dpe + dfood; 
    printf("%.3fn",childHeight);

    return 0;
}

 三、switch..case 语句练习题

练习7:实现一个简易的计算器功能

只能操作一个运算符即可 (+ - * / %)。输入表达式 输出结果

如: 5+4 = 9   3*4= 12 10%4 = 2

#include <stdio.h>
                 
int main(int argc, const char *argv[])
{
    int a = 0;
    int b = 0;
    char operator = 0;
    
    printf("请输入:");
    scanf("%d %c%d", &a, &operator, &b);
    //在%c前加一个空格,表示清理垃圾字符。若不加必须输入如:a+b 不能带空格                            
    
    switch(operator){
        case '+':
            printf("%d + %d = %dn", a, b, a+b);
            break;
        case '-':
            printf("%d - %d = %dn", a, b, a-b);
            break;
        case '*':
            printf("%d * %d = %dn", a, b, a*b);
            break;
        case '/':
            printf("%d / %d = %fn", a, b, (float)a/(float)b);
    //因为a和b本身是int类型 计算的结果会舍弃小数位,所以要转换成float参与运算

            break;
        case '%':
            printf("%d %% %d = %dn", a, b, a%b);  
       //要想打印 % 必须输入 %% 才行

            break;
    }         
    return 0;
}

练习8:学生成绩管理

输入一个学生的成绩,[90,100] A 、[80,90) B  、[70,80) C 、[60,70) D 、[0,60) 不及格 、其他 输入错误。使用switch..case 语句实现

#include <stdio.h>
                 
int main(int argc, const char *argv[])
{   
    int ret = 0;
    int score = 0;
    printf("输入一个学生的成绩:");
    ret = scanf("%d",&score); 
    //scanf函数执行成功返回值是 按指定格式输入变量的个数
    //scanf函数未按照格式输入时,数据并没有存到变量中,此时返回值为0,即ret = 0。
    //在本代码中若按int格式输入则return 1,未按格式输入则return 0
    //输入'+'或其他非数字时,若不进行if语句的判断,则直接执行case 0:输出不及格
     
    getchar(); //清理下垃圾字符
    if(ret==1){
        switch(score / 10){
            case 10: //利用case击穿原则
            case 9:
                printf("An");
                break;
            case 8:
                printf("Bn");
                break;
            case 7:
                printf("Cn");
                break;
            case 6:
                printf("Dn");
                break;
            default:
                printf("不及格n");
                break;
        }
    }else{
         printf("输入错误n");
    }             
    return 0;
}

四、使用goto实现循环

练习9:使用goto计算 1+2+3+...+99+100 的和。

#include <stdio.h>
                 
int main(int argc, const char *argv[])
{
    int sum = 0; //sum必须初始化为0,否则随机值会影响计算的结果
    int i = 1; //用来控制循环次数的变量

LOOP: 
    sum += i;
    i++;
    if(i <= 100){
        goto LOOP; //goto XX; XX可以为其他的,上面跟这个相同即可。
    } 
    printf("%dn", sum);  
            
    return 0;
}

五、while 循环

练习10:使用while循环 计算 1~100 的和 

#include <stdio.h>
                 
int main(int argc, const char *argv[])
{
    int sum = 0; //sum必须初始化为0,否则随机值会影响计算的结果
    int i = 1; //用来控制循环次数的变量

    while(i <= 100){
        sum += i;
        i++;
    }
    printf("%dn", sum);  
            
    return 0;
}

练习11、猴子吃桃问题

一个猴子第一天摘了若干个桃,当即就吃了一半数量的桃,没吃过瘾,又多吃了一个,第二天,将剩下的桃又吃了一半数量,没吃过瘾,又多吃了一个,以后的每一天都吃一半数量多一个,到第十天再想吃桃的时候,发现只剩一个桃了。问:猴子第一天摘了多少个桃。

用while循环实现。把每天吃之前的桃子数量 都打印出来 应该怎么做?

#include <stdio.h>
                 
int main(int argc, const char *argv[])
{
    
    int num = 1; //第十天剩一个
    int i = 0; //循环变量 控制循环次数

    while(i < 9){
        printf("猴子第%d天有%d个桃n",10-i,num);
        num = (num+1)*2;
        i++;
    }
    printf("猴子第一天有%d个桃n",num);
    return 0;
}

 

六、do..while 循环

练习12: do..while说明

#include <stdio.h>

int main(int argc, const char *argv[])
{
	int i = 0;
	do{
		//不管while后面的条件为真还是为假
		//代码块都会先执行一次
		printf("hello worldn");
		i++;
	}while(i<5);


	return 0;
}

七、for 循环

练习13:使用for循环 计算 1-100 的和

#include <stdio.h>
                 
int main(int argc, const char *argv[])
{
    int i = 0;
    int num = 0;
    for(i=1; i<101; i++){
        num += i;  // += 为复合赋值运算符 相当于num = num +i;
    }            
    printf("%dn",num);
    return 0;
}

练习14:输出 [100,999] 范围内所有的水仙花数

水仙花数:个*个*个 + 十*十*十 + 百*百*百 == 自身

例如 153:1*1*1 + 5*5*5 + 3*3*3 = 1 + 125 + 27 == 153

所以 153 就是一个水仙花数

答:153、370 、371、 407

#include <stdio.h>
                 
int main(int argc, const char *argv[])
{
    int ge = 0;
    int shi = 0;
    int bai = 0;

    int i = 0;
    for(i = 100; i < 1000; i++){ 

        // 不要在循环里面定义变量 因为循环里面定义的变量的生命周期和作用域都是循环的 
        // 循环每执行一次 都会释放原来的空间 然后重新分配 会有时间上的开销 效率低
        
        ge = i % 10;
        shi = i /10 % 10;
        bai = i / 100;
        if(ge*ge*ge + shi*shi*shi + bai*bai*bai == i){
            printf("%d 是一个水仙花数n",i);
        }
    }             
    return 0;
}

练习15:输入一个日期 输出这个日期是这一年的第几天

注意,得考虑平年闰年的问题。如:输入:2021-3-24

输出:2021年3月24日是2021年的第 83 天

#include <stdio.h>
                 
int main(int argc, const char *argv[])
{
    //输入日期的变量
    int year = 0;
    int mon = 0;
    int day = 0;

    int mon2_day = 0; //2月天数变量
    int mon_day = 0;  //月份的天数
    int sum_day = 0;  //总天数
    int i = 1;        //月份初始为1月
    printf("输入一个日期:");
    scanf("%d-%d-%d",&year,&mon,&day);
    //判断2月有多少天数
    if((year%4 == 0 )&& (year%100 != 0) || year%400 == 0){
        mon2_day = 29;
    }else{
        mon2_day = 28;
    }

    if(mon >= 0 && mon <= 12 ){ //判断输入月份是否正确
        while(i < mon ){ //若输入为5月,循环求出前几个月的月份天数
            switch(i){
                case 1:case 3:case 5:case 7:case 8:case 10:case 12:
                    mon_day = 31;break;
                case 2:mon_day = mon2_day;break;
                case 4:case 6:case 9:case 11:mon_day = 30;break;
            }
            sum_day = sum_day + mon_day; //月份天数递加
            i++;   //月份自增
        } 
    }else{
        printf("请输入正确月份n");
    } 

    //当i 正好为 输入的月份时,注判断输入日期满足不超过当月的天数
    if(mon == i ){ 
        switch(i){  //求当月的天数
            case 1:case 3:case 5:case 7:case 8:case 10:case 12: 
                mon_day = 31;break;
            case 2:mon_day = mon2_day;break;
            case 4:case 6:case 9:case 11:mon_day = 30;break;
        }
        if(day <= mon_day){  //判断输入日期day 是否小于等于 当月天数
            sum_day = sum_day + day;  //若满足 用之前满月的天数加上输入的 day
            printf("%d年%d月%d日是%d年的第%d天n",year,mon,day,year,sum_day); 
        }else{
            printf("请输入正确日期n");
        } 
    }   
    return 0;
}

 八、控制语句综合练习

练习16:输出 [3,100] 范围内所有的偶数 

#include <stdio.h>
                 
int main(int argc, const char *argv[])
{
    int i = 0;
    //遍历3-100
    for(i=3; i <= 100; i++){
        if( i%2 == 0){
            printf("偶数 %dn",i);
        }
    }
                 
    return 0;
}

练习17:输入一个数,输出这个数的所有因子

如:输入 12 则输出 1 2 3 4 6 12

#include <head.h>
                 
int main(int argc, const char *argv[])
{
    int num = 0;
    int i = 0; 
    printf("输入一个数:");
    scanf("%d",&num);
    
    //遍历1-num,寻找因子 
    for(i = 1; i <= num; i++){

    //如果整数A除B,得出结果是没有余数的整数,就称B是A的因子。
        if(num%i == 0){
            printf("因子: %dn", i);
        }
    }               
    return 0;
}

练习18:输出 1000 以内的所有完数

完数:又叫完备数,也叫完美数。一个数除了自身之外的所有因子和还等于自身的数。

如: 6 就是一个完数 1 + 2 + 3 == 6

#include <stdio.h>
                 
int main(int argc, const char *argv[])
{
    int sum = 0;
    int i = 0; 
    int j = 0;

    //遍历1~1000 因为每个数都有可能是完数
    for(i = 1; i <= 1000; i++){
        sum = 0;  
        //注意:sum还保留着 上一个数的所有因子和,所有必须清0
        for(j = 1; j < i; j++){  //先获取i所有因子的和
            if(i%j == 0){
                sum += j;
            }
        }  
        //当for循环结束时 sum是i 除了自身之外所有因子的和

        //判断i是不是完数
        if(sum == i){ 
            printf("%d 是完数n", i);
        }   
    }           
    return 0;
}

练习19:输出 [3,100] 范围内所有的质数

质数:因子只有1和本身的数

解法1:根据循环结束的状态处理。

#include <stdio.h>
                 
int main(int argc, const char *argv[])
{
    int i = 0;
    int j = 0;
    //遍历  3-100
    for(i = 3; i<= 100; i++){
        // [2,i-1] 范围内 有任何一个能把i整除的数 都说明i不是质数
        for(j = 2; j < i; j++){
            //说明i不是质数
            if(i % j == 0){
                break;
            }
        }
        //上面的for循环有两种结束条件
		//1.由于 j==i 循环正常结束
		//2.由于break导致的退出,此种退出是  j一定是小于i的
        if(i == j){
            printf("%d 是质数n",i);
        }
    }             
    return 0;
}

解法2:使用标志位来处理

#include <stdio.h>

int main(){
	int i = 0;
	int j = 0;
	int flag = 0;  //0  不是质数   1 质数
	//遍历  3-100
	for(i = 3; i <= 100; i++){
		flag = 1;//每次需要重新置1
		// [2,i-1] 范围内 有任何一个能把i整除的数 都说明i不是质数
		for(j = 2; j < i; j++){
			if(i%j == 0){
				//说明i不是质数
				flag = 0;
			}
		}
		if(flag == 1){
			printf("%d 是质数n", i);
		}
	}
	return 0;
}

九、一维数组练习

练习20:求数组中最大值,及最大值的下标

定义一个int类型的一维数组,长度为10,从终端给数组赋值

找出数组中最大值,及最大值的下标,并输出。

#include <stdio.h>
                 
int main(int argc, const char *argv[])
{
    int i = 0;
    int s[10] = {0};
    //循环给数组成员赋值
    for(i = 0;i < 10; i++){
        scanf("%d",&s[i]);
    }  
    //找最大值及最大值下标           
    int max_index = 0;
    for(i = 1; i < 10; i++){
        if(s[max_index] < s[i]){
            //
            max_index = i;
        }
    }
    //当循环结束的时候 max_index 中记录的是最大值的下标
    //通过最大值的下标 也就找到了最大值
    printf("最大值:%d 下标:%dn",s[max_index],max_index);
    return 0;
}

练习21:斐波那契数列

斐波那契数列 1 1 2 3 5 8 13 21 ....  前两个数固定为 1 从第三个开始 依次是前两个数的和,

要求定义一个数组 类型为int 长度为20,给数组中的成员赋斐波那契数列的值,并输出

#include <stdio.h>
                 
int main(int argc, const char *argv[])
{
    int s[20] = {1,1}; //不完全初始化 没有初始化的位 默认用0初始化
    //循环给数组赋值 注:不要越界
    int i = 0;
    for(i = 0; i < 18; i++){
        s[i+2] = s[i] +s[i+1];
    }
    //输出数组的值
    for(i = 0; i < 20; i++){
        printf("%d ",s[i]);
    }
    printf("n");
    return 0;
}

练习22:使用循环打印下面的图案

 F

_FE

__FED

___FEDC

____FEDCB

_____FEDCBA

#include <stdio.h>
                 
int main(int argc, const char *argv[])
{
    int i = 0;
    int j = 0;
    char ch = 0;
    //外层循环控制行数
    for(i = 0; i < 6; i++){
        ch = 'F'; 
        //若使用后不置为F,就不是从F开始打印
        //内层循环控制每行的打印
        //打印每行的 下划线
        for(j = 0; j < i; j++){ 
            printf("_");
        }
        //打印每行的字母
        for(j = 0; j <= i; j++){
            putchar(ch); //向终端输出字符 也可以用printf
            ch--;
        }
        putchar(10); //换行 相当于printf("n");
    }              
    return 0;
}

练习23:冒泡排序

将一维数组按照上升的顺序排列

#include <stdio.h>
                 
int main(int argc, const char *argv[])
{
    int i = 0;
    int j = 0;
    int s[9] = {9,5,6,8,2,7,3,4,1};
    //排序前
    for(i = 0; i < 9; i++){
        printf("%d ",s[i]);
    }
    putchar(10);

    //升序 整个排序的流程
    int temp = 0; 
    int len = sizeof(s)/sizeof(s[0]);
    //外层循环控制比较的趟数 len-1 最后一趟只剩下一个元素就不用排序了
    for(i = 0; i < len-1; i++){
        //内层循环控制一趟排序比较的次数
        //每趟都能确定一个最值,最值在下一趟中就不用再参与比较了 所有len-i-1
        for(j = 0; j < len-i-1; j++){
            if(s[j] > s[j+1]){
                //交换
                temp = s[j];
                s[j] = s[j+1];
                s[j+1] = temp ;
            } 
        }
    }
    //排序后
    for(i = 0; i < 9; i++){
        printf("%d ",s[i]);
    }
    printf("n");
    return 0;
}

 十、二维数组练习

练习24:找出数组中最大值以及最大值的行号、列号,并输出 

定义一个int类型的3行4列的二维数组,并以行为单位完全初始化,找出数组中最大值,及最大值的行号,列号 并输出。

#include <stdio.h>
                 
int main(int argc, const char *argv[])
{
    int s[3][4] = {{12,32,42,11},
                    {7,4,90,6},
                    {1314,520,100,678}};
    
    int max_hang = 0;
    int max_lie = 0;
    
    int i = 0;
    int j = 0;
    for(i = 0; i < 3; i++){
        for(j = 0; j < 4; j++){
            if(s[max_hang][max_lie] < s[i][j]){
                max_hang = i;
                max_lie = j;
            }
        }
    }
    //当循环结束时  max_hang 里存的就是最大值的行号
    //max_lie 里存的就是最大值的列号
    printf("最大值:%d 行号:%d 列号:%dn",
                    s[max_hang][max_lie],max_hang,max_lie); 
        
    return 0;
}

十一、字符串处理函数 及字符串倒置

练习25:自己实现strlen函数的功能(计算字符串的长度)

#include <stdio.h>
                 
int main(int argc, const char *argv[])
{
    char s[32] = "book";
    int len = 0;
    //一般不确定长度的时候 使用while循环比较多
    while(s[len] != ''){  //0 和''都可以 '0'不可以
        len++;
    }
    //循环结束时 len 中保存的就是字符串的长度
    printf("%dn",len);            
    return 0;
}

练习26:自己实现 strcpy 函数的功能(字符串的复制)

#include <stdio.h>
                 
int main(int argc, const char *argv[])
{
    char s1[32] = "homework";
    char s2[32] = "happy";

    //要保证 s1 足够大 否则会越界
    int i = 0;
    while(s2[i] != ''){
        s1[i] = s2[i];
        i++;
    } 
    //将s2的''也拷贝给 s1
    s1[i] = s2[i];
    printf("s1 = %sn", s1);  //happy
    printf("s2 = %sn", s2);  //happy      
    return 0;
}

练习27:自己尝试实现 strcat 函数的功能(字符串的追加)

#include <stdio.h>
                 
int main(int argc, const char *argv[])
{
    char s1[32] = "homework";
    char s2[32] = "happy";

    int i = 0;
    int j = 0;
    //先找到s1 的 ''
    while(s1[i] != ''){
        i++;
    }
    //当上面循环结束的时候 i 就是s1 的 '' 的下标

    //开始追加
    while(s2[j] != ''){
        s1[i] = s2[j];
        i++;
        j++;
    }
    //将s2的 '' 也追加给s1
    s1[i] = s2[j];
    
    printf("%sn",s1);
    printf("%sn",s2);            
    return 0;
}

练习28:将字符串倒置输出

有一个以空格分隔的多个单词的字符串(空格的个数不确定有几个)

"this is a book"

将这个字符串 以单词为单位,倒置输出

"book a is this"

#include <stdio.h>
                 
int main(int argc, const char *argv[])
{
    char s[32] = "this   is  a book";
    
    //先将字符串整体倒置 ---> koob a  si   siht
    int i = 0;
    int j = 0;
    int temp = 0;
    //先找到字符串的最后一个字符
    while(s[j] != ''){
        j++;
    }
    //上面循环结束的时候, j是''的下标
    j--; //让 j 做为 'k' 的下标

    //开始交换前面数据和后面数据
    while(i < j){
        temp = s[i];
        s[i] = s[j];
        s[j] = temp;
        i++;
        j--;
    }
    printf("第一次处理:[%s]n",s);

    //进行单词倒置 -->book a  is   this
    int k = 0; //用来控制整体单词的循环,同时当个中间变量
    i = 0;  //控制空格
    j = 0;  //控制单词
    while(s[k] != ''){
        i = k;
        //当不是空格时,不执行
        while(s[i] == ' ' && s[i] != ''){ 
            i++;
        }
        //交换完所有单词时,i的下标在'',跳出循环
        while(s[i] == ''){  
            break;
        }
        // 没交换完单词时,i 的下标在每个单词的第一个字符上,将该下标给 j
        j = i; 
        while(s[j] != ' ' && s[j] != ''){
            j++;
        }
        k = j; //j 的下标在空格上,将j 的值赋给 k ,让k 赋给i 
                //若直接赋给i,会影响下面代码 i 的下标
        j--;   
        // j 的下标 在单词的最后一个字符上,i 在单词的第一个字符上
        while(i < j){  
            temp = s[i];
            s[i] = s[j];
            s[j] = temp;
            i++;
            j--;
        }
        
    }
    printf("第二次处理:[%s]n",s);
    return 0;
}

 十二、指针练习题

 练习29:看代码输出小练习题

int *p = NULL;

printf("%d %d %dn", p+1, p, (p+1)-p);

上面代码会输出什么?

#include <stdio.h>

int main(int argc, const char *argv[])
{
	int *p = NULL;
	printf("%d %d %dn", p+1, p, (p+1)-p);//4 0 1

	//p = NULL;  NULL 就是  (void *)0
	//p+1 :   0 + 1 个int  所以p+1 是4号地址   4
	//(p+1) - p:  两个int * 指针做差  得到的结果 相差的int的个数  1

	return 0;
}

练习30:根据要求写程序

定义一个普通变量a 类型为 int ,里面存储数据 9999

定义一个指针变量 p1 类型为 int *, 让p1指向a

然后通过p1将a中的内容修改为 0x12345678

再定义一个指针p2 类型为 char *,让p2也指向 a

用 %#x 输出 *p2 的值 以及 *(p2+1) *(p2+2) *(p2+3)的值

#include <stdio.h>
                 
int main(int argc, const char *argv[])
{
    int a = 9999;
    int *p1 = &a;
    *p1 = 0x12345678;
    char *p2 = (char *)&a;
    printf("%#x %#x %#x %#xn",*p2,*(p2+1),*(p2+2),*(p2+3));              
    return 0;
}
//我们使用的主机是小端存储
//所有结果:0x78 0x56 0x34 0x12

 练习31: 请你设计一个程序,判断主机是大端存储还是小端存储?

 

#include <stdio.h>
                 
int main(int argc, const char *argv[])
{
    int a = 0x12345678;
    char *p = (char *)&a;
    if(0x78 == *p){
        printf("小端n");
    }else if(0x12 == *p){
        printf("大端n");
    }                
    return 0;
}

练习32:看代码输出小练习题

int x = 0x41424344;

printf("%sn", &x);

上面的代码会输出什么?

答:小端存储的前提下,输出DCBA+不确定的东西。

练习33:使用指针实现 strlen 函数的功能

#include <stdio.h>
                 
int main(int argc, const char *argv[])
{
    char s[32] = "book";
    char *p = s;
    int count = 0;

 #if 0   // 法一
    while(*p != 0){
        count++;
        p++;
    }
#endif 

    //法二
    while(*p++){
        count++;
    }

    printf("%dn",count);              
    return 0;
}

练习34:使用指针实现 strcpy 函数的功能

#include <stdio.h>
                 
int main(int argc, const char *argv[])
{
    char s1[32] = "hello world";
    char s2[32] = "book";

    char *p1 = s1;
    char *p2 = s2;
    while(*p2 != ''){
        *p1 = *p2;
        p1++;
        p2++;
    }
    *p1 = *p2;

    printf("%sn", s1);
    printf("%sn", s2);               
    return 0;
}

练习35:使用指针实现 strcat 函数的功能

#include <stdio.h>
                 
int main(int argc, const char *argv[])
{
    char s1[32] = "hello world";
    char s2[32] = "book";

    char *p1 = s1; //将p1指向s1
    char *p2 = s2;

    //先将p1 下标循环到最后一个字符
    while(*p1 != ''){
        p1++;
    }
    //循环结束的时候  p指向 s1 的''
    //循环将s2 的字符追加到 s1 的后面
    while(*p2 != ''){
        *p1 = *p2;
        p1++;
        p2++;
    }
    *p1 = *p2;
    printf("%sn",s1);
    printf("%sn",s2);              
    return 0;
}

十三、指针和一维数组的练习

 练习36:字符串转换及统计数字个数

从终端输入一个字符串 gets,将所有的大写转成小写,将所有的小写转成大写,如果有数字,统计数字的个数,其他字符全部转换成 -,并输出转换后的字符串 及 数字的个数 

#include <stdio.h>
                 
int main(int argc, const char *argv[])
{
    char buff[128] = {0};
    gets(buff);
    printf("处理前:[%s]n",buff);
    char *p = buff;
    int count = 0;

    while(*p != ''){
        if(*p >= 'A' && *p <= 'Z'){
            *p = *p + ('a'-'A');
        }else if(*p >= 'a' && *p <= 'z'){
            *p = *p - ('a'-'A');
        }else if(*p >= '0' && *p <= '9'){
            count++;
        }else{
            *p = '-';
        }
        p++;
    }
    printf("处理后:[%s] 共有数字 %d 个n",buff,count);           
    return 0;
}

练习37:自己实现 atoi函数 的功能

atoi 将字符串的数字 转成整型的数

"12345678" ---> 12345678

#include <stdio.h>
                 
int main(int argc, const char *argv[])
{
    char buff[32] = "12345678";
    char *p = buff;
    int sum = 0;
    while(*p != ''){
        sum *= 10 ;   
        sum += (*p -'0');
        p++;
    }
    printf("%dn",sum); 

    return 0;
}

 练习38:使用命令行传参的方式 实现 简易计算器的加减功能

如: ./a.out 10 + 20 ---> 30

./a.out 100 - 50 ---> 50

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
                 
int main(int argc, const char *argv[])
{
    int left_value = atoi(argv[1]);
    int right_value = atoi(argv[3]);
    if(0 == strcmp(argv[2],"+")){
        printf("%d+%d=%dn",left_value,right_value,left_value + right_value);
    }else if(0 == strcmp(argv[2],"-")){
        printf("%d-%d=%dn",left_value,right_value,left_value + right_value);
    }          
    return 0;
}

十四、函数练习题

练习39:自己封装一个 能输出 1~n 求和结果的函数

n由参数传递,并调用测试

#include <stdio.h>
#include <stdlib.h>

//函数声明时 可以只写类型 不写形参名
void my_sum(int );
 
int main(int argc, const char *argv[])
{
    int num = atoi(argv[1]);
    my_sum(num);           
    return 0;
}

//定义时 必须要写 形参名 因为函数内部要使用这个名字
void my_sum(int n){
    int i = 0;
    int sum = 0;
    for(i = 0; i <= n; i++){
        sum += i;
    }
    printf("%dn",sum);
}

练习40:实现 两个整数 加减乘除 的功能

编写4个函数,my_add, my_sub, my_mul, my_div ,分别实现 两个整数 加减乘除 的功能,并调用测试。

#include <stdio.h>
#include <stdlib.h>

//函数声明                 
int my_add(int, int);
int my_sub(int,int);
int my_mul(int,int);
float my_div(int,int);

int main(int argc, const char *argv[])
{
    int a = atoi(argv[1]);
    int b = atoi(argv[2]);
    printf("%dn",my_add(a,b));
    printf("%dn",my_sub(a,b));
    printf("%dn",my_mul(a,b));
    printf("%.3fn",my_div(a,b));                
    return 0;
}

int my_add(int x,int y){
    return x+y;
}
int my_sub(int x,int y){
    return x - y;
}
int my_mul(int x,int y){
    return x * y;
}
float my_div(int x,int y){
    return (float)x/(float) y;
}

 练习41:将前面冒泡排序的功能 封装成函数

int sort(int *p, int len, int flag);

flag 1 升序 、 flag 0 降序 

#include <stdio.h>
//flag 1 升序  flag 0 降序
void my_sort(int *p,int len,int flag){
    int i = 0;
    int j = 0;
    int temp = 0;
    for(i = 0; i <len -1; i++){
        for(j = 0; j < len-i-1; j++){
            if(flag == 1){ //升序
                if(p[j] > p[j+1]){
                    temp = p[j];
                    p[j] = p[j+1];
                    p[j+1] = temp;
                }
            }else if(flag == 0){ //降序
                if(p[j] < p[j+1]){
                    temp = p[j];
                    p[j] = p[j+1];
                    p[j+1] = temp;
                }
            }
        }
    }
}

void my_print(int *p,int len){ //打印数组
    int i = 0;
    for(i = 0; i < len; i++){
        printf("%d ",p[i]);
    }
    printf("n"); 
}

int main(int argc, const char *argv[])
{
    int s[10] = {2,1,8,5,4,3,7,9,6,10};
    //排序前
	my_print(s, 10);
	//升序排序
	my_sort(s, 10, 1);
	//排序后
	my_print(s, 10);
	//降序排序
	my_sort(s, 10, 0);
	//排序后
	my_print(s, 10);           
    return 0;
}

练习42:将 strlen 封装成函数 

法一: 

#include <stdio.h>

//函数调用
void my_strlen(char *p){
    int len = 0;
    while(*p++){ //先进行 p++ 后 *(p++)
        len++;  //统计字符个数
    }
    printf("%dn",len);
} 

int main(int argc, const char *argv[])
{
    char s[32] = "book";
    my_strlen(s);                
    return 0;
}

法二:

#include <stdio.h>

int my_strlen(const char *str){
	int len = 0;
	while(*str != ''){
		len++;
		str++;
	}
	return len;
}

int main(int argc, const char *argv[])
{
	char s[32] = "hello world";
	printf("%dn", my_strlen(s));
	return 0;
}

练习43:将strcpy 封装成函数 

#include <stdio.h>

int my_strcpy(char *dest, const char *str){
	while(*str != ''){
        *dest = *str;
        str++;
        dest++;
	}
    *dest = *str;
	return 0;
}

int main(int argc, const char *argv[])
{
	char s1[32] = "hello world";
    char s2[32] = "book";
    my_strcpy(s1,s2);
	printf("%sn", s1);
    printf("%sn", s2);
	return 0;
}

练习44:将 strcat 封装成函数 

#include <stdio.h>

int my_strcat(char *dest, const char *str){
    //先让dest 的下标指向''
    while(*dest != ''){
        dest++;
    }
    //让str 的字符循环追加到 dest的后面
	while(*str != ''){
        *dest = *str; 
        str++;  
        dest++;
	}
    *dest = *str;  //将str 的 '' 赋给 dest
	return 0;
}

int main(int argc, const char *argv[])
{
	char s1[32] = "hello world";
    char s2[32] = "book";
    my_strcat(s1,s2);  
	printf("%sn", s1);
    printf("%sn", s2);
	return 0;
}

练习45:将 strcmp 封装成函数 

#include <stdio.h>

int my_strcmp(char *s1, const char *s2){    
    while(*s1 == *s2 && *s1 != ''&& *s2 != ''){
        s1++;
        s2++;
    }
    //如果循环结束时 *s1 == *s2  说明 *s1 和 *s2 都是 ''
	if(*s1 == *s2){
        return 0;
    }else{
        return *s1-*s2;
    }
}

int main(int argc, const char *argv[])
{
	char s1[32] = "hello";
	char s2[32] = "halloasdfqewr";
    int ret = my_strcmp(s1,s2);  

	if(ret == 0){
        printf("s1 == s2n");
    }else if(ret > 0){
        printf("s1 > s2n");
    }else if(ret < 0){
        printf("s1 < s2n");
    }
	return 0;
}