-1

This is a code for reading in .txt file and spliting it by : and printing out the result. But I got stuck on the while-loop. This is my code.

#include <iostream>
#include <fstream>
#include <string>
#include <cstring>

using namespace std;

string* split(const string& str, const string& delim) {
    string* string_list = new string[10];

    int idx = 0;
    char *token = strtok(const_cast<char*>(str.c_str()), delim.c_str());
    while (token != NULL) {
        string_list[idx] = token;
        token = strtok(NULL, delim.c_str());
        ++idx;
    }

    return string_list;
}

struct Item {
    string name;
    string age;
    string id;
    string subject[10];
};

struct Item* create_item() {
    struct Item* pitem = new Item;

    return pitem;
};

void insert_item(struct Item *prev_item, struct Item *item) {
    item = (prev_item + 5);
}


int main() {
    string student, student2;
    string *string_list, *subject, *string_list2, *subject2;
    struct Item* pstudent, *pstudent2;

    ifstream fin;
    fin.open("input.txt");
    fin >> student;
    while (student != "\n") {
        string_list = split(student, ":");
        pstudent = create_item();
        pstudent->name = *string_list;
        pstudent->age = *(string_list + 1);
        pstudent->id = *(string_list + 2);
        subject = split(*(string_list + 3), ",");
        for (int i = 0; i < 10; i++) {
            if (*(subject + i) != "") {
                pstudent->subject[i] = *(subject + i);
            }
        }
        cout << *(string_list+1) << endl;

        fin >> student2;
        string_list = split(student2, ":");
        pstudent2 = create_item();
        insert_item(pstudent, pstudent2);
        pstudent2->name = *(string_list);
        pstudent2->age = *(string_list + 1);
        pstudent2->id = *(string_list + 2);
        subject2 = split(*(string_list + 3), ",");
        for (int i = 0; i < 10; i++) {
            if (*(subject2 + i) != "") {
                pstudent2->subject[i] = *(subject2 + i);
            }
        }

    }

    cout << pstudent2->name << endl;

    fin.close();
    return 0;
}

I am still working on this code, but the while-loop in the main() will not stop. I wanted it to stop when the input.txt file input is a new line.

input.txt is

Mary:20:287:Math,Algorithm\n Tom:21:202:Math,English\n Hee:20:256:Math

thanks in advance!

  • You have a few memory leaks in your code. Each time you call `split` you allocate memory (maybe even more than you really need), but nowhere do you free it. I recommend you take some time [with a few good books](https://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list/388282#388282) and learn more about [`std::vector`](http://en.cppreference.com/w/cpp/container/vector). – Some programmer dude Oct 09 '18 at 10:55
  • 7
    `student` never gets changed inside the while loop, so `student != "\n"` is never false. – Zinki Oct 09 '18 at 10:56
  • 1
    Furthermore, think about what you do inside your `insert_item` function. It doesn't really "insert" anything, all it does is a single assignment between pointers, and whose effect will be lost once the function returns. – Some programmer dude Oct 09 '18 at 10:57
  • [How to debug small programs](https://ericlippert.com/2014/03/05/how-to-debug-small-programs/). – zett42 Oct 09 '18 at 10:58
  • 1
    Oh and your `insert_item` have another problem, and that is its out-of-bounds indexing of `prev_item`. The variable `prev_item` points to a *single* `Item` structure, but you use it as an array of at least six elements. – Some programmer dude Oct 09 '18 at 10:59
  • for the `insert_item` function, I wanted to link the items. So in this case it would be pstudent and pstudent2. – Doyoung Kim Oct 09 '18 at 11:00
  • Furthermore, the formatted extraction operator `>>` will never result in a single newline being extracted from the input string. That's not how it works. Both `>>` and `std::getline`, by default, discard newlines. Open your C++ book to the chapter that describes how to read and parse input, and read it. – Sam Varshavchik Oct 09 '18 at 11:02
  • 1
    I would suggest `*(string_list + i)` --> `string_list[i]`. Indexing is far more readable than pointer arithmetic, and harder to get wrong. Even better: use `std::vector` instead of arrays and `std::string::find` instead of `strtok`. – molbdnilo Oct 09 '18 at 11:09
  • To a rough approximation, C++ code should not contain the keyword `new`. You do not need any pointers here – Caleth Oct 09 '18 at 13:09

1 Answers1

0

Don't try to process more than one student in the body of the loop.

Rather than trying to write a linked-list type, use an existing collection type.

#include <iostream>
#include <fstream>
#include <string>
#include <vector>

using strings_view = std::vector<std::string_view>;

strings_view split(std::string_view str, char delim) {
    strings_view view;

    while (str.size()) 
    {
        auto pos = str.find(delim);
        view.push_back(str.substr(0, pos - 1));
        str = str.substr(pos + 1);
    }

    return view;
}

struct Item {
    std::string name;
    std::string age;
    std::string id;
    std::vector<std::string> subject;
};

int main() {
    std::vector<Item> students;

    std::ifstream fin("input.txt");
    for (std::string line; get_line(fin, line);) {
        strings_view view = split(line, ':');
        Item student;
        student.name = view[0];
        student.age = view[1];
        student.id = view[2];
        string_view subject = split(view[3], ',')
        student.subject.assign(subject.begin(), subject.end());
        students.push_back(student);
    }

    std::cout << students[1].name << std::endl;

    return 0;
}
Caleth
  • 52,200
  • 2
  • 44
  • 75