入门阶段ing,没想到指针花了这么久时间,主要原因还是以前就没学明白,现在大体疏通好了,还需要用的时候灵活适应。
感谢大佬几款优秀的支持C、C++在线编译器
stage1——5天入门阶段
教程网站:C++ 教程
在线编译器:compile c++ gcc online
刷题网站:阶段1第一关:基本数据类型
day4 planA
教程(20-23),刷题2,复习2(1)
教程完成度100%,刷题完成度100%,复习完成度100%
主要原因:优秀吧(bushi)。目标稍微合理一点就比较好达成。缺点:饿de快。下面执行planB。
day4 planB
教程7(2),刷题3(5)
教程完成度10%,刷题完成度80%
主要原因:开会,是所有正在进行任务的最大阻碍 << 以及找规律题,有点意思。
Q&A
1.引用
引用变量是一个别名,也就是说,它是某个已存在变量的另一个名字。一旦把引用初始化为某个变量,就可以使用该引用名称或变量名称来指向变量。
引用和指针对比:
- 不存在空引用。引用必须连接到一块合法的内存。
- 一旦引用被初始化为一个对象,就不能被指向到另一个对象。指针可以在任何时候指向到另一个对象。
- 引用必须在创建时被初始化。指针可以在任何时间被初始化。
试想变量名称是变量附属在内存位置中的标签,您可以把引用当成是变量附属在内存位置中的第二个标签。因此,您可以通过原始变量名称或引用来访问变量的内容。
int a;
a=1;
int& b=a;//定义引用并初始化
读作 "b是一个初始化为a的整型引用"
引用其实相当于给变量重新找个名称,除了初始化的时候需要加上&
,在使用或者输出的时候和变量是一样的。
#include <iostream>
using namespace std;
int main()
{
int a;
a=1;
int& b=a;
cout << a << endl;
cout << b << endl;
return 0;
}
输出--------------------------------------------
1
1
1.1 引用调用
引用的使用之前也提及过,比如在函数定义的时候,作为形参,在函数中对形参进行改变也会改变变量的值;
#include <iostream>
using namespace std;
void swap(int &a, int &b)
{
int t;
t=a;
a=b;
b=t;
}
int main()
{
int a=1,b=2;
cout << "origin: " << a << " " << b <<endl;
swap(a,b);
cout << "new: " << a << " " << b << endl;
return 0;
}
1.2 引用返回
C++ 函数可以返回一个引用,方式与返回一个指针类似。
当函数返回一个引用时,则返回一个指向返回值的隐式指针。这样,函数就可以放在赋值语句的左边。
#include <iostream>
using namespace std;
double vals[] = {10.1, 12.6, 33.1, 24.1, 50.0};
double& setValues(int i) {
double& ref = vals[i];
return ref; // 返回第 i+1 个元素的引用,ref 是一个引用变量,ref 引用 vals[i]
}
// 要调用上面定义函数的主函数
int main ()
{
cout << "改变前的值" << endl;
for ( int i = 0; i < 5; i++ )
{
cout << "vals[" << i << "] = ";
cout << vals[i] << endl;
}
setValues(1) = 20.23; // 改变第 2 个元素
setValues(3) = 70.8; // 改变第 4 个元素
cout << "改变后的值" << endl;
for ( int i = 0; i < 5; i++ )
{
cout << "vals[" << i << "] = ";
cout << vals[i] << endl;
}
return 0;
}
上面的使用可以这样理解,引用函数的返回值是一个引用,而引用在使用的时候通常是在赋值语句左侧
的,所以调用引用函数的时候,引用函数在赋值语句左侧,右侧为自定义值;
而在引用函数内部,需要定义并初始化一个引用,并对该引用赋予所对应的变量名。或者定义一个变量。返回值为引用对应的变量,或者直接定义的变量。
令,为了在所有函数中可以通用引用所对应的变量,该引用要在最前定义。
//复习
#include <iostream>
using namespace std;
int a=1;
int& usee()
{
int &t=a;
return t;
}
int main()
{
cout << "origin: " << a << endl;
usee()=5;
cout << "new: " << a << endl;
return 0;
}
输出-------------------------------------
origin: 1
new: 5
当返回一个引用时,要注意被引用的对象不能超出作用域。所以返回一个对局部变量的引用是不合法的,但是,可以返回一个对静态变量的引用。
int& func() {
int q;
//! return q; // 在编译时发生错误
static int x;
return x; // 安全,x 在函数作用域外依然是有效的
}
2.日期和时间
为了使用日期和时间相关的函数和结构,需要在 C++ 程序中引用 <ctime>
头文件。
四个与时间相关的类型:clock_t
、time_t
、size_t
和tm
。
类型clock_t
、time_t
、size_t
能够把系统时间和日期表示为某种整数。
结构类型tm
把日期和时间以 C 结构的形式保存,tm 结构的定义如下:
struct tm {
int tm_sec; // 秒,正常范围从 0 到 59,但允许至 61
int tm_min; // 分,范围从 0 到 59
int tm_hour; // 小时,范围从 0 到 23
int tm_mday; // 一月中的第几天,范围从 1 到 31
int tm_mon; // 月,范围从 0 到 11
int tm_year; // 自 1900 年起的年数
int tm_wday; // 一周中的第几天,范围从 0 到 6,从星期日算起
int tm_yday; // 一年中的第几天,范围从 0 到 365,从 1 月 1 日算起
int tm_isdst; // 夏令时
};
注意,上面的秒、分、时、月、兴起、天数均是从0开始计数,只有每月天数是从1开始计数。
相关库函数:
可以看到,常用的时间类型为time_t
和tm
结构。函数调用时参数基本都为指针,除了求两个时间之间的秒差。返回值也大多是指针。
Unix
时间戳(Unix timestamp),或称Unix
时间(Unix time)、POSIX
时间(POSIX time),是一种时间表示方式,定义为从格林威治时间1970年01月01日00时00分00秒
起至现在的总秒数。
目前相当一部分操作系统使用32位
二进制数字表示时间。此类系统的Unix时间戳最多可以使用到格林威治时间2038年01月19日03时14分07秒
(二进制:01111111 11111111 11111111 11111111
)。其后一秒,二进制数字会变为10000000 00000000 00000000 00000000
,发生溢出错误,造成系统将时间误解为1901年12月13日20时45分52秒
。这很可能会引起软件故障,甚至是系统瘫痪。使用64位
二进制数字表示时间的系统(最多可以使用到格林威治时间292,277,026,596年12月04日15时30分08秒
)则基本不会遇到这类溢出问题。
详情参见c++ 时间类型详解 time_t。
主要时间概念:
- 世界时
UT1
变到UT2
(格林威治时间GMT
) - 原子时
TAI
- 世界协调时
UTC
,是对UT2
调闰秒后的结果,是0时区
的时间。
UTC的表示方式为:年(y)、月(m)、日(d)、时(h)、分(min)、秒(s),均用数字表示。
可以认为格林威治时间就是时间协调时间(GMT
=UTC
),格林威治时间和UTC
时间均用秒数来计算的。
在计算机中看到的utc时间都是从(1970年01月01日 0:00:00)开始计算秒数的,因此,可以认为
UTC
和Unix
时间是一样的,但使用的时候精确单位需要自己选取。
linux
下存储时间常见的有两种存储方式,一个是从1970年到现在经过了多少秒,一个是用一个结构来分别存储年月日时分秒的。
time_t
这种类型就是用来存储从1970年到现在经过了多少秒,要想更精确一点,可以用结构struct timeval
,它精确到微妙。
struct timeval
{
long tv_sec; /*秒*/
long tv_usec; /*微秒*/
};
直接存储年月日的是一个结构:
struct tm
{
int tm_sec; /*秒,正常范围0-59, 但允许至61*/
int tm_min; /*分钟,0-59*/
int tm_hour; /*小时, 0-23*/
int tm_mday; /*日,即一个月中的第几天,1-31*/
int tm_mon; /*月, 从一月算起,0-11*/ 1+p->tm_mon;
int tm_year; /*年, 从1900至今已经多少年*/ 1900+ p->tm_year;
int tm_wday; /*星期,一周中的第几天, 从星期日算起,0-6*/
int tm_yday; /*从今年1月1日到目前的天数,范围0-365*/
int tm_isdst; /*日光节约时间的旗标*/
};
//复习一下
#include <iostream>
#include <ctime>
using namespace std;
int main()
{
time_t t;
time(&t);
//要不就直接time_t t=time(0);
cout << "time_t type: " << t << endl;
char *outt=ctime(&t);
cout << "time_t to char: " << outt << endl;
#if 1
tm *tt=gmtime(&t);
char *outtm=asctime(tt);
cout << "time_t to struct: " << outtm << endl;
#endif
return 0;
}
输出-----------------------------------
time_t type: 1646728734
time_t to char: Tue Mar 8 09:38:54 2022
time_t to struct: Tue Mar 8 08:38:54 2022
localtime
和'gmtime
的区别,前者还考虑到本地时区和夏令时标志,后者就是零时区。
#include <iostream>
#include <ctime>
using namespace std;
int main()
{
time_t t;
time(&t);
cout << "time_t type: " << t << endl;
char *outt=ctime(&t);
cout << "time_t to char: " << outt << endl;
#if 1
tm *tt=gmtime(&t);
char *outtm=asctime(tt);
cout << "time_t to struct: " << outtm << endl;
#endif
tm *lt=localtime(&t);
char *outlt=asctime(lt);
cout << "time_t to local struct: " << outlt << endl;
return 0;
}
输出-----------------------------------
time_t type: 1646728734
time_t to char: Tue Mar 8 09:38:54 2022
time_t to struct: Tue Mar 8 08:38:54 2022
time_t to local struct: Tue Mar 8 09:38:54 2022
3.基本输入输出
C++
的I/O
发生在流中,流是字节序列。如果字节流是从设备(如键盘、磁盘驱动器、网络连接等)流向内存,这叫做输入操作。如果字节流是从内存流向设备(如显示屏、打印机、磁盘驱动器、网络连接等),这叫做输出操作。
主要头文件:
注意数据的流向,采用<<
或>>
。两者都可以在一个语句中多次使用,如:
cin >> name >> age;//连续输入2个数,分别赋值给name和age
等同于
cin >> name;
cin >> age;
3.1 标准错误流
预定义的对象cerr
是iostream
类的一个实例。cerr
对象附属到标准错误设备,通常也是显示屏,但是cerr
对象是非缓冲的,且每个流插入到cerr
都会立即输出。
#include <iostream>
using namespace std;
int main()
{
int put;
put=0;
switch(put)
{
case 0:
cerr << "error occured." << endl;
break;
case 1:
cout << "already input 1." << endl;
break;
}
return 0;
}
3.2 标准日志流
预定义的对象clog
是iostream
类的一个实例。clog
对象附属到标准错误设备,通常也是显示屏,但是clog
对象是缓冲的。这意味着每个流插入到clog
都会先存储在缓冲区,直到缓冲填满或者缓冲区刷新时才会输出。
用起来和cerr
一样的。
#include <iostream>
using namespace std;
int main()
{
int put;
put=0;
switch(put)
{
case 0:
clog << "error occured." << endl;
break;
case 1:
cout << "already input 1." << endl;
break;
}
return 0;
}
4.数据结构
结构
是C++
中另一种用户自定义的可用的数据类型,它允许您存储不同类型的数据项
。
4.1 定义结构
为了定义结构,您必须使用struct
语句。struct
语句定义了一个包含多个成员的新的数据类型。
struct type_name {
member_type1 member_name1;
member_type2 member_name2;
member_type3 member_name3;
.
.
} object_names;//object_names可加可不加,不加的话后面定义用type_name object_names;就行
type_name
是结构体类型的名称,member_type1
、member_name1
是标准的变量定义,比如int i;
或者float f;
或者其他有效的变量定义。在结构定义的末尾,最后一个分号之前,您可以指定一个或多个结构变量,这是可选的。
整体和class
是差不多的。
class Box
{
public:
double length; // 盒子的长度
double breadth; // 盒子的宽度
double height; // 盒子的高度
};
举个例子:
struct cloth
{
char shirt[20];
char pants[30];
char shoes[30];
}dailycloth;
4.2 访问结构成员
为了访问结构的成员,我们使用成员访问运算符.
。成员访问运算符是结构变量名称和我们要访问的结构成员之间的一个句号。
#include <iostream>
#include <cstring>
using namespace std;
struct cloth
{
char shirt[20];
char pants[30];
char shoes[30];
int suit;
};
int main()
{
cloth dailycloth;
strcpy(dailycloth.shirt,"blue");
//strcpy(dailycloth.pants,"black");
strcpy(dailycloth.pants="black");
strcpy(dailycloth.shoes,"white");
dailycloth.suit=3;
cout << "shirt\t" << dailycloth.shirt << endl;
cout << "pants\t" << dailycloth.pants << endl;
cout << "shoes\t" << dailycloth.shoes << endl;
cout << "suit\t" << dailycloth.suit << endl;
return 0;
}
输出---------------------------------
shirt blue
pants black
shoes white
suit 3
注意!!!
在对结构体中的字符数组成员赋值时,采用strcpy()才可以,不然会出现数据类型问题
比如
dailycloth.pants="black";//错误
会出现incompatible types in assignment of ‘const char [6]’ to ‘char [30]’的报错。
关于结构体字符串的赋值问题里面有提到别的赋值方式。
//用指针
struct cloth
{
char *name;
};
cloth cc.name="blue";
//用scanf输入
struct cloth
{
char name[10];
};
cloth cc;
scanf("blue",&cc.name);
//定义赋值
struct cloth
{
char name[10];
};
cloth cc={"blue"};
4.3 结构体作为函数参数
结构体做参数,注意形参的数据类型是struct cloth
这样的struct
加结构体名称的样式。为传值调用。
#include <iostream>
#include <cstring>
using namespace std;
struct cloth
{
char color[20];
int num;
};
void output(struct cloth clo)
{
cout << "the color of cloth is " << clo.color << endl;
cout << "the number of cloth is " << clo.num << endl;
}
int main()
{
cloth clothes;
strcpy(clothes.color,"blue");
clothes.num=2;
output(clothes);
return 0;
}
输出-----------------------
the color of cloth is blue
the number of cloth is 2
4.4 指向结构的指针
您可以定义指向结构的指针,方式与定义指向其他类型变量的指针相似,赋值和一般变量相同,需要使用&
符号:
struct Books *struct_pointer;
Books *struct_pointer;
struct_pointer = &Book1;
函数中形参可以使用指向结构的指针,为指针调用,实参需要&
。
ps. 似乎只有数组在用指针的时候直接用数组名,一般单一变量都需要用
&
#include <iostream>
#include <cstring>
using namespace std;
void printBook( struct Books *book );
struct Books
{
char title[50];
char author[50];
char subject[100];
int book_id;
};
int main( )
{
Books Book1; // 定义结构体类型 Books 的变量 Book1
Books Book2; // 定义结构体类型 Books 的变量 Book2
// Book1 详述
strcpy( Book1.title, "C++ 教程");
strcpy( Book1.author, "Runoob");
strcpy( Book1.subject, "编程语言");
Book1.book_id = 12345;
// Book2 详述
strcpy( Book2.title, "CSS 教程");
strcpy( Book2.author, "Runoob");
strcpy( Book2.subject, "前端技术");
Book2.book_id = 12346;
// 通过传 Book1 的地址来输出 Book1 信息
printBook( &Book1 );
// 通过传 Book2 的地址来输出 Book2 信息
printBook( &Book2 );
return 0;
}
// 该函数以结构指针作为参数
void printBook( struct Books *book )
{
cout << "书标题 : " << book->title <<endl;
cout << "书作者 : " << book->author <<endl;
cout << "书类目 : " << book->subject <<endl;
cout << "书 ID : " << book->book_id <<endl;
}
为了使用指向该结构的指针访问结构的成员,您必须使用->
运算符。
struct_pointer->title;
注意!!!
1).
指向class
类(即对象)中的成员
2.)->
指向struct
结构中的成员
4.5 typedef
类型
可以为创建的类型取一个"别名"。
参考typedef 用法总结
typedef struct Books struct Books
{
char title[50];
char author[50];
char subject[100];
int book_id;
}Books;
typedef long int *pint32;
pint32 x, y, z;
5.类&对象
类是 C++ 的核心特性,通常被称为用户定义的类型。
类用于指定对象的形式,它包含了数据表示法和用于处理数据的方法。类中的数据、方法、函数称为类的成员。
5.1 类的定义
它定义了类的对象包括了什么,以及可以在这个对象上执行哪些操作。
注意:class
和struct
定义时,{}
后一定要加;
class cloth
{
public:
int num;
char color[10];
};
int main()
{
cloth c;
return 0;
}
在类对象作用域内,public
公共成员在类的外部是可访问的。
对象是类的实例,对类进行定义后就获得了一个对象。
#include <iostream>
using namespace std;
class cloth
{
public:
int num;
int types;
char brand[20];
int sum()//可以直接在class里面定义,也可以在外面定义,但要在主函数前面
{
return num*types;
}
void get(int n, int t);
};
void cloth::get(int n, int t)
{
num=n;
types=t;
}
int main()
{
cloth c;
//c.num=5;
//c.types=2;
c.get(5,2);
int output=c.sum();
cout << "the sum of cloth is " << output << endl;
return 0;
}
梳理一下写的时候会遗漏的东西:
1)class
中要注意写上public:
或private:
或protected:
2)如果class
中的函数成员要在类之外定义,那么一定要加上范围解析运算符,比如cloth::
3)给class
中成员赋值或者调用函数的时候,记得使用类名.
,如c.
这样的格式去调用成员
但是私有的成员和受保护的成员不能使用直接成员访问运算符.
来直接访问