#define定义标识符常量和宏
标识符常量
#include <stdio.h>
#define M 100//只是个符号,没有地址,编译期间用到M的地方全部变成100
int main()
{
int arr[M] = {0};
int m = M;
printf("%d\n", sizeof(arr));//400
printf("%d\n", M);//100
printf("%d\n", m);//100
return 0;
}
test.c 源文件怎么使用的:
(预编译) - 编译 - (汇编) - 链接 - 运行 - test.exe
//预编译解析
#define MAX 1000
int main()
{
int m = 1000; //此时 define 定义的符号在预编译(预处理)阶段会被替换成它的内容
printf("%d", m);
return 0;
}
define 定义的数据类型依据具体情况而定,上文代码 MAX 本身是没有类型的,它的内容 1000 是有类型的,所以使用 MAX 可以把它当成整型来用
#define STR "hello bit"//STR 是 sting(字符串) 的缩写
int main()
{
printf("%s", STR);
return 0;
}
根据编译环境来看能否打印汉字
宏
#include <stdio.h>
#define ADD(x, y) ((x)+(y))//宏
int Add(int x, int y)//函数
{
return x + y;
}
int main()
{
int a = 10;
int b = 20;
int c = ADD(a, b);
//编译后变为int c = ((a)+(b))
int d = Add(a, b);
printf("%d\n", c);//输出30
printf("%d\n", d);//输出30
return 0;
}
宏:#define
+宏名ADD
+参数(x, y)
+实现体((x)+(y))
函数:返回类型int
+函数名Add
+参数(int x, int y)
+函数体{ ...code... }
函数与宏的区别:
- 函数参数有类型及名字 (int x, int y),宏参数没有类型;只有名字 (x, y)
- 函数有返回类型;宏没有
- 函数体需要用 { } 括起来;宏直接写实现方式
- 函数名字一般不会全大写;宏名一般全大写
宏的语句可以是多条语句
指针
内存
内存是电脑上特别重要的存储器,计算机中程序的运行都是在内存中进行的(寄存器集成在 CPU 上,没有地址;内存才有地址)
为了有效的使用内存,就把内存划分成一个个小的内存单元,每个内存单元的大小是1个字节
为了能够有效的访问到内存的每个单元,就给内存单元进行了编号,这些编号被称为该内存单元的地址
右侧为内存单元对应的地址,常用16进制表示
地址就是为了让我们很方便地找到内存里面的空间
32位/64位
32位:32根地址线/数据线
在计算机上,有地址线,有强弱两种电信号,电信号依照高低电频转换为数字信号1/0
00000000000000000000000000000000
00000000000000000000000000000001
…
11111111111111111111111111111111
共 2 32 2^{32} 232个可能的二进制序列,一个二进制序列可以对应一个内存单元(1Byte),内存单元有编号,编号就是内存单元的地址
2 32 2^{32} 232个二进制序列—— 2 32 2^{32} 232个内存单元—— 2 32 2^{32} 232(4,294,967,296)Byte——4GB
所以32位机器真正能管理的物理空间只有4GB,同理64位机器真正能管理的物理空间有16EB(17179869184GB)
程序运行起来,要加载到内存中,也要申请内存空间使用
内存窗口
输入 &a - 取a的地址
int a = 10;
printf("%p", &a);//%p - 打印地址,输出0x000000FCD3CFFB44,为 a 的起始地址,而不是所有地址
取地址
#include <stdio.h>
int main()
{
int a = 10;
int* pa = &a;//pa的数据类型为int*,pa叫做指针变量,是用来存放指针的变量
printf("%p\n", &a);//%p是专门用来打印地址的,表示形式为16进制
printf("0x%p\n", &a);
*pa = 20;
printf("%d\n", a);//20
return 0;
}
内存单元编号=地址=指针,口头说的指针,基本上都是指针变量
& 是取地址,* 是通过地址找回去,是相反的动作
指针变量的大小
printf("%d\n", siezeof(int*));//4
printf("%d\n", siezeof(char*));//4,而不是1
32位机器上:地址是32个二进制位,这个地址存储需要4个字节,所以32位机器上指针变量的大小是4Byte
64位机器上:地址是64个二进制位,这个地址存储需要8个字节,所以64位机器上指针变量的大小是8Byte
结构体
#include <stdio.h>
//创建结构体类型
struct Stu
{
//创建结构体成员
char name[20];//名字
int age;//年龄
char sex[5];//性别:男/女/保密
};
void print1(struct Stu s)//需要写在创建结构体类型下面
{
printf("%s %d %s\n", s.name, s.age, s.sex);
printf("%s %d %s\n", (&s)->name, (&s)->age, (&s)->sex);
}
void print2(struct Stu* ps)
{
printf("%s %d %s\n", (*ps).name, (*ps).age, (*ps).sex);//写法1,.结构成员访问操作符,格式:结构体变量.结构体成员
printf("%s %d %s\n", ps->name, ps->age, ps->sex);//写法2,->结构成员访问操作符,格式:结构体指针->结构体成员
}
int main()
{
//创建结构体变量
struct Stu s1 = {"张三", 18, "男"};//初始化学生1
struct Stu s2 = {"如花", 45, "女"};//初始化学生2
printf("%s %d %s\n", s1.name, s1.age, s1.sex);//直接打印s1
print1(s2);//函数打印s2
print2(&s2);//函数打印s2
scanf("%s %d %s", s1.name, &(s1.age), s1.sex)//输入(替换)s1结构体数据,name、sex是数组,数组名本来就是地址,故不需取地址
return 0;
}
//typedef 类型重命名
typedef struct Stu
{
char name[20];
int age;
char sex[5];
}Stu;//将struct Stu重命名为Stu
int main()
{
//结构体变量
Stu s1 = {"张三", 18, "男"};//重命名使之简写
struct Stu s2 = {"如花", 45, "女"};
return 0;
}
课后习题
4 BC101 班级成绩输入输出
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
int main()
{
float score[5] = { 0.0 };
int i = 0;
for (i = 0; i < 5; i++)
{
int j = 0;
float sum = 0.0;
for (j = 0; j < 5; j++)
{
scanf("%f", &score[j]);
sum += score[j];
}
for (j = 0; j < 5; j++)
{
printf("%.1f", &score[j]);
}
printf("%.1f\n", sum);
}
return 0;
}
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
int main()
{
int i = 0;//初始化i表示5个同学,用来循环5次
for (i = 1; i <= 5; i++)
{
double score = 0.0;//初始化,防止上一个同学影响到下一个同学
double sum = 0.0;//初始化,防止上一个同学影响到下一个同学
int j = 0;//初始化j表示5科成绩,用来循环5次
for (j = 1; j <= 5; j++)
{
scanf("%lf", &score);//输入单科成绩
printf("%.1lf ", score);//输出单科成绩,注意空格
sum += score;
}
printf("%.1lf\n", sum);//输出单行成绩之和
}
return 0;
}
注意:空格把数据进行分隔,scanf进行获取时只能以空格为间隔一个个进行获取
5 BC56 线段图案
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
int main()
{
int i = 0;//线段长度
int n = 0;//循环次数
while (scanf("%d", &i) != EOF)//!= EOF可以替换成== 1
{
for (n = 1; n <= i; n++)
{
printf("*");
}
printf("\n");
}
return 0;
}
6 时间转换
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
int main()
{
int sec = 0;//输入秒数
scanf("%d", &sec);
int h = sec / 60 / 60;//时
int m = sec / 60 % 60;//分
int s = sec % 60;//秒
printf("%d %d %d\n", h, m, s);
return 0;
}
注意:时分秒的简便计算