C++ premier Plus书之--C++指针, 数组, 结构体, 字符串

指针和字符串, demo:

#include "iostream"
#include "cstring"
using namespace std;
 
int main() {
       char animal[20] = "bear";
       // 字符常量指针, 也就是bird指向的内存时不允许修改的
       const char* bird = "wren";
       char* ps;
      
       cout << animal << " and ";
       cout << bird << endl;
       // 随机显示, 可能是空格, 也可能崩溃
       // cout << ps << endl;
      
       cout << "Enter a kind of animal : ";
       cin >> animal;
      
       ps = animal;
       cout << ps << "!\n";
       cout << "Before using strcpy()" << endl;
	   // 输出的是animal字符数组的首地址
       cout << animal << " at " << (int *) animal << endl;
       cout << "&animal is " << &animal << endl;
       cout << ps << " at " << (int *)ps << endl;
       cout << " ps is " << ps << endl;
	   // 这里输出的不是指针指向的内容的地址, 而是指针变量的地址, 因此与上面的输出地址不同
       cout << " &ps " << &ps << endl;
      
	   // 这么声明字符数组可以节省空间
       ps = new char[strlen(animal) + 1];
       stpcpy(ps, animal);
       cout << "After using strcpy() : " << endl;
       cout << animal << " at " << (int *) animal << endl;
       cout << ps << " at " << (int *)ps << endl;
       delete[] ps;
       return 0;
      
}

上面程序的运行结果如下:

从程序运行结果可以看出:

对数组名应用(int *)animal 可以得到字符数组的首地址, 和对指针应用(int *)类似

指针和结构体

看一个简单的应用demo:

// 指针和结构体
#include "iostream"
#include "cstring"
using namespace std;
 
struct things {
       int good;
       int bad;
};
 
struct inflatable {
       char name[20];
       float volume;
       double price;
};
 
int main() {
       things gurbnose = {1, 23};
       // 将创建的结构体的首地址赋值给指针
       things* pt = &gurbnose;
      
       // 结构体变量访问结构体内成员使用.符号
       cout << "gurbnose.good = " << gurbnose.good << ", and gurbnose.bad = " << gurbnose.bad << endl;
       // 结构体指针访问结构体内成员使用->符号
       cout << "pt->good = " << pt->good  << ", and pt->bad  = " << pt->bad << endl;
      
       // 另一种通过指针访问结构体的成员的方法使使用(*pt).price, 这种方法
       // 因为pt是指向结构体的指针, 因此(*pt)就是该结构体, 因此可以通过(*pt).的这种方式访问成员
       // 创建了一个结构体指针
       inflatable* ps = new inflatable;
       cout << "Enter name of inflatable item: ";
       cin.get(ps->name, 20);
       cout << "Enter volume in cubic feet: ";
       cin >> (*ps).volume;
       cout << "Enter the price : ";
       cin >> ps->price;
      
       cout << "Name : " << (*ps).name << endl;
       cout << "volume : " << ps->volume << endl;
       cout << "price : " << (*ps).price << endl;
       // 记得释放new申请的空间
       delete ps;
       return 0;
      
}

程序的运行结果如下:

从demo中可以看出指针引用结构体的成员的方法有两种, 假如ps是指向结构体的指针, 结构体里有price这个成员:

  1. ps->price
  2. (*ps).price

这两种方法均可

从上面的demo中可以看出new和delete是成对出现的, 再看一个new和delete的例子:

// new和delete
#include "iostream"
#include "cstring"
using namespace std;
 
// 声明函数原型
char* getName(void);
 
int main() {
       char* name;
       name = getName();
       cout << name << " at " << (int*)name << endl;
       cout << "name : " << name << endl;
       // 释放资源
       delete[] name;
      
       name = getName();
       cout << name << " at " << (int*)name << endl;
	   // 这个输出的是指针name的地址而不是指针指向的字符串的首地址
       cout << "&name : " << &name << endl;
       delete[] name;
       return 0;
}
 
char* getName() {
       // 声明了一个临时存储空间
       char temp[80];
       cout << "Enter your name : ";
       cin >> temp;
       // 声明了一个char型指针, 指向一个长度是输入的字符串长度+1的char型数组的起始地址
       char* pn = new char[strlen(temp) + 1];
       strcpy(pn, temp);
       return pn;
}

程序运行结果:

从代码中可以看出来,

1.new和delete要成对的使用,  

2.delete释放的空间可以重复使用

3.new和delete可以分别在两个函数中使用, 但是要注意的是需要成对的使用

最后看一个多种类型混合使用的例子:

#include "iostream"
#include "cstring"
using namespace std;
 
struct my_year {
       int year;
};
 
int main() {
       // 声明了三个my_year结构体的变量
       my_year y1, y2, y3;
       y1.year = 1998;
       // 声明了一个my_year结构体指针, 并指向y2的首地址
       my_year* py2 = &y2;
       py2->year = 1999;
      
       // 声明了一个长度为3的my_year结构体数组
       my_year years[3];
       years[0].year = 2003;
      
       // 输出2003, 第一个元素的year
       cout << years->year << endl;
       // 声明了一个指针数组
       const my_year* parr[3] = {&y1, &y2, &y3};
      
       // 1999
       cout << parr[1]->year << endl;
       // 指向指针的指针
       const my_year** pparr = parr;
       const my_year** pparr2 = parr;
	   // 下面这种写法需要c++11才能编译通过
       // auto pparr2 = parr;
	   // 由于pparr是指向指针的指针, 所以*pparr还是指针, 因此需要用->来引用year
       cout << (*pparr)->year << endl;
	   // (*(pparr2 + 1)) 是一个指向了parr[1]的结构体的指针, 
	   // 因此(*(*(pparr2 + 1)))就是parr[1]这个指针指向的结构体了, 1999
       cout << (*(*(pparr2 + 1))).year << endl;   
       return 0;
}

看一下运行结果:

具体的代码解释, 看一下注释即可, 写的比较详细

接下来说一下C++里的自动存储, 静态存储和动态存储

1.自动存储

在函数内部定义的常规变量使用自动存储空间, 被称为自动变量(automatic variable), 也就是它们在所属的函数被调用的时候自动产生, 在该函数结束的时候消亡.

例如上上个demo中的getName()函数活动的时候temp被创建, 当getName执行完毕的时候释放.

自动变量通常存储在栈中, 这意味着执行代码块的时候, 其中的变量将以此加入到栈中, 而在离开代码块的时候, 将按相反的顺序释放这些变量(LIFO后进先出).

2.静态存储

静态存储是整个程序执行期间都存在的存储方式. 声明方式有两种:

一种是在函数外面定义,

另一种是在声明变量时使用关键字static如: static double fee = 1.23;

3.动态存储

new和delete运算符提供了一种比自动变量和静态变量更灵活的方法. 他们管理了一个内存池, 在c++中称为自由存储空间或者堆(heap). 该内存池同用于静态变量和自动变量的内存是分开的. 上上个demo表明, new和delete能让我们在一个函数中分配内存, 而在另一个函数中释放. 因此数据的生命周期不完全受程序或函数的生存时间控制. 需要注意delete否则可能导致内存泄漏的危险

注意在堆内存上使用new创建变量后, 要记得使用delete进行释放, 否则可能会造成内存泄漏

猜你喜欢

转载自blog.csdn.net/c1392851600/article/details/84311040