简体   繁体   English

在 C++ 中设置指向 null 的结构指针时,存储的值消失

[英]Stored value disappears when setting a struct pointer to null in C++

I'm writing a C++ application to do a word search across a large database of song lyrics.我正在编写一个 C++ 应用程序来对大型歌词数据库进行单词搜索。 to start, I'm taking each word and putting it into a Word struct that looks like this:首先,我将每个单词放入一个 Word 结构中,如下所示:

struct Word{
    char* clean;
    int size;
    int position;
    SongId id;
    Word* same;
    Word* diff;
};

I have a "makeNode" function that does the following:我有一个“makeNode”function,它执行以下操作:

  1. takes in each word接受每个单词
  2. creates a new Word struct and adds the word to it创建一个新的 Word 结构并将单词添加到其中
  3. creates a Word* called node which points to the new word创建一个名为 node 的 Word* 指向新单词
  4. stores the pointer in a hash table.将指针存储在 hash 表中。

In my makeNode function, I set node->clean to my "clean" word.在我的 makeNode function 中,我将 node->clean 设置为我的“干净”字。 I can print the word by cout'ing node->clean.我可以通过 cout'ing node->clean 来打印这个词。 But when I set node->same to NULL, I lose node->clean.但是当我将 node->same 设置为 NULL 时,我失去了 node->clean。 I don't lose node->position or node->size.我不会丢失节点-> 位置或节点-> 大小。 If I remove the line where I assign node->same to to NULL, I do not lose node->clean.如果我删除将 node->same 分配给 NULL 的行,我不会丢失 node->clean。

char* clean = cleanse(word);
Word* node = new Word;
node->size = strlen(word);
node->clean = clean;
cout<<"MADE NODE FOR "<<node->clean<<endl;
node->position = position;
cout<<"4 node clean: "<<node->clean<<endl;
node->id = id;
cout<<"5 node clean: "<<node->clean<<endl;
node->same = NULL;
cout<<"6 node clean: "<<node->clean<<endl;
cout<<"node position: "<<node->position<<endl;
cout<<"node size: "<<node->size<<endl;
node->diff = NULL;

yields the following output:产生以下 output:

MADE NODE FOR again
4 node clean: again
5 node clean: again
6 node clean:
node position: 1739
node size: 6
0 node clean:
1 node clean:
3 node clean: 

Can anyone help me get past this error?谁能帮我克服这个错误? If you need more info, let me know.如果您需要更多信息,请告诉我。 Thanks in advance!提前致谢!

EDIT: here is the cleanse function.编辑:这是清洁 function。

char* SongSearch::cleanse(char* dirty)
{

string clean;
int iter = 0;
while (!isalnum(dirty[iter]))
{
    iter++;
}
while(dirty[iter]!='\0')
{
    clean += dirty[iter];
    iter++;
}

int backiter = clean.length() - 1;
while(!isalnum(clean[backiter]))
{
    clean.erase(backiter, 1);
    backiter--;
}


char c;
  for (int i = 0; i<clean.length(); i++)
{
    c = tolower(clean[i]);
    clean[i] = c;
}

char* toReturn = (char*)(clean.c_str());
return toReturn;
}

You need to reduce your code to a minimal example which displays the problem, and post that.您需要将代码简化为显示问题的最小示例,然后发布。

The following code fails to display the problem.以下代码无法显示问题。 The contents of main and the definition of Word are copied from your code, then I have added code as necessary to get it to compile: main的内容和Word的定义是从您的代码中复制的,然后我根据需要添加了代码以使其编译:

#include <iostream>
#include <cstring>
using namespace std;

typedef int SongId;

struct Word{
    char* clean;
    int size;
    int position;
    SongId id;
    Word* same;
    Word* diff;
};

char *cleanse(const char *w) {
    return (char *)w;
}
const char *word = "again ";
const int position = 1739;
const int id = 0;

int main() {
    char* clean = cleanse(word);
    Word* node = new Word;
    node->size = strlen(word);
    node->clean = clean;
    cout<<"MADE NODE FOR "<<node->clean<<endl;
    node->position = position;
    cout<<"4 node clean: "<<node->clean<<endl;
    node->id = id;
    cout<<"5 node clean: "<<node->clean<<endl;
    node->same = NULL;
    cout<<"6 node clean: "<<node->clean<<endl;
    cout<<"node position: "<<node->position<<endl;
    cout<<"node size: "<<node->size<<endl;
    node->diff = NULL;
}

Output is: Output 是:

MADE NODE FOR again 
4 node clean: again 
5 node clean: again 
6 node clean: again 
node position: 1739
node size: 6

The problem is probably that in cleanse , you return clean.c_str() .问题可能是在cleanse中,您返回clean.c_str()

That pointer value ceases to be valid when clean ceases to exist, which is when the function exits.clean不再存在时,该指针值不再有效,即 function 退出时。 It is no longer guaranteed to point to anything, so it's pure luck that you're ever seeing the string "again" as expected.它不再保证指向任何东西,所以你能按预期“再次”看到字符串是纯粹的运气。

What I suspect happens is that the memory that used to be occupied by the data for the string clean in cleanse , has been re-used for the structure word , but is not immediately overwritten.我怀疑发生的情况是,memory曾经cleanse中的字符串clean的数据占用,已被重新用于结构word ,但不会立即被覆盖。 It just so happens that the byte that used to hold the first a now holds part of the same member of your struct.碰巧的是,曾经保存第一个a的字节现在保存了结构的same成员的一部分。 So, when you write a null pointer to node->same , it has the effect of writing a 0 byte to the location pointed to by node->clean .因此,当您将 null 指针写入node->same时,它具有将 0 字节写入node->clean指向的位置的效果。 Thereafter, it appears to point to an empty string.此后,它似乎指向一个空字符串。

Okay, we'd need to actually see the code for some of these to be sure, but here's what the bug is telling you: at some point, you're assigning to something that overwrites or deletes your clean.好的,我们需要实际查看其中一些代码才能确定,但这就是错误告诉您的内容:在某些时候,您正在分配的东西会覆盖或删除您的清理。 Since y,ou declare it as a char *, I'm guessing you use it as a pointer to an array of characters, and the odds are good that one array is being aliased to two "clean" pointers in two different Words.由于 y,ou 将其声明为 char *,我猜您将其用作指向字符数组的指针,并且一个数组被别名为两个不同单词中的两个“干净”指针的可能性很大。

Aside from new and cout this might as well be C.除了 new 和 cout 这也可能是 C。

Some other reading其他一些读物
What are the differences between struct and class in C++? C++中的struct和class有什么区别?
char * Vs std::string char * 与 std::string
Remove spaces from std::string in C++ 从 C++ 中的 std::string 中删除空格
tolower function for C++ strings 降低 function 用于 C++ 字符串
How can I negate a functor in C++ (STL)? 如何否定 C++ (STL) 中的函子?

Try the following alternative (uncompiled sample)尝试以下替代方法(未编译的示例)

#include <iostream>
#include <string>
#include <algorithm>
#include <functional>

typedef int SongId;

class Word{
    int position;
    SongId id;
    Word* same;
    Word* diff;

public: 
  const std::string word;

  const int size() const { return clean.length() };

  Word( const std::string& word_, const int position_ = 1739, const int id_ = 0 )
    : clean( cleanse(word_) )
    , position( position_ )
    , id( id_ )
    , same( NULL )
    , diff( NULL )
  {
    cout<<"MADE NODE FOR "<< word_ << "\n"
      <<"node clean: "<< word << "\n"
      <<"node position: "<< position << "\n";
      <<"node size: "<< size() << endl;
  }

  static std::string cleanse( const std::string& dirty)
  {
    string clean( dirty );

// Remove anything thats not alpha num
    clean.erase(remove_if(clean.begin(), clean.end(), std::not1(::isalnum) ), clean.end());
// make it lower case
    std::transform( clean.begin(), clean.end(), clean.begin(), ::tolower);  // or boost::to_lower(str);

    return clean;
  }
};

const char *word = "again ";

int main() {
    Word* node = new Word(word);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM