文章目录
1.结构体
1.C中struct结构体
- 想存放
函数
,得使用函数指针
#include <stdio.h>
typedef void (*pfunc)(); // 函数指针
struct Stu{
char* name;
int age;
pfunc action; // 函数指针
};
void write_code(){
printf("正在努力的写代码\n");
}
int main(){
struct Stu stu = {"zhangsan",18,write_code};
stu.action(); // 正在努力的写代码
return 0;
}
2.C++中的struct结构体
-
C++中的struct结构体在定义变量,再也不需要写冗余的
struct
关键字 -
C++中的struct结构体,默认是public访问权限
-
函数
不占用
结构体类型空间#include <iostream> using namespace std; struct Stu { int age; void wirte_code(){ cout << "正在写代码" << endl; } }; int main() { Stu stu; stu.age = 18; stu.wirte_code(); // 正在写代码 cout <<sizeof(stu)<<" , "<< stu.age << endl; // 4 , 18 // 就int的4字节;函数不占用结构体类型空间 return 0; }
2.string类型字符串
at()
是有边界检查 ; 越界访问 报错[ ]
运算符函数是没有边界的。会越界访问 不报错front()
首字符,back()
尾字符empty()
判断是否为空+
或者append()
拼接字符串getline(cin,变量)
输入可以空格 输出一行
string name = "baidu.com";
//获取具体的位置的某个字符。
cout << name.at(0) << endl; //at是有边界检查的 ; 越界访问 报错
cout << name[9] << endl;// [ ]运算符函数是没有边界的。会越界访问 : 不报错
// 首 h 尾部 m
cout << name.front() << "," << name.back() << endl;
if(!name.empty())
cout << "字符串对象中有字符" << endl;
string name2 = "www.";
//拼接字符串。
cout << name2 + name << endl; // www.baidu.com
cout << name2.append(name) << endl; // www.baidu.com
string tmp;
getline(cin,tmp); // 输入可以空格 输出一行
cout << tmp;
3.&运算符
&
取地址运算符。&
取 数组首 地址 为升维
为一个数组指针&
取 函数地址 为升维
为此函数的函数指针类型的指针
int a = 10;
int* p = &a; // 指针 -> a 的地址
int arr[3] = {100,1,3};
int (*pa)[3] = &arr; // &arr是一个数组指针
cout << **(pa) <<"," << *(*pa) <<endl; // 100 , 100
cout << *(*pa+2) << ","<< *(*(pa)+2) <<endl; //3
void show()
{
cout << " AAAA" << endl;
}
// 函数指针
void (*pfunc)() = show; // show是 (void*)类型
void (*pfunc_a)() = &show; // 如果加了& 之后 void (*)() 函数指针类型
pfunc(); // AAAA
pfunc_a(); // AAAA
4.const
- C语言中 在 声明结构体 里,用
const修饰
,会报错 **: 声明结构体,没有内存,const修饰变量或指针都有内存 ** - 当const修饰的变量 或 指针,必须
赋初值
。但指针的特性:1.指针可以不用赋初始值,语法也允许野指针的存在
#include <stdio.h>
struct Stu{
const int age; // const修饰变量,声明结构体,没有内存,会报错; 现在编译器自动优化,不报错
};
int main(){
struct Stu stu = {18}; // 初始化
printf("%d\n",stu.age);//18
return 0;
}
- 在C++中有一个 符号常量表 的概念。这个 符号常量表 是由 编译器 维护,当使用
const 修饰
的内置类型的变量时,C++的编译器就会把这个变量中的值 存放在 符号常量表 (直接赋值,编译器 才会 把它放在 符号常量表) - 变量存放在 符号常量表 就无法 使用指针 强制类型转换修改
#include <iostream>
using namespace std;
int main()
{
#if 0
int const a = 100; // 如果是这种直接赋值,编译器 会 把它放在 符号常量表。
int* p = (int*)&a; // 强制类型转换 失败
*p = 200; // 修改失败
cout << "a = " << a << endl; // a = 100
#else
int b = 100;
int const a = b; //如果出现这种传递的操作,编译器也不会把它放在符号常量表。
int* p = (int*)&a; // 强制类型转换 成功 去掉 const
*p = 200; // 修改成功
cout << "a = " << a << endl; // a = 200
#endif
return 0;
}
-
当const 修饰 普通变量(a\b) 时,变量为只读,不可修改的属性。
-
当const修饰指针变量时,
在
*
前 则修饰的是 指针类型,此指针不可以
改变 指向空间中的值
。
在*
后 则修饰的是这个 指针变量本身。也就是 指向的地址 是不可以变的, 所以
不可以 指向别外
的一块空间,但可以
改变是指向空间的值
。
int a = 100;
const int b = 1000;
//b = 99; // 报错;不能 用const给变量'b' 赋值…
const int* pa= &a; // <==>int const *pa= &a;
//*pa = 99; // 错误;只读变量 不可赋值
pa =&b; // cout<<*pa<<endl; // 1000 ;成功改指向
int* const pb = &a;
*pb = 99; // 成功 改指向 内存空间中的 值的。
//pb = &b; // 错误,不能改指向
5.C++内联函数 inline
- 内联函数不能 逻辑过于复杂 或有 延时等待 或耗时操作,编译器将会自动停止内联。
- C++内联函数是有代价的:函数代码的膨胀
#define ADD(x,y) (x+y) // 在 预处理 阶段展开
#define MAX(x,y) (((x) > (y))? (x) :(y))
// 内联函数
inline int max(int a, int b)
{
return a > b? a : b;
}
int main()
{
int a = 10;
int b = 20;
int sum = ADD(a,b) * 5; // 若#define ADD(x,y) x+y 则 sum =x + y * 5
cout << sum << endl; // 150
cout << "-------------------------------------------------------" << endl;
int c = 10;
int d = 20;
int e = MAX(c,++d); //10 >++20? 10:++21 y=22
cout << e << endl; // 22
cout << "-------------------------------------------------------" << endl;
d = 20;
int e1 = max(c,++d); // 10 >21 ? 10 : 21
cout << e1 << endl; // 21
return 0;
}
6.函数重载
-
当同一作用域下的同名函数,如果出现,函数
参数
的类型
及个数
不同时,就会发生函数重载
-
与
返回值
没关系;( 函数形参列表
的类型
及个数
不同 )C++编译器,在编译时,根据函数中的参数类型与个数不同,在 符号表 中重新生成一个 新的函数名。所以同一作用域下的两个函数不会产生命名冲突。
int add(int a , int b) { return a + b; } float add(float a, float b) { return a + b; }
7.&引用
- 类型
&
变量名 = 另一个变量名; - 引用的本质:就是一个
const修饰的指针
,它指向一块已经 存在
的固定的内存空间,所以 引用不会 出现野指针的情况 int* const p = &a;
p 不可以 指向别外
的一块空间,但可以
改变是指向空间的值
int a = 100;
int* p = &a; // &取地址
*p = 888;
cout << a << endl; //a=888
int* const p = &a; // 本质
//&引用
int& b = a; //引用,理解为变量的别名
cout << b << endl; //b=888
b=999;
cout << b <<","<< a << endl; //b=999,a=999
a=1111111;
cout << b << endl; //a=b=1111111
- 函数传参,优先使用引用。因为他与指针一样高效,并保证了指向空间的合法性。是一种安全机制。
void swap(int& a, int& b) // 引用传参
{
int tmp = a;
a = b;
b = tmp;
}
int main()
{
int a = 10, b = 20;
swap(a,b); // a=20,b=10
return 0;
}
8.常引用const &
const
类型&
变量名 = 常量 。const int& b = 10;
void show(const string& str) //常引用
{
cout << str << endl;
}
int main()
{
const int& b = 10; // 加了 const 修饰的引用 就是一个 常引用,可以引用常量。
//string& name1 = "www.baidu.com"; //错误;要 指向一块 已经存在 的固定的内存空间
const string& name1 = "www.baidu.com"; //正确 ;
//会临时开辟 一块内存空间; string tep = "wwww.baidu.com"; const string& name2 = tep;
show("www.baidu.com"); // www.baidu.com
return 0;
}
字符串常量(“www.baidu.com”)是一个字符数组,它在程序编译时被分配在
静态存储区
域中,并且其内部元素是不可修改
的。一个
非 const 引用
不能绑定到一个临时对象
或字符串常量
。当你尝试通过非 const 引用来初始化一个字符串对象时,编译器会报错。
因为引用是一个别名,通过它可以改变所引用的对象,而字符串常量是一个常量值,其值不能被修改。
所以,正确的方式应该是使用 const 引用来绑定到字符串字面值常量上,如下所示:
const string& name1 = "www.baidu.com";
这样做是允许的,因为使用 const 修饰引用表示所指向的对象是只读的,不能被修改,从而避免了引起系统运行错误的可能性
。
9.动态开辟空间new
new
连续开辟的堆区空间,则需要使用delete[]
来释放
1. int* p = new int(0);
delete p;//释放空间
2. string* s = new string;
delete s;
3. double* d = new double;
delete d;
4. int* pa = new int[3]{0,1,2}; //在堆区 使用new连续开辟空间 并 初始化 。 C++11方式。
delete [ ] pa;//释放连续空间
5. int* pb = new int[3]; //在堆区 使用new开辟了一块连续空间。
delete [ ] pb;