1. 指针
定义指针变量
C 语言中,定义变量时,在变量名 前 写一个 *
星号,这个变量就变成了对应变量类型的指针变量。必要时要加 ( ) 来避免优先级的问题。
引申:C 语言中,定义变量时,在定义的最前面写上 typedef ,那么这个变量名就成了一种类型,即这个类型的同义词。
int a ; //int类型变量 a
int *a ; //int* 变量a
int arr[3]; //arr是包含3个int元素的数组
int (* arr )[3]; //arr是一个指向包含3个int元素的数组的指针变量
//-----------------各种类型的指针------------------------------
int* p_int; //指向int类型变量的指针
double* p_double; //指向idouble类型变量的指针
struct Student *p_struct; //结构体类型的指针
int(*p_func)(int,int); //指向返回类型为int,有2个int形参的函数的指针
int(*p_arr)[3]; //指向含有3个int元素的数组的指针
int** p_pointer; //指向 一个整形变量指针的指针
取地址
既然有了指针变量,那就得让他保存其它变量的地址,使用 &
运算符取得一个变量的地址。
int add(int a , int b)
{
return a + b;
}
int main(void)
{
int num = 97;
float score = 10.00F;
int arr[3] = {1,2,3};
//-----------------------
int* p_num = #
float* p_score = &score;
int (*p_arr)[3] = &arr;
int (*fp_add)(int ,int ) = add; //p_add是指向函数add的函数指针!!
return 0;
}
特殊的情况,他们并不一定需要使用 & 取地址:
- 数组名的值就是这个数组的第一个元素的地址。
- 函数名的值就是这个函数的地址。
- 字符串字面值常量作为右值时,就是这个字符串对应的字符数组的名称, 也就是这个字符串在内存中的地址。
int add(int a , int b){
return a + b;
}
int main(void)
{
int arr[3] = {1,2,3};
//-----------------------
int* p_first = arr;
int (*fp_add)(int ,int ) = add;
const char* msg = "Hello world";
return 0;
}
解地址
我们需要一个数据的指针变量干什么?当然使用通过它来操作(读 / 写)它指向的数据啦。对一个指针解地址,就可以取到这个内存数据,解地址的写法,就是在指针的前面加一个 *
号。
解指针的实质是:从指针指向的内存块中取出这个内存数据。
int main(void)
{
int age = 19;
int*p_age = &age;
*p_age = 20; //通过指针修改指向的内存数据
printf("age = %d\n",*p_age); //通过指针读取指向的内存数据
printf("age = %d\n",age);
return 0;
}
Null 指针
在变量声明的时候,如果没有确切的地址可以赋值,为指针变量赋一个 NULL 值是一个良好的编程习惯。赋为 NULL 值的指针被称为空指针,它表明该指针不指向一个可访问的内存位置。
int *ptr = NULL;
if(ptr) /* 如果 ptr 非空,则完成 */
if(!ptr) /* 如果 ptr 为空,则完成 */
指针的算术运算
ptr++
会带来什么?
int *ptr : 假设指向地址 1000 的整型指针,是一个 32 位的整数,递增一次后,将指向下一个整数位置,即当前位置往后移 4 个字节,1004
char *ptr : 假设 ptr 指向一个地址为 1000 的字符,递增一次后,将指向下一个字符 1001
指针的比较
指针可以用关系运算符进行比较,如 ==、< 和 >。如果 p1 和 p2 指向两个相关的变量,比如同一个数组中的不同元素,则对 p1 和 p2 进行大小比较是有意义的,否则比较地址值的大小通常没有意义。
指针 vs 数组
指针和数组在很多情况下是可以互换的,但注意不能修改数组名的值
#include <iostream>
using namespace std;
const int MAX = 3;
int main ()
{
int var[MAX] = {10, 100, 200};
for (int i = 0; i < MAX; i++)
{
*var = i; // 这是正确的语法
*(var + 2) = i; // 这是正确的语法
var++; // 这是不正确的
}
return 0;
}
指针的数组
int *ptr[MAX];// ptr 中的每个元素,都是一个指向 int 值的指针
const char *names[MAX] = {
"Zara Ali",
"Hina Ali",
"Nuha Ali",
"Sara Ali",
};//names 的每一个元素都指向一个char类型的指针,可以存储一个字符串列表
指向指针的指针(多级间接寻址)
int **var;
指向指针的指针是一种多级间接寻址的形式,或者说是一个指针链。通常,一个指针包含一个变量的地址。当定义一个指向指针的指针时,第一个指针包含了第二个指针的地址,第二个指针指向包含实际值的位置。
2. 引用
引用是某个已存在变量的别名。
引用 vs 指针
- 不存在空引用。引用必须连接到一块合法的内存。
- 一旦引用被初始化为一个对象,就不能被指向到另一个对象。指针可以在任何时候指向到另一个对象。
- 引用必须在创建时被初始化。指针可以在任何时间被初始化。
// 声明简单的变量
int i;
double d;
// 声明引用变量 "&" 读作引用
int& r = i;// r 是一个初始化为 i 的整型引用
double& s = d;// s 是一个初始化为 d 的 double 型引用
引用作为参数和返回值
通过使用引用来替代指针,会使 C++ 程序更容易阅读和维护
// 把引用作为参数,会改变内存值
void swap(int& x, int& y);
//引用作为返回值,要注意被引用的对象不能超出作用域,返回一个对**局部变量**的引用是不合法的
double vals[] = {10.1, 12.6, 33.1, 24.1, 50.0};
double& setValues( int i )
{
return vals[i]; // 返回第 i 个元素的引用
}
3. C++ 日期 & 时间
#include <ctime>
四个与时间相关的类型:clock_t、time_t、size_t 和 tm
#include <iostream>
#include <ctime>
using namespace std;
int main( )
{
// 基于当前系统的当前日期/时间
time_t now = time(0);
// 把 now 转换为字符串形式
char* dt = ctime(&now);
cout << "本地日期和时间:" << dt << endl;
// 把 now 转换为 tm 结构
tm *gmtm = gmtime(&now);
dt = asctime(gmtm);
cout << "UTC 日期和时间:"<< dt << endl;
}
4. C++ 基本的输入输出
I/O头文件
头文件 | 函数和描述 |
---|---|
<iostream> | 该文件定义了 cin、cout、cerr 和 clog 对象,分别对应于标准输入流、标准输出流、非缓冲标准错误流和缓冲标准错误流。 |
<iomanip> | 该文件通过所谓的参数化的流操纵器(比如 setw 和 setprecision),来声明对执行标准化 I/O 有用的服务。 |
<fstream> | 该文件为用户控制的文件处理声明服务。 |
iostream
#include <iostream>
using namespace std;
int main( )
{
char name[50];
cout << "请输入您的名称: ";//<< 运算符被重载来输出内置类型(整型、浮点型、double 型、字符串和指针)的数据项
cin >> name; //cin >> name >> age;相当于cin >> name; cin >> age;
cout << "您的名称是: " << name << endl;
char str[] = "Unable to read....";
//标准错误流
cerr << "Error message : " << str << endl;//附属到标准错误设备,通常也是显示屏
//标准日志流
clog << "Error message : " << str << endl;
}
5. Struct 结构
struct type_name {
member_type1 member_name1;
member_type2 member_name2;
member_type3 member_name3;
.
.
} object_names;
使用成员访问运算符(.)访问
结构作为函数参数
可以把结构作为函数参数,传参方式与其他类型的变量或指针类似
指向结构的指针
可以定义指向结构的指针,方式与定义指向其他类型变量的指针相似
struct Books *struct_pointer;
struct_pointer->title;//使用 -> 运算符,指向该结构的指针 的成员
typedef 关键字
是一种更简单的定义结构的方式,可以为创建的类型取一个"别名"
typedef struct
{
char title[50];
char author[50];
char subject[100];
int book_id;
}Books;
typedef long int *pint32;
Books Book1, Book2;
pint32 x, y, z;