我需要用类创建一个链表。每个列表将存储两个值:URI和IP。完成所有添加后,我需要能够计算链表中的项目总数。我尝试了以下代码,但它没有编译。我们不允许使用std :: list。有什么建议吗?
#include <iostream>
#include <cstdlib>
#include <string>
using namespace std;
class ip_uri_store {
protected:
string ip;
string uri;
ip_uri_store *next;
public:
ip_uri_store(string huri, string hip);
void additem(string auri, string aip);
void deleteitem(string duri);
void findbyuri(string furi);
void findbyip(string fip);
int totalitems();
};
ip_uri_store *head = NULL;
ip_uri_store *curr = NULL;
void ip_uri_store::additem(string auri, string aip)
{
curr = head;
while (curr->next != NULL) {
curr = curr->next;
}
curr->uri = auri;
curr->next = new ip_uri_store;
curr->ip = aip;
curr->next = new ip_uri_store;
curr = curr->next;
curr = head;
}
int ip_uri_store::totalitems()
{
int i = 0;
curr = head;
while (curr->next != NULL) {
i += 1;
curr = curr->next;
}
return i;
}
int main(int argc, char *argv[])
{
if (argc == 1) {
cout << "123456, 123456@student.rmit.edu.au, Gordon Brown" << endl;
return (0);
}
head = new ip_uri_store;
curr = head;
int i;
for (i = 1; i < argc; i++) {
if (argv[i][0] == 'A') //add item
{
ip_uri_store.additem(argv[i + 1], argv[i + 2]);
i += 2;
}
else if (argv[i][0] == 'N') //print total tiems
{
cout << ip_uri_store.totalitems() << endl;
}
else {
cout << "command error\n";
return 0;
}
}
return (0);
}
答案 0 :(得分:1)
你的ip_uri_store::additem()
非常混乱。在其中,您可以在为其指定新值之前更改curr
对象:
curr->uri = auri;
curr->next = new ip_uri_store;
这样做可以更改列表中的最后一项,而不是将auri
分配给稍后添加的新项目。 (有趣的是,您通过ip
得到了正确的订单。)
我喜欢提供代码名称的想法,以便您可以阅读他们所做的事情。功能就是这样做的。例如,我将找出找到最后一个列表节点的代码
ip_uri_store *find_last_node(ip_uri_store *curr)
{
while (curr->next != NULL) {
curr = curr->next;
}
return curr;
}
并从ip_uri_store::additem()
:
void ip_uri_store::additem(string auri, string aip)
{
ip_uri_store *curr = find_last_node(head);
// ...
现在创建一个新对象并记住其在curr->next
// ...
curr->next = new ip_uri_store(auri,aip);
}
您的ip_uri_store::totalitems()
会返回int
。为什么?你有没有期望对象的数量是负数?最好返回无符号类型。
您应该考虑删除列表节点时会发生什么。如果它仍指向next
对象,则指针可能不存储在其他任何位置,因此对象(以及它指向的对象)正在泄漏。解决这个问题的一种方法是为ip_uri_store
编写一个删除next
的析构函数。 (如果要在不删除节点的情况下删除节点,可以先将NULL
指定给其next
指针。)
此外,根据Rule of Three,您需要考虑复制列表节点。在第一次尝试中做到这一点并不容易,所以你可能只想禁止它:
class ip_uri_store {
private:
ip_uri_store(const ip_uri_store&); // not implemented
ip_uri_store& operator=(const ip_uri_store&); // not implemented
// ...
您可以将它们放入类中,而不是使用全局变量。这样你就可以拥有多个列表。将ip_uri_store
重命名为ip_uri_store_impl
并将其重命名为新的ip_uri_store
类:
class ip_uri_store {
private:
class ip_uri_store_impl { /* ... */ };
ip_uri_store_impl* head;
};
由于此类管理动态分配的对象,因此您需要考虑销毁和复制此类对象。
包装器类应该有公共方法,可以调用ip_uri_store_impl
的方法。像totalitems()
这样在整个列表(而不是节点)上运行的函数应该可以在包装类中实现。
答案 1 :(得分:0)
您需要为ip_uri_store
类的构造函数提供两个参数:
// The constructor call needs two arguments
curr->next = new ip_uri_store(huri, hip);
您无法在类本身上调用实例方法:
// Invalid, totalitems() is valid only on instances of ip_uri_store.
cout << ip_uri_store.totalitems() << endl;
为什么变量head
和curr
是全局的?他们确实应该是班级的数据成员。
拉出ip
的{{1}},uri
和next
成员,并将它们放在自己的结构中,比如ip_uri_store
。然后,ip_uri_store_node
可以定义初始化它们的构造函数。然后让ip_ur_store_node
按住ip_uri_store
和head
个curr
个实例。
这就是我的意思:
ip_uri_store_node
函数struct ip_uri_store_node
{
string ip;
string uri;
ip_uri_store_node* next;
ip_uri_store_node(const char* u, const char* i)
: ip(i), uri(u), next(0) {}
};
class ip_uri_store
{
private:
ip_uri_store_node* head;
ip_uri_store_node* curr;
public:
// Initializes head and curr
ip_uri_store();
// These functions woud act on head and curr.
void additem(string auri, string aip);
void deleteitem(string duri);
void findbyuri(string furi);
void findbyip(string fip);
int totalitems();
};
int main()
{
ip_uri_store list;
// Do things with the list...
return 0;
}
可以像这样创建additem
的新实例:
ip_uri_store_node
其余由你决定。