[C++系列] C语言基础 day12 指针数组,宏,条件编译
in C/C++ with 0 comment

[C++系列] C语言基础 day12 指针数组,宏,条件编译

in C/C++ with 0 comment

#练习

#模拟登陆,利用上节课的字符串知识

/*
 * 模拟登陆练习
 * */
#include <stdio.h>
#include <string.h>
int main() {
    char buf[10] = {0};
    int num = 0;
    for (num = 1;num <= 3;num++) {
        printf("请输入用户名:");
        fgets(buf, 10, stdin);
        if (strlen(buf) == 9 && buf[8] != '\n') {
            scanf("%*[^\n]");
            scanf("%*c");
        }
        if (strcmp(buf, "admin\n")) {
            continue;
        }
        printf("请输入密码:");
        fgets(buf, 10, stdin);
        if (strlen(buf) == 9 && buf[8] != '\n') {
            scanf("%*[^\n]");
            scanf("%*c");
        }
        if (strcmp(buf, "123456\n")) {
            continue;
        }
        break;
    }
    if (num <= 3) {
        printf("登陆成功\n");
    }
    else {
        printf("登陆失败\n");
    }
    return 0;
}

#指针数组

在C语言和C++语言中,数组元素全为指针的数组称为指针数组。
指针数组里的每个存储区是一个指针类型的存储区
字符指针数组里包含多个字符类指针,其中每个指针可以表示一个字符串
字符指针数组可以用来表示多个相关字符串

/*
 * 字符指针数组演示
 * */
#include <stdio.h>
int main() {
    char *strs[] = {"abc", "def", "iop",
           "vbn", "xyz"};
    int num = 0;
    for (num = 0;num <= 4;num++) {
        printf("%s\n", strs[num]);
    }
    return 0;
}

#主函数的参数

主函数的第二参数是一个字符指针数组。
其中每个指针代表一个字符串,所有这些字符串的内容都来自用户的命令
主函数的第一个参数是一个整数,它表示第二个参数里的指针个数

/*
 * 主函数的参数
 * */
#include <stdio.h>
int main(int argc, char *argv[]) {
    int num = 0;
    for (num = 0;num <= argc - 1;num++) {
        printf("%s\n", argv[num]);
    }
    return 0;
}

#练习

鸡兔同笼问题,利用主函数的参数。

/*
 * 鸡兔同笼练习
 * */
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[]) {
    int heads = 0, legs = 0, num = 0;
    if (argc < 3) {
        printf("命令错误\n");
        return 0;
    }
    heads = atoi(argv[1]);
    legs = atoi(argv[2]);
    for (num = 0;num <= heads;num++) {
        if (4 * num + 2 * (heads - num) == legs) {
            printf("兔子有%d只,鸡有%d只\n", num, heads - num);
            return 0;
        }
    }
    return 0;
}

#

define 预处理指令可以用来定义宏。

宏可以用来给数字起名字,
定义宏的时候要把宏名称写再#define预处理指令后,宏名称后写它所代表的数字
宏名称通常由大写英文字母构成,宏名称里不可以包含空格
用宏给数字起名字的时候不可以使用赋值操作符
可以在程序里使用宏名代替它所对应的数字
编译器会把程序里的所有宏名替换成它所代表的数字

可以在编译命令里使用-D选项临时指定宏所代表的数字。
宏还可以给一个计算公式起名字
计算公式里包含未知数字,宏的参数用来表示这些未知数字。

编译器采用二次替换的方式处理带参数的宏

/*
 * 宏演示
 * */
#include <stdio.h>
#define     PI            3.14f
#define     CIRCLE(r)     2 * PI * r
int main() {
    float pi = 3.14f;
    int radius = 0;
    printf("请输入半径:");
    scanf("%d", &radius);
    printf("周长是%g\n", CIRCLE(radius));
    printf("周长是%g\n", 2 * pi * radius);
    return 0;
}

宏的参数不一定代表数字,所以它没有类型
如果宏有多个参数就需要用逗号把它们分开

宏不可以使用自己的存储区和函数进行数据传递

宏没有形式参数也没有用来存放返回值的存储区

能当作数字使用的宏必须编写一个表达式(因为宏没有用来记录返回值的存储区)


宏的参数直接代表使用函数的存储区。对宏参数内容的修改就是修改函数存储区的内容。

#练习

编写一个宏,这个宏计算两个整数的差

/*
 * 宏演示
 * */
#include <stdio.h>
#define   SUB(x, y)         ((x) - (y))
int main() {
    printf("SUB(10, 5)是%d\n", SUB(10, 5));
    printf("20 - SUB(10, 5)是%d\n", 20 - SUB(10, 5));
    printf("SUB(20, 10 - 5)是%d\n", SUB(20, 10 - 5));
    return 0;
}

宏没有记录返回值的存储区所以不能保证优先计算宏里面的操作符。

宏没有形式参数所以不能保证优先计算参数里的操作符。所以所有能当数字使用的参数也必须写在小括号里。

#练习

#编写宏求一个数的绝对值和相反数。

/*
 * 宏演示
 * */
#include <stdio.h>
#define    ABS(n)        n >= 0 ? n : 0 - n
#define    NEG(n)        n = 0 - n
int abs(int num) {
    if (num >= 0) {
        return num;
    }
    else {
        return 0 - num;
    }
}
void neg(int *p_num) {
    *p_num = 0 - *p_num;
}
int main() {
    int num = 0;
    printf("请输入一个数字:");
    scanf("%d", &num);
    printf("绝对值是%d\n", abs(num));
    printf("绝对值是%d\n", ABS(num));
    neg(&num);
    printf("num是%d\n", num);
    NEG(num);
    printf("num是%d\n", num);
    return 0;
}

#练习

#编写一个宏,这个宏计算一个数的平方、

/*
 * 宏练习
 * */
#include <stdio.h>
#define   SQUARE(n)         ((n) * (n))
int main() {
    int num = 5;
    printf("SQUARE(5)是%d\n", SQUARE(5));
    printf("100 / SQUARE(5)是%d\n", 100 / SQUARE(5));
    printf("SQUARE(2 + 3)是%d\n", SQUARE(2 + 3));
    printf("SQUARE(++num)是%d\n", SQUARE(++num));
    return 0;
}

使用宏的时候不要使用自增自减作为宏的参数。

编写宏的时候可以使用一些特殊符号。叫做宏操作符。

"#"是一个宏操作符,它可以把宏的参数转换成字符串字面值。

"##" 也是一个宏操作符,它可以把一个代表标识符的参数和其他内容连接形成一个新的标识符。

#include<stdio.h>
#define STR(n)          #n     //将n以双引号包围称为字符串面值
#define PTR(n)          p_##n //根据普通变量名称计算指针变量名称 , ##后面的被识别为变量n
int main(){
int num =0;
int *p_num = &num;
printf("%s\n",STR(2+5));
PTR(num);
return 0;
}

#条件编译

在编译程序的时候从几组语句里选择一组编译而忽略其他组。

#ifdef/#ifndef ... #else ... #endif
以上结构可以根据一个宏名称是否被定义从两组语句中选择一组编译。
最开始的预处理指令应该从两个里选择一个,不论选择谁后面都要跟着一个宏名称。
如果选择#ifdef就表示宏名称被定义过就编译前一组语句,否则编译后一组语句。
如果选择#ifndef则效果和#ifdef完全相反。

/*
 * 条件编译演示
 * */
#include <stdio.h>
int main() {
//#ifdef   YI
#ifndef   ER
    printf("1\n");
#else
    printf("2\n");
#endif
    return 0;
}

#练习

为饭馆编写一个点菜程序
1表示龙虾
2表示小鸡炖蘑菇
要求为普通客人和赵各编译一个版本。

#include<stdio.h>
int main(){
int order = 0;
printf("请点菜:");
scanf("%d",&order);
#ifdef  ZHAO
        if(order == 1){
            printf("没有\n");
        }else if(order == 2){
            printf("真没有\n");
        }
#else
        if(order == 1){
            printf("有\n");
        }
        else if(order == 2){
            printf("没有\n");
        }
#endif
return 0;
}

#if ... #elif(任意多次) ... #else .. #endif

以上结构也可以实现条件编译,它可以根据任意逻辑表达式从多组语句中选择一组编译。

#include<stdio.h>

int main(){
#if     defined(GONGCHANG)
printf("80%%\n");
#elif   !defined(GONGCHANG) && !defined(JINGPING)
printf("100%%\n");
#else
printf("120%%\n");
#endif
return 0;
}

#if#elif后都需要写逻辑表达式,这些逻辑表达式里可以使用任意逻辑操作符,它们的作用
和if分支里的逻辑表达式的作用一样

#练习

编写一个模拟登陆练习
一共给用户三次机会,如果有一次用户名和密码都正确就算登陆成功,否则登陆失败。
无论成功还是失败,都需要在屏幕上给出提示。
正确的用户名是admin,正确的密码是123456

#include<stdio.h>
#include<string.h>
int check_login(char *username,char *password){
     if(!strcmp(username,"admin\n") && !strcmp(password, "123456\n")){
     return 1;
}else{
     return 0;
}
}
int main(){
     int num = 1;
     char username[20]={0};
     char password[20]={0};
     while(num <=3 ){
          printf("输入用户名:");
          fgets(username,10,stdin);
          printf("输入密码:");
          fgets(password,10,stdin);
     if(check_login(username,password)){
          printf("成功登录!\n");
          break;
     }
    printf("登录失败,还有%d次机会\n",3-num,check_login(username,password));
    num++;
    }
return 0;
}

#预习

* 多文件编程
* 结构体
Responses