如下示例程序所示, 首先构建了一个如下所示的Node树,每个节点存有一个数字。程序需要通过node的name返回其数字,即findNodeNumByName,其中name是const char*,表示方法中不会修改其参数。另外这个参数来自于另外一个方法,即findNodeNameByNum,输入数字找到对应的node的name。所以正确的程序输出应该为输入1,输出1,输入2,输出2,输出与输入相同。

1

<span style="color:#333333"><span style="background-color:#ffffff"><code class="language-c language-c++"><span style="color:#2b91af">#<span style="color:#0000ff">include</span><span style="color:#3388aa"><iostream></span></span>
<span style="color:#2b91af">#<span style="color:#0000ff">include</span><span style="color:#3388aa"><string></span></span>
<span style="color:#2b91af">#<span style="color:#0000ff">include</span><span style="color:#3388aa"><vector></span></span>

<span style="color:#0000ff">class</span> <span style="color:#a31515">Node</span>
{
public:
	Node(<span style="color:#0000ff">std</span>::<span style="color:#0000ff">string</span> s, <span style="color:#a31515">int</span> n)
	{
		name = (<span style="color:#a31515">char</span>*)<span style="color:#0000ff">malloc</span>(<span style="color:#880000">10</span>);
		strcpy_s(name, <span style="color:#880000">10</span>, s.c_str());
		num = n;
	}
	<span style="color:#0000ff">std</span>::<span style="color:#0000ff">string</span> <span style="color:#a31515">GetName</span>() {<span style="color:#0000ff">return</span> name;}

	<span style="color:#a31515">const</span> <span style="color:#a31515">char</span>* <span style="color:#a31515">GetNameCstr</span>() {<span style="color:#0000ff">return</span> name;}

	<span style="color:#a31515">int</span> <span style="color:#a31515">GetNum</span>() { <span style="color:#0000ff">return</span> num; }

	<span style="color:#0000ff">std</span>::<span style="color:#0000ff">vector</span><Node*> <span style="color:#a31515">GetChildNodes</span>() {<span style="color:#0000ff">return</span> childNodes;}

	<span style="color:#a31515">char</span>* name;
	<span style="color:#a31515">int</span> num;
	<span style="color:#0000ff">std</span>::<span style="color:#0000ff">vector</span><Node*> childNodes;
};

Node* A, * B, * C, * D, * E, * F, * G, * H;
<span style="color:#a31515">void</span> <span style="color:#a31515">initializeNodes</span>()
{
	A = new Node(<span style="color:#a31515">"A"</span>, <span style="color:#880000">0</span>);
	B = new Node(<span style="color:#a31515">"B"</span>, <span style="color:#880000">1</span>);
	C = new Node(<span style="color:#a31515">"C"</span>, <span style="color:#880000">2</span>);
	D = new Node(<span style="color:#a31515">"D"</span>, <span style="color:#880000">3</span>);
	E = new Node(<span style="color:#a31515">"E"</span>, <span style="color:#880000">4</span>);
	F = new Node(<span style="color:#a31515">"F"</span>, <span style="color:#880000">5</span>);
	G = new Node(<span style="color:#a31515">"G"</span>, <span style="color:#880000">6</span>);
	H = new Node(<span style="color:#a31515">"H"</span>, <span style="color:#880000">7</span>);

	A->childNodes.push_back(B);
	A->childNodes.push_back(C);
	B->childNodes.push_back(D);
	B->childNodes.push_back(E);
	B->childNodes.push_back(F);
	C->childNodes.push_back(G);
	E->childNodes.push_back(H);
}

<span style="color:#a31515">const</span> <span style="color:#a31515">char</span>* <span style="color:#a31515">findNodeNameByNum</span>(Node* node, <span style="color:#a31515">int</span> num)
{
	<span style="color:#a31515">const</span> <span style="color:#a31515">char</span>* n = node->GetName().c_str();
	<span style="color:#0000ff">if</span> (node->GetNum() == num)
		<span style="color:#0000ff">return</span> n;
	<span style="color:#0000ff">for</span> (<span style="color:#0000ff">auto</span>* n : node->GetChildNodes())
	{
		<span style="color:#a31515">const</span> <span style="color:#a31515">char</span>* result = findNodeNameByNum(n, num);
		<span style="color:#0000ff">if</span> (result != nullptr)
			<span style="color:#0000ff">return</span> result;
	}

	<span style="color:#0000ff">return</span> nullptr;
}

<span style="color:#a31515">int</span> <span style="color:#a31515">findNodeNumByName</span>(Node* node, <span style="color:#a31515">const</span> <span style="color:#a31515">char</span>* name)
{
	<span style="color:#008000">//std::cout << name << ":" << (void*)name << std::endl;</span>
	<span style="color:#0000ff">if</span> (<span style="color:#0000ff">strcmp</span>(node->GetName().c_str(), name) == <span style="color:#880000">0</span>)
		<span style="color:#0000ff">return</span> node->num;

	<span style="color:#0000ff">for</span> (<span style="color:#0000ff">auto</span>* n : node->GetChildNodes())
	{
		<span style="color:#a31515">int</span> result = findNodeNumByName(n, name);
		<span style="color:#0000ff">if</span> (result != <span style="color:#880000">-1</span>)
			<span style="color:#0000ff">return</span> result;
	}

	<span style="color:#0000ff">return</span> <span style="color:#880000">-1</span>;
}

<span style="color:#a31515">int</span> <span style="color:#a31515">main</span>()
{
	initializeNodes();
	<span style="color:#0000ff">std</span>::<span style="color:#0000ff">cout</span> << <span style="color:#a31515">"Please input number you want to find:"</span> << <span style="color:#0000ff">std</span>::<span style="color:#0000ff">endl</span>;
	<span style="color:#a31515">int</span> n;
	<span style="color:#0000ff">while</span> (<span style="color:#0000ff">std</span>::<span style="color:#0000ff">cin</span>>> n)
	{
		<span style="color:#0000ff">if</span> (n<<span style="color:#880000">0</span>||n><span style="color:#880000">7</span>) <span style="color:#0000ff">break</span>;
		<span style="color:#a31515">const</span> <span style="color:#a31515">char</span>* name = findNodeNameByNum(A, n);
		<span style="color:#0000ff">std</span>::<span style="color:#0000ff">cout</span> << <span style="color:#a31515">"find: "</span> << findNodeNumByName(A, name) << <span style="color:#0000ff">std</span>::<span style="color:#0000ff">endl</span>;
	}
	
	<span style="color:#0000ff">return</span> <span style="color:#880000">0</span>;
}

</code></span></span>

输出结果

result

分析

看结果发现,0,1,3,7正确,2,4,5,6错误,并都返回了3. 单单看findNodeNumByName方法基本没有问题,传入的name为const char*, 理论上不应该在方法中被修改。程序中的bug也不难发现,这个const char*来源于findNodeNameByNum,而这个指针为悬空指针,所以传入findNodeNumByName中的值应为空,为什么还会有值返回?

  • 将node类成员函数GetName()返回值改为DebugString,而DebugString继承std::string,区别只是构造/析构时候返回内部成员c_str的地址。
<span style="color:#333333"><span style="background-color:#ffffff"><code class="language-c language-c++"><span style="color:#0000ff">struct</span> <span style="color:#a31515">DebugString</span> : public <span style="color:#0000ff">std</span>::<span style="color:#0000ff">string</span> {
	DebugString(<span style="color:#a31515">const</span> <span style="color:#a31515">char</span>* s) : <span style="color:#0000ff">std</span>::<span style="color:#0000ff">string</span>(s) {
		<span style="color:#0000ff">std</span>::<span style="color:#0000ff">cout</span> << <span style="color:#a31515">"Constructed: "</span> << c_str() << <span style="color:#a31515">":"</span> << (<span style="color:#a31515">void</span>*)c_str() << <span style="color:#a31515">"\n"</span>;
	}
	~DebugString() {
		<span style="color:#0000ff">std</span>::<span style="color:#0000ff">cout</span> << <span style="color:#a31515">"Destroyed: "</span> << c_str() << <span style="color:#a31515">"\n"</span>;
	}
};

<span style="color:#0000ff">class</span> <span style="color:#a31515">Node</span>
{
	.....
	DebugString <span style="color:#a31515">GetName</span>() {<span style="color:#0000ff">return</span> name;}
	.....
}
</code></span></span>

以0为例发现,第一次findNodeNameByNum,找到A节点名字的临时指针为FA50,然后析构后为空,传入findNodeNumByName,函数中首先对A节点查找name,并再次在FA50地址中赋值,所以判断为相等,返回相应的值。

0

再以6为例发现, D/E/G 构造的地址都相同,都为FAC0;B,C构造的地址相同,都为FB70;所以当传入的是6,为G的地址,在第二次循环的时候,D/E/G还在原来的地址上构造,导致先返回D的地址为3.

6

同理,传入的是B,C的值,先返回的都是B的值,如下图所示

2

更多推荐