-2

I am attempting to read data from a .txt file and put its contents into a linked list that holds two strings per node. Because some of the strings in the .txt file contain spaces, and I'd rather leave them as is than kill the spaces, I am using std::getline().

I have the .txt file formatted as so:

"Tourism, Recreation & Sports Management"

“TRS”

"Anthropology"

“ANT”

And so on but without the blank lines between each line. The linked list has a print() method that prints the data in this format : data1 / data2 ; data1 / data2:

So, when I print a node with data1 == "Tourism, Recreation & Sports Management" and data2 == "TRS" the desired output is:

"Tourism, Recreation & Sports Management" / "TRS";

HOWEVER, what I actually get is:

"TRS"ism, Recreation & Sports Management"

However, when I read the lines and assign them to strings, and then print out those strings without inserting them into the linked list, I get correct output. That is

std::cout << data1 << std::endl;
std::cout << data2 << std::endl;

Will correctly output:

"Tourism, Recreation & Sports Management"
"TRS"

What gives?

Edit: Linked List header:

#ifndef _2DLL_H_
#define _2DLL_H_
#include <iostream>
#include <string>



class Llist{
  struct node{
    //node member var
    std::string department;
    std::string abv;
    node * next;

    //node member methods

    std::string search(std::string dep);
    void print();
    void remove(const std::string dep);
    void clear();
    //constructer
  node(const std::string dep , const std::string a):department(dep), abv(a), next(NULL){}

  };// end node

 public:
  //Llist member var
  node * head;

  //LList constructer & destructor
 Llist():head(NULL){}
  ~Llist(){clear();}

  //Llist member functions
  std::string search(const std::string dep);
  void insert(const std::string dep , const std::string a);
  void print();
  void remove(const std::string dep);
  void clear();
  const int operator[](unsigned int index)const;
};// end Llist


#endif //_2DLL_H_

Linked List .cpp

#include "2DLL.h"
#include <algorithm>


//=========INSERT==============

void Llist::insert(const std::string dep, const std::string a){ //will just prepend. Fuck the police;
  node * n = new node(dep , a);
  n->next = head;
  head = n;
}

//========PRINT=================
void Llist::print(){
  if(head==NULL){
    std::cout << "ERROR: List is empty" << std::endl;
  }
  else{
    head->print();
  }
}

void Llist::node::print(){
  if(next==NULL){
    std::cout << department << ";" << abv << std::endl;
  }
  else{
    std::cout << department << ";" << abv << " / " ;
    std::cout << std::endl;
    next->print();
  }
}

//=======REMOVE========

void Llist::remove(const std::string dep){
  if(head==NULL){
    std::cout << "ERROR: List is empty" << std::endl;
  }
  else{
    head->remove(dep);
  }
}

void Llist::node::remove(const std::string dep){
  if(next->department == dep){
    node * n = next;
    next = n->next;
    delete n;
  }
  else{
    next->remove(dep);
  }
}

//===========CLEAR()==================

void Llist::clear(){
  if(head==NULL){
    std::cout << "ERROR:List is empty" << std::endl;
  }
  else{
    head->clear();
    head = NULL;
  }
}

void Llist::node::clear(){
  if( this==NULL){
    return;    

  }
  else{
    next->clear();
    delete this;
  }

}

//=========OPERATOR=============
/*
const int Llist:: operator[] (unsigned int index) const{
  node * n = head;
  for(int i = 0 ; i < index && n!=NULL ; ++i){
    n=n->next;
  }
  return n->data;
}

*/

//========SEARCH====================

std::string Llist::search(std::string dep){
  if(head == NULL){
    std::cout << "ERROR: List is empty" << std::endl;
    return "ERROR";
  }
  else{
    //dep.erase(std::remove(dep.begin(),dep.end(),' '),dep.end());
    //std::cout << dep << std::endl;
    return head->search(dep);
  }
}

std::string Llist::node::search(std::string dep){
  if(department == dep){
      return abv;
  }
  else{
      return next->search(dep);
    }
  }

Implementation of the Reading

#include "genCollege.cpp"
#include "genDepartment.cpp"
#include "2DLL.cpp"
#include <ctime>
#include <fstream>

using namespace std;


int main(){
    std:: ifstream file;
    file.open("DepList.txt");
    std::string department;
    std::string abv;

    srand(time(0));
    /*for (int  i = 0 ; i < 30 ; i++){
        std::string college = genCollege();
        std::string department = genDepartment(college);

        std::cout << "College: "<< college << std::endl;
        std::cout << "\t" << "Department: " << department << std::endl;
        std::cout << std::endl;
    }   */
    Llist list;

    while(file.is_open()){
        if(file.eof()){break;};

        std::getline(file , department);
        std::getline(file, abv);

        list.insert(department , abv);

    }
    //file.close();
    list.print();



    return 0 ; 
}
The Alex
  • 201
  • 1
  • 5
  • 10
  • 1
    A 5-page essay (poorly formatted) and no code? What gives? – Kerrek SB Oct 05 '14 at 21:49
  • Sounds like your nodes do not correctly allocate independent storage for each string. Do the node contain `std::string`? `char[]`? `char*` ? – Ben Voigt Oct 05 '14 at 21:50
  • I figured it might have been just a quirk with using the getline() method in general and that I did not know about. What code would you like to see? You need only ask :) – The Alex Oct 05 '14 at 21:51
  • 3
    You have a text file created for Windows that has `\r\n` as the line terminator. Your program either runs on a un*x or fails to open the file in text mode. Thus you are getting `\r` at the end of each string, which messes your terminal window. – n. 'pronouns' m. Oct 05 '14 at 21:53
  • The code we want to see is the part that calls `std::getline` to read `data1` and `data2`. We would also be interested to see the definition of those two variables. – paddy Oct 05 '14 at 21:55
  • @n.m. Ah, that would explain why since I am running on Ubuntu. What would be the correct way to remedy this? or is simply because I am using the terminal in ubuntu that it looks incorrect, but the implementation is actually correct? – The Alex Oct 05 '14 at 21:56
  • No, you don't want to have random control characters hanging around. If you want to handle Windows files you have to filter `\r`s out. Just after `std::getline()` check whether your last character is `\r` and if so, remove it. – n. 'pronouns' m. Oct 05 '14 at 22:03
  • On an unrelated note, your program suffers from the [`while(!eof)` syndrome](http://stackoverflow.com/questions/5605125/why-is-iostreameof-inside-a-loop-condition-considered-wrong). – n. 'pronouns' m. Oct 05 '14 at 22:05
  • @n.m Perfect! I've done what you've suggest and it works 100% as desired. Thanks a ton for your help. – The Alex Oct 05 '14 at 22:10

1 Answers1

0

As the user n.m suggested, it seemed that because I was reading a text file for Windows and running program on Ubuntu, the output looked wrong. His answer word for word:

"You have a text file created for Windows that has \r\n as the line terminator. Your program either runs on a un*x or fails to open the file in text mode. Thus you are getting \r at the end of each string, which messes your terminal window. "

He suggested I check to see if the the last character in the string after I've used std::getline() is \r and, if it is, to remove it from the string. I did this by simply making a substring of the strings in question after I acquired them with std::getline()

I then inserted the new substrings into the linked list and the print() method now outputs as desired.

The Alex
  • 201
  • 1
  • 5
  • 10