【问题标题】:Question with bad access issue (code enclosed below)访问不正确的问题(代码如下)
【发布时间】:2020-05-02 18:33:55
【问题描述】:

您好,如果没有正确询问,请原谅我,但我的代码有问题。这是学校的作业,但我正在寻求帮助以理解问题而不是答案,因此我们将不胜感激。

我将附上下面的代码,运行它会给我一个我不明白的错误。我昨天和老师谈过了,他指出了我解决的问题,但它没有再次出现。

虽然我的代码中可能有更多错误,但我想先了解错误的访问错误。任何帮助将不胜感激。

请告诉我将来如何更好地发布问题。

错误线程 1:EXC_BAD_ACCESS(代码=1,地址=0x0):

#include <iostream>
#include <fstream>
#include <string>
#include <vector>
using namespace std;

vector<string> getVector(const string&);
string getName(const string&);
void selectionSort(vector<string>&);
bool search(const string&, const vector<string>&);
void displayResult(const string&, const string&, bool);
void writeToFile(const string&, const vector<string>&);
void reverseVector(vector<string>&);

int main()
{
    string boyName, girlName;
    bool boyNameFound, girlNameFound;


    vector<string> boyNames(getVector("BoyNames.txt"));
    vector<string> girlNames(getVector("GirlNames.txt"));


    boyName = getName("boy's");
    girlName = getName("girl's");

    selectionSort(boyNames);
    selectionSort(girlNames);

    boyNameFound = search(boyName, boyNames);
    girlNameFound = search(girlName, girlNames);

    displayResult("boy's", boyName, boyNameFound);
    displayResult("girl's", girlName, girlNameFound);

    writeToFile("Boynames_asc.txt", boyNames);
    writeToFile("Girlnames_asc.txt", girlNames);

    reverseVector(boyNames);
    reverseVector(girlNames);

    writeToFile("Boynames_desc.txt", boyNames);
    writeToFile("Girlnames_desc.txt", girlNames);

    cout<<endl;

    system("PAUSE");
    return 0;
}


void selectionSort(vector<string> &arr)
{

    int startScan, minIndex;
    string minValue;

    for (startScan = 0; startScan < (arr.size() - 1); startScan++)
    {
        minIndex = startScan;
        minValue = arr[startScan];
        for(int index = startScan + 1; index < arr.size(); index++)
        {
            if (arr[index] < minValue)
            {
                minValue = arr[index];
                minIndex = index;
            }
        }
        arr[minIndex] = arr[startScan];
        arr[startScan] = minValue;
    }


}// above is code the teacher provided
// below is where I have written code for the assignment
 vector<string> getVector(const string& fileName)
{
    string name;
    ifstream file;
    vector<string> namesFromFile;
    file.open(fileName);
    while(getline(file, name))
    {
        namesFromFile.push_back(name);
    }
    return namesFromFile;
}

string getName(const string& gender)
{
    string nameChoice;

    cout << "Enter a " << gender << " name, or N if you do not wish to enter a " << gender << " name: " << endl;
    getline(cin, nameChoice);

    return nameChoice;
}

bool search(const string& nameChoice, const vector<string>& names)
{


    for(int i = 0; i < names.size(); i++)
    {
        if(nameChoice == names.at(i)) // names[i]
        {

            return true;

        }

    }
    return false;
}

void displayResult(const string& gender, const string& names, bool nameFound)// change this function so either displays name found not found or chose //not to enter
{
    if(nameFound)
    {
       cout << names << "is one of the most popular " << gender << "names." << endl;
    }
    else if(!nameFound)
        cout << names << " is NOT one of the most popular " << gender << " names." << endl;

    else if(names == "N")
    {
        cout << "You chose not to enter a " << gender << " name." << endl;
    }

}

void writeToFile(const string& fileName, const vector<string>& names)
{

    ofstream outputFile;
    outputFile.open(fileName);
    for(int i = 0; i < names.size(); i++)
    {
        outputFile << names[i] << endl;

    }
}

void reverseVector(vector<string>& names) 
{
    string temp = 0;
    for(int i = 0; i < names.size(); i++)
    {
        temp = names[0];
        names[0] = names[names.size() - i];
        names[names.size() - i] = temp;
    }



}

【问题讨论】:

  • 在您的代码中某处您正在取消引用一个空指针。你试过调试吗?
  • selectionSort 中,您使用无效索引访问 arr,第一个 0 为空。使用迭代器怎么样?向量的大小是 unsigned 所以 0u-1u 不是 -1 所以 startScan &lt; (arr.size() - 1)arr 为空 时为真
  • in reverseVector 在第一轮 i 是 0 所以你访问names[names.size()]; withis out of the array,即使你从索引开始1 如果数组的大小至少为 4,则不要反转数组
  • @AlanBirtles 我没有尝试调试,我们还没有完成调试,所以我必须先自我教育。我知道我可以逐步完成该程序,但我只是不知道该怎么做,除非我将所有内容都注释掉并一次将其带入一个函数中。
  • @bruno 老师写了选择排序函数,所以我没有更改它,我只是保持原样。但是,对于您的最后评论,它可能与我的反向向量函数有关,因为这是我创建的函数。因此,如果对此功能有更多详细说明,我将采用它们并开始修复它。我很难理解如何反转向量,这就是我想出的。我期待有关此功能的任何其他建议,并将在此之前继续工作。伙计们,我也非常感谢快速的 cmets。

标签: c++ string vector


【解决方案1】:

错误线程 1:EXC_BAD_ACCESS(代码=1,地址=0x0):

这是因为您对 reverseVector 的定义,有两个原因,第一个是 string temp = 0;,您在其中初始化字符串时使用 char* 为 NULL 且行为未定义,只需使用 string temp;

i 为 0 时,第二个在第一个循环中,您可以访问 names[names.size()],因此在最后一个元素之后。由于向量中的元素超过 3 个,因此您的算法不正确,因为您总是与 name[0] 交换。您必须将 name[0] 与 names[names.size()-1]andname1with names[names.size()-2] 等交换,将在我的回答结束时返回该功能

老师写了选择排序函数所以我没改

所以对你的老师说他的函数假设向量不为空,当它为空时,测试:

for (startScan = 0; startScan < (arr.size() - 1); startScan++)

总是假的 arr.size() 返回一个 size_t 这是 unsigned 所以当为空时值 ~0u 这是 size_t 的最大可能值。

说他混合(signed)int和(unsigned)size_t是错误的,一般是编译器发出信号的,而且我们是C++,不是C,他们有迭代器

关于主要

为了避免 selectionSort 中的错误,请在调用它之前检查向量是否为空,所以:

if (! boyNames.empty())
  selectionSort(boyNames);
if (! girlNames.empty())
  selectionSort(girlNames);

你在getName中有特殊情况N,当输入的名字是N你不能考虑输入:

if (boyName != "N") {
  boyNameFound = search(boyName, boyNames);
  displayResult("boy's", boyName, boyNameFound);
}

if (girlName != "N") {
  girlNameFound = search(girlName, girlNames);
  displayResult("girl's", girlName, girlNameFound);
}

注意main做两次同样的事情,男孩一次,女孩一次,添加一个函数允许不重复所有代码。

不过好像main也是你老师写的,真是可惜了。

getVector 中可能会在您无法读取文件时产生一条消息。为了帮助阅读代码,我鼓励你在每个声明部分之后添加一个空行,ifstream 的构造函数允许打开文件,这样你就可以拥有

vector<string> getVector(const string& fileName)
{
    string name;
    ifstream file(fileName);
    vector<string> namesFromFile;

    while(getline(file, name))
    {
        namesFromFile.push_back(name);
    }

    return namesFromFile;
}

vector<string> getVector(const string& fileName)
{
  vector<string> namesFromFile;
  ifstream file(fileName);

  if (! file)
    cerr << "cannot read " << fileName << endl;
  else
  {
    string name;

    while(getline(file, name))
    {
      namesFromFile.push_back(name);
    }
  }

  return namesFromFile;
}

关于getName

它不管理 EOF 情况,也不管理名称是否为空或仅包含空格,或者开头和/或结尾有空格。

如果名称必须是唯一的单词,所以“John”而不是“John Doe”,您可以将 getline 的使用替换为 cin &gt;&gt; nameChoice;,并强制 N em> 如果 EOF :

string getName(const string& gender)
{
    string nameChoice;

    cout << "Enter a " << gender << " name, or N if you do not wish to enter a " << gender << " name: " << endl;
    return (!(cin >> nameChoice)) ? string("N") : nameChoice;
}

如果可以组成名字,调用后必须去掉开头和结尾的空格,然后检查输入的名字是否为空,强制N

string getName(const string& gender)
{
    string nameChoice;

    cout << "Enter a " << gender << " name, or N if you do not wish to enter a " << gender << " name: " << endl;
    getline(cin, nameChoice);

    size_t b = 0;

    for (;;) {
      if (b == nameChoice.size())
        return "N";
      if (!std::isspace(nameChoice[b]))
        break;
      b += 1;
    }

    size_t e = nameChoice.size();

    while ((e != 0) && std::isspace(nameChoice[--e]))
      ;

    return (e >= b) ? nameChoice.substr(b, e - b + 1) : string("N");
}

因为教师代码中没有迭代器,所以这里和以后不再使用它们。 请注意,您可能还必须将多余的空格删除到组合名称中,我将“John Doe”替换为“John Doe”?

关于搜索

名字的向量是通过调用selectionSort来排序的,所以如果名字小于向量中的名字,在所有向量中搜索是没有用的

bool search(const string& nameChoice, const vector<string>& names)
{
    for(size_t i = 0; i < names.size(); i++)
    {
        if(nameChoice == names[i])
        {
            return true;
        }
        if (nameChoice < names[i])
        {
            return false;
        }
    }
    return false;
}

不管怎样,即使是你的搜索的小优化仍然在 O(N)

您还可以在 O(log(N)) 中进行更有效的搜索,与一半的(子)向量相比,您可以自己或使用std::binary_search

关于显示结果

nameFoundtrue of false 不可能是别的东西,所以你无法到达else if(names == "N"),你需要先检查那个case , 当你知道 if(nameFound)false 时检查 if(!nameFound) 是没有用的,例如(使用 name 而不是 names 因为只有一个名字):

void displayResult(const string& gender, const string& name, bool nameFound)// change this function so either displays name found not found or chose //not to enter
{
    if(name == "N")
      cout << "You choose to not enter a " << gender << " name." << endl;
    else if(nameFound)
      cout << name << " is one of the most popular " << gender << "names." << endl;
    else
      cout << name << " is NOT one of the most popular " << gender << " names." << endl;
}

void displayResult(const string& gender, const string& name, bool nameFound)// change this function so either displays name found not found or chose //not to enter
{
    if(name == "N")
      cout << "You choose to not enter a ";
    else 
      cout << name << " is" << ((nameFound) ? "" : " NOT")
       << " one of the most popular ";

    cout << gender << " name." << endl;
}

关于writeToFile

ifstream 的构造函数 ofstream 允许打开文件

您不检查是否可以在文件中写入,这很危险,因为隐藏问题,最好这样做:

void writeToFile(const string& fileName, const vector<string>& names)
{
    ofstream outputFile(fileName);

    if (! outputFile)
      cerr << "Cannot open " << fileName << " to write it" << endl;
    else
    {
      for(size_t i = 0; i < names.size(); i++)
        outputFile << names[i] << endl;
    }
}

关于reverseVector

正如我所说的它的定义不正确,他的捷径是使用std::reverse,否则你自己做:

void reverseVector(vector<string>& names) 
{
    string temp;
    size_t pos = 0, sup = names.size();

    while ((pos + 1) < sup)
    {
        temp = names[pos];
        names[pos++] = names[--sup];
        names[sup] = temp;
    }

    for (auto s : names) cout << s << ' ';
    cout << endl;
}

【讨论】:

    【解决方案2】:

    您好,感谢所有帮助我解决这个问题的人。在大家的帮助下,我能够理解发生了什么。

    @bruno 帮助我了解我试图越界或访问向量/数组的末尾。通过使用下面的代码,我能够将第一个元素存储在最后一个元素中,并将最后一个元素存储在第一个元素中。

    void reverseVector(向量和名称)

     {
    string temp;
    for(int i = 0; i < names.size(); i++)
    {
        temp = names[i];
        names[i] = names[names.size() - 1 - i];
        names[names.size() - 1 - i] = temp;
    
    }
    

    } 原来的线程访问错误是因为,虽然老师提供了

    getVector函数上面的代码我应该已经明白了基本思路还是要改全文件路径。

    错误线程 1:EXC_BAD_ACCESS(代码=1,地址=0x0):

    vector<string>         boyNames(getVector("/Users/Desktop/comp165/assignment8/BoyNames.txt"));
    vector<string>
    
    
    
    
    
     Thank you all for your help
    

    【讨论】:

      猜你喜欢
      • 2015-04-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-06-15
      相关资源
      最近更新 更多