一直在工作中对指针和内存分配搞不太清楚。模模糊糊。现在看下今天犯下的一个错误:
方程为
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 void RouteSerializer::setupChildNode(xml_node<> *childnode, std ::string childname, xml_node<> *fathernode, std ::vector <std ::pair<std ::string , std ::string >> attri, std ::string content){ char *contentc; if (content.empty()) { contentc = NULL ; } else { contentc = m_doc.allocate_string(content.c_str()); } char *childnamec = m_doc.allocate_string(childname.c_str()); childnode = m_doc.allocate_node(node_element, childnamec, contentc); for (int i = 0 ; i < attri.size(); i++) { char *keyc = m_doc.allocate_string(attri[i].first.c_str()); char *valuec = m_doc.allocate_string(attri[i].second.c_str()); childnode->append_attribute(m_doc.allocate_attribute(keyc, valuec)); } fathernode->append_node(childnode); }
其中在方程中为这个指针分配了内存空间,出现的问题是调用一次该方程没问题,但是连续调用两次该方程,程序崩溃。
1 childnode = m_doc.allocate_node(node_element, childnamec, contentc);
原因在于,我们查看原代码可以发现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 xml_node<Ch> *allocate_node(node_type type, const Ch *name = 0 , const Ch *value = 0 , std ::size_t name_size = 0 , std ::size_t value_size = 0 ) { void *memory = allocate_aligned(sizeof (xml_node<Ch>)); xml_node<Ch> *node = new (memory) xml_node<Ch>(type); if (name) { if (name_size > 0 ) node->name(name, name_size); else node->name(name); } if (value) { if (value_size > 0 ) node->value(value, value_size); else node->value(value); } return node; }
源代码在这里申请了内存。我后面还没试我的想法对不对,但是当我读到了一句话如果函数的参数是一个指针,不要指望用该指针去申请动态内存 .如下
1 2 3 4 5 6 7 8 void GetMemory (char *p, int num) { p = (char *)malloc (sizeof (char ) * num); } void Test (void ) { char *str = NULL ; GetMemory(str, 100 ); strcpy (str, "hello" ); }
毛病出在函数GetMemory中。编译器总是要为函数的每个参数制作临时副本,指针参数p的副本是 _p,编译器使 _p=p。如果函数体内的程序修改了_p的内容,就导致参数p的内容作相应的修改。这就是指针可以用作输出参数的原因。在本例中,_p申请了新的内存,只是把 _p所指的内存地址改变了,但是p丝毫未变。所以函数GetMemory并不能输出任何东西。事实上,每执行一次GetMemory就会泄露一块内存,因为没有用free释放内存。
还有就是对于指针来说无疑就是几个方式,作为参数放到方程里面,作为返回值。作为参数说了,不能在方程中给他赋值。作为返回值,要看指针指向的地方,加入你指向栈,出了函数域你就自动释放了。所以返回的指针必须要new一个内存块。
刚才试了一下 新建, 地址为0, 说明建的时候是不会有地址的,有值了才会有地址。
1 2 3 4 5 6 7 8 9 10 11 #include <iostream> #include <string> #include <memory> int main () { int *p; std ::cout <<"dizhi " <<p; }
如果是传递指针,那么会先复制该指针,在函数内部使用的是复制后的指针,这个指针与原来的指针指向相同的地址,如果在函数内部将复制后的指针指向了另外的新的对象,那么不会影响原有的指针;
但 是对于传递指针应用,如果将传递进来的指针指向了新的对象,那么原始的指针也就指向了新的对象,这样就会造成内存泄漏,因为原来指针指向的地方已经不能再 引用了,即使没有将传递进来的指针指向新的对象,而是在函数结束的时候释放了指针,那么在函数外部就不能再使用原有的指针了,因为原来的内存已经被释放了.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 #include <cstdlib> #include <cstring> #include <memory> #include <iostream> using namespace std ; void func2 (char *str) { str = (char *)malloc (10 ); strcpy (str, "hello" ); } void func3 (char *&str) { str = (char *)malloc (10 ); strcpy (str, "hello" ); } int main () { char *str = "1234567890" ; func2(str); cout << str << endl ; func3(str); cout << str << endl ;
简单一点可以这么想,如果不用引用的话,被传递的参数本身是不能被修改的,
即使你传递的是指针,也不过能修改指针指向的内容,不能修改指针本身。
如果要修改当前被传递的参数的话,要么再加一级指针,要么用引用。
指针的引用类似于二级指针
传递指针的话,在函数体内你只能修改指针的内容,不能改变指针本身(非const type *类型,指针本身也能修改的,只是这个修改,不会影响到实参指针)
传递指针的引用,在函数体内,你既可以修改指针的内容,也可以修改指针本身(实参)
有区别,
无论你传值还是传指针,函数都会生成一个临时变量, 但传引用时,不会生成临时变量, 当你传值时,只可以引用值而不可以改变值,但传值引用时,可以改变值, 当你传指针时,只可以改变指针所指的内容,不可以改变指针本身,但传指针引用时,即可以改变指针所指的内容,又可以改变指针本身,但传引用主要是它不生成临时变量,不进行返回值copy等,速度快。