抱歉这个冗长的标题。
class Student
{
public:
// Some routines
private:
string name;
int grade;
}
主要是:
Student* newStudent = NULL;
我知道NULL等同于零,但是现在name和grade是怎么设置的呢?当我这样做时:
cout << newStudent->getName();
它不返回 0 - 相反,Visual Studio 给了我某种错误。
所以我也想知道,newStudent 到底指的是什么?它只是消除了所有私有(private)数据,并将整个类指向 0 吗?
编辑:
好的,克里斯 - 我就是这么想的。我的后续问题是: 我如何在 getName 函数中检查这一点。
我不能像这样使用 bool,
if (name == 0)
// Return an error message.
那么有解决办法吗?
编辑: VS错误是: Ex8_3.exe 中 0x00FFAAA6 处的未处理异常:0xC0000005:访问冲突读取位置 0x00000014。
请注意,这实际上是一个更大程序的一部分,我只是隔离了问题部分。
编辑: 好的,这是导致问题的代码。我将只发布整个程序,因为它不是太大,而且我可以使用任何我能得到的建设性批评。
#include <iostream>
#include <string>
#include <vector>
using namespace std;
class Student
{
public:
// Accessor
string getName();
vector<string> getCourseList();
Student* getLink();
// Mutators
void setName (string aName);
void setCourses(vector<string> list);
void setLink (Student* aLink);
private:
string name;
vector<string> courseList;
Student* link;
};
// Linked-list Non-Member Functions.
typedef Student* NodePtr;
void head_insert (NodePtr& head);
NodePtr search (NodePtr head, string target);
NodePtr searchPrevious (NodePtr head, string target);
void deleteNode (NodePtr& head, string target);
void show_list (NodePtr& head);
void showFirstCourses (NodePtr& head);
int main()
{
NodePtr headPointer = NULL;
head_insert(headPointer);
headPointer->setName("Tim");
head_insert(headPointer);
headPointer->setName("Jan");
head_insert(headPointer);
headPointer->setName("Jim");
deleteNode(headPointer, "Tim");
NodePtr test1 = NULL;
head_insert(test1); // This is where the new Student is created.
test1 = search (headPointer, "Jon"); // Still experiencing a problem between here and the next instruction.
cout << test1->getName(); // Something is wrong if this == NULL.
system("pause");
return 0;
}
string Student::getName()
{
return name;
}
vector<string> Student::getCourseList()
{
return courseList;
}
Student* Student::getLink()
{
return link;
}
void Student::setName (string aName)
{
name = aName;
}
void Student::setCourses(vector<string> list)
{
courseList = list;
}
void Student::setLink (Student* aLink)
{
link = aLink;
}
void head_insert (NodePtr& head)
{
NodePtr temp_ptr;
temp_ptr = new Student;
temp_ptr->setLink(head); // Link this to what the head is linking to.
head = temp_ptr; // Use this node as the new head.
}
NodePtr search (NodePtr head, string target) // Needs to be tested, to see if getLink is working correctly.
{
// Point to the head node
NodePtr here = head;
// If the list is empty nothing to search
if (here == NULL)
{
return NULL;
}
// Search for the item
else
{
// while you have still items and you haven't found the target yet
while (here->getName() != target && here->getLink() != NULL)
here = here->getLink();
// Found the target, return the pointer at that location
if (here->getName() == target)
return here;
// Search unsuccessful, return Null
else
return NULL;
}
}
NodePtr searchPrevious (NodePtr head, string target) // This function needs to be checked for the same things the above function does.
{
// Point to the head node
NodePtr here = head;
// If the list is empty nothing to search
if (here == NULL)
{
return NULL;
}
// Search for the item
else
{
// while you still have items and you haven't found the target yet
while (here->getName() !=target && (here->getLink())->getName() != target && (here->getLink())->getLink() != NULL)
here = here->getLink();
// Found the target, return the pointer at that location
if (((here->getLink())->getName() == target) || (here->getName() == target))
{
return here;
}
// Search unsuccessful, return Null
else
return NULL;
}
}
void deleteNode (NodePtr& head, string target)
{
NodePtr toBeDeleted = search (head, target);
NodePtr previousPointer = searchPrevious (head, target);
// Make sure the desired value is in the list.
if (toBeDeleted == NULL)
{
cout << target << " is not in the list, so it can't be deleted.\n";
return;
}
// Test to see if we are removing the first node.
if (previousPointer == toBeDeleted)
{
head = toBeDeleted->getLink();
delete toBeDeleted;
return;
}
// Connect the node from before to after.
previousPointer->setLink(toBeDeleted->getLink());
delete toBeDeleted;
}
最佳答案
不要将指向 NULL 的指针上的 name
和 grade
视为设置为某物。当 Student *
指针设置为 NULL 时,它什么也没有指向。就好像你指着房间里的一 block 空地,问我你指的那个人叫什么名字。
你不能解引用一个 NULL 指针,所以这样做:
Student *s = NULL;
s->name;
是未定义的行为。什么事情都可能发生;最有可能的是,你会遇到段错误。 (但这是一个实现细节,并不能保证。)
您可以检查空值,只需:
if(s) {
// s isn't NULL.
}
(您也可以使用 if(s != NULL)
或 if(s != nullptr)
。)
现在我们已经有了您的代码,让我们看看这个案例:
test1 = search (headPointer, "Jon"); // Still experiencing a problem between here and the next instruction.
cout << test1->getName(); // Something is wrong if this == NULL.
这里的问题是第二行:在搜索失败的情况下,你为什么期望能够输出学生的姓名?我们还没有找到学生!我们需要解决没有学生的问题:
test1 = search(headPointer, "Jon");
if(test1) {
cout << "Found student; his name is " << test1->getName() << endl;
} else {
cout << "Couldn't find that student." << endl;
}
同样,我们这里有一些错误的逻辑:
while (here->getName() != target && here->getLink() != NULL)
here = here->getLink();
假设 here->getLink()
在我们到达此列表末尾的不可避免的情况下返回 NULL。 while
(here->getName()
) 中的条件现在解除对无效 (NULL) 指针的引用。让我们显着重构整个函数:
NodePtr search (NodePtr head, string target) {
// Where in the list we are:
NodePtr here = head;
// Check that head points at a student:
while(here != NULL) {
// Check if this is the student we are searching for:
if(here->getName() == target) {
// It is. Great! Return him/her:
return head;
}
}
return NULL;
}
请注意,除非您需要实现链表,否则 STL(标准模板库)有几个列表容器:std::list
和 std::vector
是两个包含对象列表的容器。它们具有不同的性能特征,您需要在这些特征之间做出选择,但它们比重新发明一个链表更容易使用。
最后一件事:
OK I can take that solution, I was just thinking there might be a more elegant solution - like including this check in the getName function if possible. The reason being, is that I would have to include the check you described above every time I call getName.
让我们谈谈getName
。 如果我们在该函数中允许一个 NULL 学生,我们该怎么办?因为我们无法得到我们没有的学生的名字……很难说。我们会输出错误吗?引发异常?杀死程序?
在成员函数中,期望您正在操作的对象存在通常是公平的游戏。如果不是,则说明调用方在 NULL 指针上执行 ->getName()
时存在错误。同样,在普通函数中,我们可以取一个引用:
void do_something_with_a_student(Student &s)
引用不应该为 NULL,因此允许此函数假定它始终有一个有效的学生。您唯一需要担心的地方是“我有一个有效的学生吗?”是逻辑上应该引起关注的地方,例如刚刚搜索过学生。如果我在类(class)花名册中搜索“Billy”,我可能有也可能没有这样的学生:在这里,我们需要“不存在”的值; NULL 对此很有用。
即使您采用指针,您也始终可以记录(可能带有注释)该函数仅允许非 NULL 指针。这在缺少引用的 C 中更常见;在 C++ 中,引用是更好的选择。
关于c++ - 将对象指向 NULL 会将成员值置于什么位置?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22586323/