起步
// C++向下兼容C,在练习过程中,请将代码保存为.cpp文件
/*
* 头文件
* 1. ".h"为头文件的文件格式
* 2. C++等价写法:#include
*/
#include
/*
* 主函数
* 1. 程序入口
* 2. 程序从主函数开始执行
* 3. 一个程序最多只能有一个主函数
*/
int main(){
int a,b;
scanf("%d%d",&a,&b);
printf("%d",a+b);
return 0;
}
一、基本数据类型
变量类型
整型
常用整型(int)和长整型(long long)。
说明:
- 绝对值在109范围以内的整数都能定义成int型。
- 如果给long long型赋一个大于231-1的初值,请在数字后加LL。如:long long bigNum = 1234567890123345LL。
- 题目要求109以内或32位整数时,用int存放;若是1018以内(如1010)或者说64位整数,使用long long存放。
浮点型
浮点型就是小数,氛围单精度(float)和双精度(double)。
说明:
- float有效精度6~7位,少用。
- 碰到浮点型的数据使用double来存储。
字符型
说明:
- C语言中,字符常量统一使用ASCII码统一编码(范围0~127)。
- 小写字母比大写字母的ASCII码值大32(a->97,A->65,空格->32)。
- 字符常量(必须是单个字符)必须使用单引号标注('z','h','r')。
- 可以将整数的ASCII码值赋给字符变量,因为在计算机内部,字符就是按ASCII码存储的。
- 转义字符"\0"代表空字符NULL(注意不是空格),其ASCII码为0。
字符串常量
#include
int main(){
/*
* 字符数组
* 1. 字符串常量为""标记的字符集。
* 2. 不能把字符串常量赋值给字符变量(不允许char c = "zhanghaoran";)
* 3. 字符串常量可以作为初值赋值给字符数组,使用%s的格式输出。
*/
char str[50] = "2022,kaoyanbisheng!";
printf("%s",str);
return 0;
布尔型
#include
int main(){
bool flag1 = 10;
bool flag2 = -10;
bool flag3 = 0;
printf("%d\n%d\n%d",flag1,flag2,flag3);
/**
/Users/zhr/CLionProjects/untitled/cmake-build-debug/untitled
1
1
0
Process finished with exit code 0
*/
return 0;
}
说明:
- 布尔型(bool)在cpp文件中直接使用,在C语言中要添加stdbool.h头文件才能使用。
- 给布尔型变量赋值的时候可以使用true、false或者整型常量。整型常量在赋值给bool变量时,会自动转换成true(非0)和false(0)。
- bool中,true使用1存储,false使用0存储,%d打印时会输出数字。
常量定义
常用的定义常量的方式有两种:
#define PI 3.1415 // 宏定义
const double PI = 3.1415; // const关键字
二、顺序结构
scanf与printf
#include
int main(){
/*
n = n + 2 <=> n += 2 后者称为符合赋值运算符,可以加快编译速度和提高可读性,应常用这种方式。
*/
int n = 0;
n += 2;
printf("%d",n);
int age;
/* 关于scanf()
* 1. scanf("格式控制",变量地址)
* 2. "&"——取地址运算符
* 3. 特别的数据类型变量的scanf格式符:
* - long long: %lld
* - double: %lf
* 4. scanf中,char数组整个输入的情况下不加&,因为数组名称本身就代表了数组第一个元素的地址
* 5. 字符数组读入时以空格和换行符为读入结束的标志,因此当输入"zhang haoran"想赋值给name时,name只会保存"zhang"
* 6. scanf的%c格式可以读入空格和换行。
*/
scanf("%d",&age);
char name[20];
scanf("%s",name);
/*
* 关于printf():
* 1. 对于double类型的变量,在printf中的输出格式为%f,而在scanf中是%lf
* 2. 输出%和\时,需要转义,即"%%"和"\\"
*/
printf("姓名:%s\n年龄:%d",name,age);
/*
* /Users/zhr/CLionProjects/untitled/cmake-build-debug/untitled
20
zhanghaoran
姓名:zhanghaoran
年龄:20
Process finished with exit code 0
*/
// 补充三种常用的输出格式
{
int num = 720;
// 1. %md 使不足m位的int型变量以m位进行右对齐输出,高位空格补齐
printf("%5d",num);
// 2. 区别于%md,%0md高位0补齐
printf("%05d",num);
double d = 1.1234567;
// 3. 让浮点数保留m位小数输出
printf("%.2f",d);
}
return 0;
}
getchar与putchar
#include
int main(){
char c1,c2,c3;
// 1. getchar()能识别空格和换行符
// 2. getchar()用来输入单个字符,putchar用来输出单个字符
c1 = getchar();
c2 = getchar();
c3 = getchar();
putchar(c1);
putchar(c2);
putchar(c3);
return 0;
/*
* /Users/zhr/CLionProjects/untitled/cmake-build-debug/untitled
z hr
z h
Process finished with exit code 0
*/
}
typedef
typedef关键字用于给复杂的一个数据类型取别名。
// 给long long数据类型取一个别名Long
typedef long long Long;
Long l = 123456789LL;
常用的math函数
在使用数学函数前,要使用#include
引入头文件。
- fabs(double x)
对double型变量取绝对值。- floor(double x) 和 ceil(double x)
对double型的变量进行向下取整和向上取整。- pow(double r,double p)
返回rp- sqrt(double x)
返回double型变量的算数平方根。- log(double x)
返回double型变量以自然对数为底的对数- sin(double x)、cos(double x)、tan(double x)
返回对应的三角函数值,参数要求是弧度制。- round(double x)
将double型变量x四舍五入后取整然后返回double类型。
三、选择结构
下面这种写法在许多数据结构算法的书上经常出现。
#include "cstdio"
int main(){
int a = 100;
int b = 0;
if(a){
printf("a is not zero!");
} else {
printf("a is zero!");
}
if(!b){
printf("a is zero!");
} else {
printf("a is not zero!");
}
}
技巧
- 在if条件中,如果表达式是"!=0",可以省略。
- 在if条件中,如果表达式是"==0",可以省略,然后在表达式前加取反运算符"!"。
四、循环结构
对于以下这种写法:
for(int i = 0; i < 10 ; i ++){
// ···
}
说明:
在C语言中是不允许在for语句的表达式A中定义变量的,但是在C++中可以,因此以上这种写法需要把文件保存为.cpp后缀才能通过编译。
五、数组
一维数组初始化
基本方法
#include
int main(){
/*
* 一维数组初始化
* 1. 数组对部分元素进行赋值操作,未被赋值的元素默认为0。
* 2. 当数组没有被赋初值,每个元素可能是0,也有可能是一个随机数。
* 3. 如果想给数组的每一个元素赋初值0,只需要把第一个元素赋为0,或者只用一个{}表示:
* a. int nums[10] = {0};
* b. int nums[10] = {};
*/
int nums[10] = {11,22,33,44,55};
for(int i = 0; i < 10 ; i ++){
printf("nums[%d]=%d\n",i,nums[i]);
}
return 0;
/*
/Users/zhr/CLionProjects/untitled/cmake-build-debug/untitled
nums[0]=11
nums[1]=22
nums[2]=33
nums[3]=44
nums[4]=55
nums[5]=0
nums[6]=0
nums[7]=0
nums[8]=0
nums[9]=0
Process finished with exit code 0
*/
}
使用memset对数组中每一个元素赋相同的值
#include "cstdio"
#include "cstring"
#define n 5
int main(){
/*
* 使用memset给数组赋初值
* 1. 添加string.h头文件
* 2. memset按字节赋值
* 3. 一般使用memset赋初值0或-1
*/
int arr[n];
memset(arr,-1,sizeof(arr));
for(int i = 0; i< n; i ++){
printf("%2d ",arr[i]);
}
memset(arr,0,sizeof(arr));
printf("\n");
for(int i = 0; i< n; i ++){
printf("%2d ",arr[i]);
}
return 0;
/*
* /Users/zhr/CLionProjects/untitled/cmake-build-debug/untitled
-1 -1 -1 -1 -1
0 0 0 0 0
Process finished with exit code 0
*/
}
数组顺推
#include
// 数组递推包括:
// 1. 顺推
// 2. 逆推
int main(){
int nums[10];
scanf("%d",nums);
for(int i = 1; i < 10 ;i ++){
nums[i] = nums[i - 1] * 2;
}
for(int i = 0; i < 10 ;i ++){
printf("nums[%d]=%d\n",i,nums[i]);
}
return 0;
/*
/Users/zhr/CLionProjects/untitled/cmake-build-debug/untitled
1
nums[0]=1
nums[1]=2
nums[2]=4
nums[3]=8
nums[4]=16
nums[5]=32
nums[6]=64
nums[7]=128
nums[8]=256
nums[9]=512
Process finished with exit code 0
*/
}
冒泡排序
#include
/*
* 冒泡排序:
* 1. 进行若干趟排序,每趟排序将数组元素的最大值移动到最右边
* 2. 当剩余元素为0时,排序结束
*/
const int n = 10;
int main(){
int nums[n] = {1,4,3,2,7,6,5,9,8};
for(int i = 0 ;i < n - 1; i ++){
for(int j = 0; j < n - i - 1; j ++){
if(nums[j] > nums[j + 1]){
int tmp = nums[j];
nums[j] = nums[j + 1];
nums[j + 1] = tmp;
}
}
}
for(int i = 0; i< n ; i ++){
printf("%d ",nums[i]);
}
return 0;
/*
* /Users/zhr/CLionProjects/untitled/cmake-build-debug/untitled
0 1 2 3 4 5 6 7 8 9
Process finished with exit code 0
*/
}
二维数组
#include
#define n 3
int main(){
/*
* 二维数组初始化
*/
int arr[n][n] = {{1,2},{2}};
for(int i = 0; i< n ;i ++){
for(int j = 0; j< n ;j ++){
printf("%02d ",arr[i][j]);
}
printf("\n");
}
/*
* 两个三阶矩阵对应位置元素相加,并将结果存放到另外一个三阶矩阵
*/
int a[n][n];
int b[n][n];
int c[n][n];
for(int i = 0; i < n ; i ++){
for(int j = 0; j< n ; j ++){
scanf("%d",&a[i][j]);
scanf("%d",&b[i][j]);
c[i][j] = a[i][j] + b[i][j];
}
}
// for(int i = 0; i < n ; i ++){
// for(int j = 0; j< n ; j ++){
// scanf("%d",&b[i][j]);
// }
// }
// for(int i = 0; i < n ; i ++){
// for(int j = 0; j< n ; j ++){
// c[i][j] = a[i][j] + b[i][j];
// }
// }
for(int i = 0 ;i < n ; i++){
for(int j = 0; j < n ; j ++){
printf("%d ",c[i][j]);
}
printf("\n");
}
/*
* /Users/zhr/CLionProjects/untitled/cmake-build-debug/untitled
01 02 00
02 00 00
00 00 00
1 9 2 8 3 7 4 6 5 5 6 4 7 3 8 2 9 1
10 10 10
10 10 10
10 10 10
Process finished with exit code 0
*/
}
字符数组
字符数组的初始化
#include
int main(){
// 字符数组初始化方式1——普通数组初始化方式
char str1[] = {'z','h','r'};
for(int i = 0 ; i < 3 ; i ++){
printf("%c",str1[i]);
}
printf("\n");
// 字符数组初始化方式2——赋值字符串(仅限初始化)
char str2[] = "zhanghaoran";
for(int i = 0 ; i< 11; i ++ ){
printf("%c",str2[i]);
}
printf("\n");
return 0;
/*
* /Users/zhr/CLionProjects/untitled/cmake-build-debug/untitled
zhr
zhanghaoran
Process finished with exit code 0
*/
}
字符数组的输入输出
#include "cstdio"
int main(){
/*
* 字符数组输入输出方式1——printf()和scanf()
1. scanf()的%c格式能够识别空格和换行符并将其输入
2. %s通过空格和换行符来识别一个字符串的结束
3. scanf()在使用%s时,对应数组名前不用加取地址运算符"&"
*/
// char name[20] = {};
// scanf("%s",name);
// printf("%s",name);
/*
/Users/zhr/CLionProjects/untitled/cmake-build-debug/untitled
zhanghaoran
zhanghaoran
Process finished with exit code 0
*/
/*
* /Users/zhr/CLionProjects/untitled/cmake-build-debug/untitled
zhang haoran
zhang
Process finished with exit code 0
*/
/*
* 字符数组输入输出方式2——getchar()和putchar()
* 注意:getchar()能识别空格和换行符
*/
// const int n = 4;
// char twoDimensionArr[n][n];
// for(int i = 0 ; i < n - 1 ;i ++){
// for(int j = 0 ;j < n - 1 ; j ++){
// twoDimensionArr[i][j] = getchar();
// }
// getchar(); // 把输入中每行末尾的换行符吸收掉
// }
// for(int i = 0 ; i < n - 1; i ++){
// for(int j = 0 ; j < n - 1; j ++){
// putchar(twoDimensionArr[i][j]);
// }
// putchar('\n');
// }
/*
* /Users/zhr/CLionProjects/untitled/cmake-build-debug/untitled
^_^
_^_ ^_^
^_^
_^_
^_^
Process finished with exit code 0
*/
/*
* 字符数组输入输出方式3——gets()和puts()
* 说明:
* 1. gets()识别换行符\n作为输入结束,scanf()后如要用gets(),需要先用getchar()把换行符吸收掉。
* 2. gets()输入的字符串可以包含空格
* 3. puts()输出会自动换行。
*/
// int a = 0;
// char str[20];
// scanf("%d",&a);
// getchar();
// gets(str);
// puts(str);
/*
* /Users/zhr/CLionProjects/untitled/cmake-build-debug/untitled
1
warning: this program uses gets(), which is unsafe.
zhanghaoran
zhanghaoran
Process finished with exit code 0
*/
// 使用gets()和puts()操作二维数组
const int row = 3;
char strs[row][20];
for(int i = 0 ; i < row ; i ++ ){
gets(strs[i]);
}
for(int i = 0 ; i < row ; i ++){
puts(strs[i]);
}
/*
* /Users/zhr/CLionProjects/untitled/cmake-build-debug/untitled
warning: this program uses gets(), which is unsafe.
zhang
hao
ran
zhang
hao
ran
Process finished with exit code 0
*/
return 0;
}
字符数组的存放方式
说明:
- 在一维数组(或二维数组的第二维)末尾都有一个空字符'\0',表示存放字符串的结尾。
- '\0'在使用gets()或者scanf()输入字符串时会自动添加在输入的字符串后面,并占用一个字符位。
- puts()和printf()通过识别'\0'作为字符串的结尾来输出的。
- 结束符'\0'的ASCII值为0,即空字符NULL,占用一个字符位,因此,在创建一个字符数组时,字符数组的长度至少要比实际存储的字符串的长度多1。
- 只有char数组末尾会加'\0',int等类型的数组末尾不加。
- '\0'和空格不是一个东西,它表示空字符NULL,空格的ASCII值为32。
string.h头文件
string.h头文件包含了许多用于字符数组的函数。
#include "cstdio"
// 引入string.h头文件
#include "cstring"
/*
* strlen()——用于获取字符数组中第一个'\0'前的字符的个数。
* 格式:strlen(字符数组)
*/
void strlen_test(){
char str[20];
// gets()可以输入包含空格的字符串
gets(str);
int len = strlen(str);
printf("%d",len);
printf("\n");
/*
* /Users/zhr/CLionProjects/untitled/cmake-build-debug/untitled
warning: this program uses gets(), which is unsafe.
zhang hao ran
13
Process finished with exit code 0
*/
}
/*
* strcmp()——以字典序为比较原则,返回两个字符串大小的比较结果。
* 格式:strcmp(字符数组1,字符数组2)
* 说明:
* 1. 若字符数组1<字符数组2,则返回一个负整数(不一定是-1)。
* 2. 若字符数组1=字符数组2,则返回0。
* 3. 若字符数组1>字符数组2,则返回一个正整数(不一定是1)。
*/
void strcmp_test(){
char str1[30];
char str2[30];
gets(str1);
gets(str2);
int res = strcmp(str1,str2);
if(res < 0){
printf("str1 < str2\n");
}else if(res == 0){
printf("str1 = str2\n");
}else{
printf("str1 > str2\n");
}
/*
* /Users/zhr/CLionProjects/untitled/cmake-build-debug/untitled
warning: this program uses gets(), which is unsafe.
nanchang
beijing
str1 > str2
Process finished with exit code 0
*/
}
/*
* strcpy()——把第二个字符串复制给第一个字符串,包括结束符"\0"
* 格式:strcpy(字符数组1,字符数组2)
*/
void strcpy_test(){
char str1[30];
char str2[30];
gets(str2);
strcpy(str1,str2);
puts(str1);
/*
/Users/zhr/CLionProjects/untitled/cmake-build-debug/untitled
warning: this program uses gets(), which is unsafe.
zhanghaoran
zhanghaoran
Process finished with exit code 0
*/
}
/*
* strcat()——把字符串2拼接到字符串1的后面
* 格式:strcat(字符数组1,字符数组2)
*/
void strcat_test(){
char str1[30];
char str2[30];
gets(str1);
gets(str2);
strcat(str1,str2);
puts(str1);
/*
* /Users/zhr/CLionProjects/untitled/cmake-build-debug/untitled
warning: this program uses gets(), which is unsafe.
zhanghaoran
like coding!
zhanghaoran like coding!
Process finished with exit code 0
*/
}
int main(){
// strlen_test();
// strcmp_test();
// strcpy_test();
strcat_test();
return 0;
}
sscanf()和sprintf()
sscanf()和sprintf()属于stdio.h头文件下的函数,用于处理字符串,可以理解为"string+scanf"和"string+printf"。
#include "cstdio"
#include "cstring"
int main(){
char str[10] = "1234";
int num;
sscanf(str,"%d",&num);
printf("%d\n",num);
/*
* /Users/zhr/CLionProjects/untitled/cmake-build-debug/untitled
1234
Process finished with exit code 0
*/
num = 12345;
sprintf(str,"%d",num);
for(int i = 0 ; i < strlen(str); i ++){
printf("%c ", str[i]);
}
printf("\n");
// printf("%s\n",str);
/*
/Users/zhr/CLionProjects/untitled/cmake-build-debug/untitled
1234
1 2 3 4 5
Process finished with exit code 0
*/
return 0 ;
}
理解:
- 我们常写的scanf()和printf()可以写成:
scanf(screen,"%d",&n); printf(screen,"%d",n);
这里的screen就看成是电脑屏幕。scanf的输入其实就是把screen中的内容以%d的格式传到变量n中(从左到右);而printf的输出就是把变量n中的内容以"%d"的格式传到screen。
- 类比到sscanf和sprintf,唯一的改变就是把screen换成了字符数组,使用格式如下:
char str[20]; sscanf(str,"%d",&n); sprintf(str,"%d",n);
- sprintf()也可以做字符串的复制
#include "cstdio" int main(){ char str1[20]; char str2[20] = "zhanghaoran"; sprintf(str1,"%s",str2); puts(str1); return 0; /* /Users/zhr/CLionProjects/untitled/cmake-build-debug/untitled zhanghaoran Process finished with exit code 0 */ }
- sscanf支持正则表达式
六、函数
再谈main函数:
int main(){
//···
return 0;
}
说明:
- 主函数对于一个程序来说只能有一个,无论主函数写在哪个位置,整个程序一定是从主函数的第一个语句开始执行,然后在需要调用其他函数的时候才回去调用。
- main函数返回0的意义在于告知系统程序正常终止。
七、指针
指针的相关概念
变量的存放:
- 变量存放在内存中。
- 每个字节都会有一个地址。
- 计算机通过地址找到某个变量。
- 变量的地址指的是它占用的字节中的第一个字节的地址。
指针:
- 在计算机中,一个地址"指向"一个变量,可以通过地址来找到变量。
- 在C语言中,使用"指针"表示内存地址(或称指针指向了内存地址)。
- 如果一个指针指向的内存地址恰好是某个变量的地址,就称"这个指针指向了该变量"。
- "&"为取地址运算符,在变量前加上"&",就表示变量的地址。
- 指针是一个unsigned类型的整数。
指针变量
指针变量用于存放指针(或者说地址)。
指针变量的定义与初始化
// 1. 数据类型后加"*"
int* p;
double* p;
char* p;
// 说明:"*"的位置在数据类型后或者变量名称之前都OK的,编译器不会对此进行区分。
//2. 同时定义多个指针变量
int *a,*b,*c;
//3. 以下方式只有p1会被定义为指针类型,p2不会
int* p1,p2;
//4. 给指针变量赋值的方式一般是把变量的地址使用取地址运算符"&"取出后赋值给对应类型的指针变量。
int a = 10;
int* pa = &a;
说明:
- int* 才是指针变量的类型,而后面的p才是变量名,用来存储变量的地址值。
- 地址值&a是赋值给p而不是*p的。
- 请记住,对指针变量来说,星号"*"是类型的一部分。
获取地址所指的元素:
- 在指针变量前加"*"。
- 指针变量p表示的是地址,*p是这个地址中存放的内容。
- 对指针变量来说,把其存储的地址的类型称为基类型。
指针与数组
#include "cstdio"
int main(){
// 1. C语言中,数组名称也作为数组的首地址使用。
// int a[5] = {1};
// int* pa = a;
// printf("%d",*pa);
/*
* /Users/zhr/CLionProjects/untitled/cmake-build-debug/untitled
1
Process finished with exit code 0
*/
// 2. 使用指针对数组进行赋值和遍历输出
const int n = 10;
int a[n];
for( int i = 0; i< n;i ++ ){
scanf("%d",a+i);
}
// 遍历方式1
// for(int i = 0 ; i < n ; i ++){
// printf("%d ",*(a+i));
// }
// printf("\n");
/*
* /Users/zhr/CLionProjects/untitled/cmake-build-debug/untitled
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9
Process finished with exit code 0
*/
// 遍历方式2
for(int* pa = a ; pa < a+n ; pa ++){
printf("%d ",*pa);
}
/*
* /Users/zhr/CLionProjects/untitled/cmake-build-debug/untitled
9 8 7 6 5 4 3 2 1 0
9 8 7 6 5 4 3 2 1 0
Process finished with exit code 0
*/
return 0;
}
在函数参数中使用指针
#include "cstdio"
void swap(int* a, int * b){
int tmp = *a;
*a = *b;
*b = tmp;
}
int main(){
int a = 10;
int b = 20;
swap(&a,&b);
printf("%d %d",a,b);
return 0;
}
引用
#include "stdio.h"
void change1(int x){
x = 10;
}
// 形参为引用
void change2(int &x){
x = 10;
}
int main(){
int x = 0 ;
change1(x);
printf("%d\n",x);
change2(x);
printf("%d\n",x);
return 0 ;
/*
* /Users/zhr/CLionProjects/untitled/cmake-build-debug/untitled
0
10
Process finished with exit code 0
*/
}
关于引用:
- 引用是C++中的语法,文件必须保存为.cpp类型。
- 引用不产生副本,只是给原变量取了一个别名,对引用变量的操作就是对原变量的操作。
- 使用方法:在函数的参数名前加"&"(或者参数类型之后,因为引用是别名的意思,所以一般加在变量名前面)
- 不管是否使用引用,函数的参数名(形参名)和实际传入的参数名(实参名)可以不同。
- 注意:把引用的"&"和取地址符"&"区分开,引用不是取地址的意思,它是C++中的一种语法。
- 强调:由于引用是产生变量的别名,因此常量不可使用引用。
下面是swap方法的另一种实现方式,这里使用到了指针的引用:
#include "cstdio"
void swap(int* &pa,int* &pb){
int* tmp = pa;
pa = pb;
pb = tmp;
}
int main(){
int a = 10, b = 20;
int *pa = &a;
int *pb = &b;
printf("%d %d\n",*pa,*pb);
swap(pa,pb);
printf("%d %d\n",*pa,*pb);
return 0;
/*
* /Users/zhr/CLionProjects/untitled/cmake-build-debug/untitled
10 20
20 10
Process finished with exit code 0
*/
}
八、结构体
定义结构体的基本格式:
struct struct_name{
// 一些基本的数据结构或者自定义的数据类型
};
结构体变量和结构体数组的2种定义方式:
// 方式1
struct studentInfo{
int id;
char gender;
char name[20];
char major[20];
}ZHANGHAORAN,stu[38];
// 方式2
struct studentInfo{
int id;
char gender;
char name[20];
char major[20];
};
studentInfo ZHANGHAORAN;
studentInfo stu[38];
结构体元素的访问:
说明:
结构体内部可以定义除了自己本身的任意数据类型(定义自己本身会引起循环定义问题),但是可以定义自身类型的指针变量。
struct studentInfo{
int id;
char gender;
char name[20];
studentInfo* next;
}stu,*p;
// 结构体普通变量访问结构体内部元素
stu.id
stu.name
stu.next
// 结构体指针变量访问结构体内部元素
// 说明:方式1和方式2等价
// 方式1
(*p).id
(*p).name
(*p).next
// 方式2
p->id
p->name
p->next
结构体的初始化:
这里介绍结构体的构造函数:
struct studentInfo{
int id;
char gender;
char name[20];
// 默认构造函数,在定义了新的构造函数后被覆盖,如需使用要单独定义。
studentInfo(){}
// 自定义构造函授
// 方式1
studentInfo(int _id,char* _name){
id = _id;
name = _name;
}
// 方式2 简化版
studentInfo(int _id,char _gender, char* _name):id(_id),gender(_gender),name(_name){
}
};
实例:
#include "cstdio"
struct Point{
int x;
int y;
Point(){}
Point(int _x,int _y):x(_x),y(_y){}
};
Point pt[10];
int main(){
for(int i = 0 ;i < 10; i ++ ){
pt[i] = Point(i+1,i+1);
}
for(int i = 0 ; i < 10 ; i ++){
printf("(%d,%d) ",(*(pt+i)).x,(*(pt+i)).y);
}
return 0;
/*
* /Users/zhr/CLionProjects/untitled/cmake-build-debug/untitled
(1,1) (2,2) (3,3) (4,4) (5,5) (6,6) (7,7) (8,8) (9,9) (10,10)
Process finished with exit code 0
*/
}
九、补充
cin与cout(不建议使用)
cin和cout是C++中的输入与输出函数,需要添加头文件#include
和using namespace std;
后才能使用。
#include "iostream"
using namespace std;
int main(){
char name[20];
int age;
char gender;
char desc[200]={};
/* cin函数:
* 1. cin采用输入运算符">>"进行输入,输入不用指定格式,也不需要加取地址运算符"&"。
* 2. cin可同时读入多个变量,只需往后面使用>>进行扩展即可。
* 3. 当需要读入一整行时,可以使用cin.getline()函数
*/
cin >> name >> age >> gender;
getchar(); // 吸收换行符
cin.getline(desc, 200);
/*
* cout函数:
* 1. 使用方法和cin几乎一致,只不过使用的是输出运算符"<<"。
* 2. 两种换行方式:
* a. "\n"
* b. endl(means 'end of line')
*/
cout<<"name:"<
说明:
在考试中,不推荐使用cin和cout进行输入输出,因为在数据量较大的情况下,有可能数据还没有输入完就超时了,因此只有在十分必要的情况下再去用cin和cout函数,推荐优先使用C语言的scanf()和printf()函数。
浮点数的比较
由于计算机中采用有限位的二进制编码,因此浮点数在计算机中的存储并不总是精确的,并且再经过大量计算后,误差会更加明显,这样就会对比较操作造成极大的干扰。
于是,为了提高浮点数比较结果的准确性,我们需要引进一个极小数eps来对误差进行修正。
这样,当一个数a落在[b-eps,b+eps]时,我们就应判断a==b是成立的。
实际上,eps可以任取,但经验表明,eps取108最合适。
const double eps = 1e-8;
我们把比较操作写成宏定义的形式:
#define equ(a,b) ((fabs((a)-(b)))<(eps))
于是,我们可以这样对两个浮点数进行比较(注意观察两种方式的结果):
#include
#include
const double eps = 1e-8;
#define Equ(a,b) ((fabs((a)-(b)))<(eps))
int main(){
double d1 = 4 * asin(sqrt(2.0) / 2);
double d2 = 3 * asin(sqrt(3.0) / 2);
// 方式1
printf("%d\n",(d1==d2));
// 方式2
printf("%d\n",Equ(d1,d2));
return 0;
/*
* /Users/zhr/CLionProjects/untitled/cmake-build-debug/untitled
0
1
Process finished with exit code 0
*/
}
我们可以写出其他运算符的宏定义形式:
// 大于(<)
#define More(a,b) ((a)-(b)) > (eps)
// 小于(<)
#define Less(a,b) ((a)-(b)) < (-eps)
// 不大于(<=)
#define LessEqu(a,b) ((a)-(b)) < (eps)
// 不小于(>=)
#define MoreEqu(a,b) ((a)-(b)) > (-eps)
关于圆周率π
圆周率π不需要死记,由 "cos(π) = -1" 得 "arccos(-1) = π",即const double Pi = acos(-1.0);
END