C++基础概念(下)
# 循环
在满足条件的情况下重复执行一份代码
# 循环类型
while、for 或 do..while 循环
循环可以嵌套使用
# 循环控制语句
控制语句 | 描述 |
---|---|
break | 循环体结束,执行下面代码 |
continue | 当前循环代码结束,执行下一次循环判断 |
goto | 直接跳转到对应的代码执行 |
# 无限循环
while、for 或 do..while 循环中,如果条件永远不为假,则循环将变成无限循环
#include <iostream>
using namespace std;
int main ()
{
for( ; ; ){
printf("无限循环.\n");
}
return 0;
}
# 判断语句
也就是比较相关
比如:
if - else if
以及三位运行符号:
Exp1 ? Exp2 : Exp3;
# 函数
函数是代码块的复用
包含修饰,返回类型,函数名称,参数 等等
# 函数声明
告诉编译器有这么个函数可以使用:
return_type function_name( parameter list );
# 定义函数
函数具体实现内容
return_type function_name( parameter list )
{
body of the function
}
# 调用函数
函数调用要根据函数对应作用域来使用,局部还是全局,对象还是类等等
eat();
# 函数参数
默认情况下,C++ 使用传值调用来传递参数
函数传递参数的方式:
参数 | 描述 |
---|---|
传值 | 对象的数据值作为参数,函数内修改不影响这个对象 |
指针参数 | 参数是对象指针,函数内修改后会被影响 |
引用对象 | 参数是对象引用,函数内修改后会被影响 |
# 函数参数的默认值
当您定义一个函数,您可以为参数列表中后边的每一个参数指定默认值。当调用函数时,如果实际参数的值留空,则使用这个默认值。
这是通过在函数定义中使用赋值运算符来为参数赋值的。调用函数时,如果未传递参数的值,则会使用默认值,如果指定了值,则会忽略默认值,使用传递的值。请看下面的实例:
#include <iostream>
using namespace std;
int sum(int a=1, int b=2){
return a + b;
}
int main (){
int result = sum();
cout << "默认求和值 :" << result << endl;
result = sum(3);
cout << "求和值 :" << result << endl;
result = sum(4, 6);
cout << "求和值 :" << result << endl;
return 0;
}
结果:
默认求和值 :3
求和值 :5
求和值 :10
# 数据操作函数
常见数据操作库函数:
函数 | 描述 |
---|---|
double cos(double); | 该函数返回弧度角(double 型)的余弦。 |
double sin(double); | 该函数返回弧度角(double 型)的正弦。 |
double tan(double); | 该函数返回弧度角(double 型)的正切。 |
double log(double); | 该函数返回参数的自然对数。 |
double pow(double, double); | 则该函数返回 x 的 y 次方。 |
double hypot(double, double); | 该函数返回两个参数的平方总和的平方根 |
double sqrt(double); | 该函数返回参数的平方根。 |
int abs(int); | 该函数返回整数的绝对值。 |
double fabs(double); | 该函数返回任意一个十进制数的绝对值。 |
double floor(double); | 该函数返回一个小于或等于传入参数的最大整数。 |
# 随机数函数
rand();
#include <iostream>
#include <ctime>
#include <cstdlib>
using namespace std;
int main ()
{
int i,j;
// 设置种子(生成随机数之前先调用 srand()函数初始化)
srand( (unsigned)time( NULL ) );
for( i = 0; i < 3; i++ ){
// 生成实际的随机数
j= rand();
cout <<"随机数: " << j << endl;
}
return 0;
}
# 数组
1、数组存储一个一系列大小的相同类型元素的顺序集合
2、数组中的特定元素可以通过索引访问
3、所有的数组都是由连续的内存位置组成
4、最低的地址对应第一个元素,最高的地址对应最后一个元素
5、虽然分配了空间,但是没有存储数据的地址强行取值会发生数组越界
# 声明数组
声明一个类型为 int 的最多包含 10 个元素的数组 tags,声明语句如下:
int tags[10];
# 初始化数组
逐个初始化数组,大括号 { } 列举:
int tags[3] = {5, 6, 8}; // 最多3个
不限制元素的个数:
int tags[] = {5, 6, 8, 2, 4};
修改数组中某个元素值:
tags[2] = 50;
# 访问数组元素
通过数组名称加索引进行访问:
int tag = tags[2];
# 多维数组
声明创建了一个二维 整型数组:
int coords[3][4];
声明创建了一个三维 整型数组:
int cube[3][4][5];
# 初始化多维数组
初始化二维数组
下面是一个带有 3 行 4 列的数组:
int coords[3][4] = {
{0, 1, 2, 3} , /* 初始化索引号为 0 的行 */
{4, 5, 6, 7} , /* 初始化索引号为 1 的行 */
{8, 9, 10, 11} /* 初始化索引号为 2 的行 */
};
与上面是等同的:
int coords[3][4] = {0,1,2,3,4,5,6,7,8,9,10,11};
# 指向数组的指针
int tags[3] = {5, 6, 8};
// 1、tags 是指向首地址的,指向 &tags[0] 的指针
int sec = *(tags + 1); // 通过指针和下标取值
int *p;
p = tags; // 指针新名称
int one = *p;
int sec = *(p+1);
int th = *(p+2);
# 传递数组给函数
// 形式参数是一个指针:
void func_1(int *arr)
{
}
// 形式参数是一个已定义大小的数组:
void func_2(int arr[3])
{
}
// 形式参数是一个未定义大小的数组
void func_3(int arr[])
{
}
# 函数返回数组
1、函数不能之间返回数组对象,可以返回数组指针
2、如果返回的是局部变量数组(默认分配在栈空间)指针,那么调用时这个对象已经释放了,这是不对的
3、可以返回堆内存的数组指针(需要手动new 和 delete)
4、可以直接返回全局变量指针,或者静态对象指针等等
示例:
#include <iostream>
using namespace std;
int * func_re()
{
// int tags[3] = {5, 6, 8}; 这个不行,返回时对象将被系统释放了
int *tags = new int[2]; // 通过new 分配堆内存对象
tags[0] = 5;
tags[1] = 8;
return tags;
}
int main()
{
int *tags = func_re();
cout << tags[0] << "," << tags[1] << endl;
delete[] tags; // 通过delete 释放开辟的空间
}
# 字符串
# C 字符串
#include <iostream>
#include <cstring>
using namespace std;
int main ()
{
char hellos[6] = {'H', 'e', 'l', 'l', 'o', '\0'};
char str1[11] = "Hello";
char str2[11] = "World";
char str3[11];
int len ;
strcpy(str3, str1);
cout << "复制 str1 到 str3: " << str3 << endl;
char *str4;
str4 = strcat(str1, str2);
cout << "连接 str1 和 str2: " << str4 << endl;
len = strlen(str4);
cout << "连接后,str4 的总长度: " << len << endl;
return 0;
}
# C++ 字符串
C++ 标准库对这些运行增加了运算符的支持,使得操作简单化:
#include <iostream>
#include <string>
using namespace std;
int main ()
{
string str1 = "Hello";
string str2 = "World";
string str3;
int len ;
str3 = str1;
cout << "复制 str1 到 str3 : " << str3 << endl;
str3 = str1 + str2;
cout << "连接 str1 和 str2: " << str3 << endl;
len = str3.size();
cout << "连接后,str3 的总长度 : " << len << endl;
return 0;
}
# 指针
# 访问内存地址
可使用连字号(&)运算符访问的地址:
#include <iostream>
using namespace std;
int main (){
int a = 2;
cout << "a 变量的地址:" << &a << endl;
return 0;
}
结果:
a 变量的地址:0x7ffe0112efec
# 指针?
指针是一个变量,存储内存位置的直接地址,声明时加上*号:
#include <iostream>
using namespace std;
int main (){
int a = 2;
cout << "a 变量的值:" << a << endl;
cout << "a 变量的地址:" << &a << endl;
int *p; // 指针变量的声明
p = &a; // 指针变量存储对象地址
cout << "指针变量p变量的地址:"<< p << endl;
cout << "指针变量p变量的地址上的值:"<< *p << endl;
return 0;
}
结果:
a 变量的值:2
a 变量的地址:0x7ffc6eeeeb04
指针变量p变量的地址:0x7ffc6eeeeb04
指针变量p变量的地址上的值:2
# 空指针
NULL 指针是一个定义在标准库中的值为零的常量。
#include <iostream>
using namespace std;
int main ()
{
int *p = NULL;
cout << "p 的值是 " << ptr ;
return 0;
}
结果:
p 的值是 0
# 指针移动
指针+1 表示当前对象内存地址偏移到下一个对象的内存地址上
指针-1 表示当前对象内存地址偏移到上一个对象的内存地址上
#include <iostream>
using namespace std;
class Person
{
public:
int borth_y;
int lenght;
int age;
};
int main( )
{
Person person;
person.borth_y = 2018;
person.lenght = 100;
person.age = 4;
int *p = &person.lenght; // 每次移动4字节内存
cout << "指针变量p变量的地址值:"<< *(p) << endl;
cout << "指针变量p变量的下一个地址值:"<< *(p+1) << endl;
cout << "指针变量p变量的上一个地址值:"<< *(p-1) << endl;
return 0;
}
结果
指针变量p变量的地址值:100
指针变量p变量的下一个地址值:4
指针变量p变量的上一个地址值:2018
发现规律了吧
# 指针和数组
前面介绍了,一个对象三个成员之间可以通过指针移动来获取,并且取值结果通常是同类型的值
那么显然这很符合数组的规律,很好解释了数组的下标操作数据的原理:
#include <iostream>
using namespace std;
int main( )
{
int ages[6] = {10, 13, 8, 4, 7, 3};
cout << "ages[0] = "<< ages[0] << endl;
cout << "ages[1] = "<< ages[1] << endl;
cout << "ages[2] = "<< ages[2] << endl;
int *p = ages;
cout << "p = "<< *(p) << endl;
cout << "p+1 = "<< *(p+1) << endl;
cout << "p+2 = "<< *(p+2) << endl;
return 0;
}
结果
ages[0] = 10
ages[1] = 13
ages[2] = 8
p = 10
p+1 = 13
p+2 = 8
结果和操作数组一样,其实本质是一样的。
# 指向指针的指针
指向指针的指针是一种多级间接寻址的形式,或者说是一个指针链:
1、变量 :存储 对应数据
2、p指针:存储 变量的地址
3、指针的指针:存储 p指针的地址
#include <iostream>
using namespace std;
int main( )
{
int age = 18; // 变量
int *p = &age; // p指针 存储 变量的地址
int **p_p = &p; // 指针的指针 存储 p指针的地址
cout << "age = " << age << endl;
cout << "*p = " << *p << endl;
cout << "**p_p = " << **p_p << endl;
cout << "age地址 = " << &age << endl;
cout << "指针p值 = " << p << endl;
cout << "指针p地址 = " << &p << endl;
cout << "指针p_p值 = " << p_p << endl;
return 0;
}
结果
age = 18
*p = 18
**p_p = 18
age地址 = 0x7ffc9463e594
指针p值 = 0x7ffc9463e594
指针p地址 = 0x7ffc9463e588
指针p_p值 = 0x7ffc9463e588
# 函数指针参数
#include <iostream>
using namespace std;
void fun1(int *p)
{
cout << "*p = " << *p << endl;
}
int main( )
{
int age = 18;
int *p = &age; // 指向int的指针
fun1(p);
return 0;
}
结果
*p = 18
# 函数返回指针
#include <iostream>
using namespace std;
int * fun2(int *p)
{
return p;
}
int main( )
{
int age = 18;
int *p = &age; // 指向int的指针
int *p2 = fun2(p);
cout << "*p2 = " << *p2 << endl;
return 0;
}
结果
*p2 = 18
# 引用(别名)
# 引用
引用变量是一个别名,也就是说,它是某个已存在变量的另一个名字(引用不能指向null)
引用 和 指针:
1、引用必须指向合法的内存,指针不用
2、引用一个对象后不能被指向到另一个对象,指针可以
3、引用必须在创建时被初始化,指针可以在任何时间被初始化
示例:
引用通过 类型+& 声明
#include <iostream>
using namespace std;
int main( )
{
int age = 18;
// 声明引用变量
int& A = age;
cout << "age = " << age << endl;
cout << "A = " << A << endl;
return 0;
}
结果:
age = 18
A = 18
A 是 age 的别名,使用相同
# 引用作为参数
#include <iostream>
using namespace std;
void fun1(int& a)
{
cout << "A = " << a << endl;
}
int main( )
{
int age = 18;
// 声明引用变量
int& A = age;
fun1(A);
return 0;
}
# 函数中返回引用
#include <iostream>
using namespace std;
int& fun2(int& a)
{
return a;
}
int main( )
{
int age = 18;
// 声明引用变量
int& A = age;
int& A2 = fun2(A);
cout << "A2 = " << A2 << endl;
return 0;
}
# 流
# 标准输入输出流
iostream 输入/输出库
输入:cin
输出:cout
#include <iostream>
using namespace std;
int main(){
char name[50];
cout << "输入名称:" << endl;
cin >> name;
cout << "您好 " << name << endl;
}
结果:
输入名称:
您好 Dean
# 标准错误流(cerr)
cerr 是 ostream 类的一个实例。
cerr 将错误信息【立即】显示到显示屏
#include <iostream>
using namespace std;
int main(){
char str[] = "open fail !";
cerr << "Error : " << str << endl;
}
结果:
Error : open fail !
# 标准日志流(clog)
clog 是 ostream 类的一个实例。
clog 将日志信息显示到显示屏
但是 clog 对象是缓冲的,缓冲填满或者缓冲区刷新时才会输出。
#include <iostream>
using namespace std;
int main(){
char str[] = "load success !";
clog << "🍻 : " << str << endl;
}
当上面的代码被编译和执行时,它会产生下列结果:
🍻 : load success !
# 数据结构struct
# 定义结构
struct Books{
char title[50];
char author[50];
char subject[100];
int price;
} book;
# 结构的使用
#include <iostream>
#include <cstring>
using namespace std;
void printBook( struct Books book );
Books book(string t, int pri);
struct Books{
string title;
int price;
};
int main(){
Books book1 = book("财经", 34);
// 输出 book1 信息
printBook( book1 );
return 0;
}
// 创建并返回一个结构体
Books book(string t, int pri) {
struct Books book;
book.title = t;
book.price = pri;
// Books *bp = &book;
return book;
}
// 结果体作参数
void printBook( struct Books book ){
cout << "Book title : " << book.title <<endl;
cout << "Book price : " << book.price <<endl;
}
结果:
Book title : 财经
Book price : 34
# typedef (别名)
typedef 可以给结构体取别名(类雏形),不同于引用别名,引用只能是已赋值对象的别名。
例如:
#include <iostream>
#include <cstring>
using namespace std;
typedef struct
{
string title;
int price;
}Books;
int main(){
Books book;
book.title = "书名";
book.price = 23;
cout << "Book title : " << book.title <<endl;
cout << "Book price : " << book.price <<endl;
return 0;
}
结果:
Book title : 书名
Book price : 23
可以使用 typedef 关键字来定义非结构类型,如下所示:
#include <iostream>
#include <cstring>
using namespace std;
int main(){
// 给 “unsigned short int” 取别名 usint
typedef unsigned short int usint;
usint x = 2;
cout << "x : " << x <<endl;
return 0;
}
结果
x : 2