0. 前言
昨晚写一个单向链表的代码, 目的是新建几个节点, 然后串联起来, 代码如下:
class ListNode
{
public:
ListNode(int v):val(v){}
int val;
ListNode *next;
static void print_node_val (const ListNode* p_node){
while(p_node != nullptr){
cout << p_node->val;
p_node = p_node->next;
if(p_node){
cout << "->";
}
else{
cout << ";";
}
}
cout << endl;
}
};
int main(int argc, char *argv[])
{
//############################################//
//################ 创建链表 ####################//
//############################################//
ListNode l1(1);
ListNode l2(1);
ListNode l3(2);
l1.next = &l2;
l2.next = &l3;
return 0;
}
代码编译通过, 但是运行的时候出现段错误.
目测是出现了访问非法内存,
然后尝试打印一下地址:
cout << l1.next << endl;
cout << l2.next << endl;
cout << l3.next << endl;
得到:
0x7ffe1b26aee0
0x7ffe1b26aef0
0x55c8295af7f0
果然是初始化的问题, 类的指针没有被初始化为nullptr, 于是在类中的构造函数里加了初始化:
class ListNode
{
public:
ListNode(int v):val(v), next(nullptr){}
int val;
...
这样话打印就正常了,
0x7ffd0ae20d10
0x7ffd0ae20d20
0
类中的静态成员函数也可以正常使用了.
一开始没加的话, 因为最后的l3
在while(p_node != nullptr)
这里不会终止, 而是继续下去, 这样子访问到的内存就是非法的了. 因此会出现段错误.
以后在写构造函数的时候, 都把值给初始化掉吧!!!
1. 回顾一下基础
为了有个更系统的理解, 我写如下代码测试一下:
/*
* @Author: sanjayzhong
* @Github: https://github.com/sanjayzzzhong
* @Date: 2019-12-16 10:34:35
*/
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
#include <set>
using namespace std;
//############################################//
//################ 测试一下带有指针的类的初始化问题 ####################//
//############################################//
class Base{
public:
int a;
float b;
double c;
Base* next;
void print(){
cout << "print" << endl;
}
void get(){
cout << this->a << endl;
}
};
void test01(){
//############################################//
//################ 类内普通成员变量不会自动初始化, 给的是随机值 ####################//
//############################################//
Base b;
cout << b.a << endl;
cout << b.b << endl;
cout << b.c << endl;
cout << b.next << endl;
Base* c = b.next;
c->a;
cout << "=============================" << endl << endl;
//############################################//
//################ 用new来试试: new会自动将值初始化 ####################//
//############################################//
Base* new_b = new Base;
cout << new_b->a << endl;
cout << new_b->b << endl;
cout << new_b->c << endl;
cout << new_b->next << endl;
}
int main(int argc, char *argv[]){
test01();
return 0;
}
运行结果如下:
2
0
4.67372e-310
0x7fe46c7fe9a0
=============================
0
0
0
0
首先看=上面部分, 上面部分主要是通过栈内存来声明类, 打印出来的值都是随机值来的, next指针指向的也是随机地址, 不是nullptr;
=
下面部分, 可以看到, 通过new创建出来的类, 会默认给初始值, 指针也是给了nullptr(0)
同样, 在栈中申请内存的时候, 虽然编译器有时候会帮我们做优化, 但是更安全的是要自己给初始, 否者的话比较容易出错.
现在问题来了, 为什么new申请堆区的内存会自动帮我们初始化呢?
其实是编译器的原因, gcc/g++在new的时候做了优化.
更正:使用new
表达式的时候,new的流程是:
- 使用
operator new
申请内存; - 调用类的构造函数对这块内存进行初始化
用visual studio跑的时候, 上面两种情况都正常!
总结
类构造函数, 要自己把变量都给初始化, 不要依赖编译器!!!