0

I want to read a .txt file.

.txt file will have N-rows and M-cols.

Each word present in the txt file will have varying length.

Sample txt file:

Suppose N = 4 rows

Suppose M = 5 cols

content of txt file:

aa bbb cc dddddddd eeee

aa bbbbbbbbbbbb cc ddddddddddd eeee

aaaaaaaaaa bb cc d e

a b c d eeee

What I have to do:

I have to store these strings into a 2D array of strings such that it looks like this:

arr[4][5] =  

[aa             bbb              cc     dddddddd        eeee]

[aa             bbbbbbbbbbbb     cc     ddddddddddd     eeee]

[aaaaaaaaaa     bb               cc     d               e   ]

[a              b                c      d               eeee]

I know how to create dynamic 2D array of integer and its working fine:

int** arr;
int* temp;

arr = (int**)malloc(row*sizeof(int*));
temp = (int*)malloc(row * col * sizeof(int));
for (int i = 0; i < row; i++)
{
    arr[i] = temp + (i * col);
}
int count = 0;
//setting values in 2-D array
for (int i = 0; i < row; i++)
{
    for (int j = 0; j < col; j++)
    {
        arr[i][j] = count++;
    }
}

But, when I am trying to do the same thing for strings, its crashing.

string** arr;
string* temp;

arr = (string**)malloc(row*sizeof(string*));
temp = (string*)malloc(row * col * sizeof(string));
for (int i = 0; i < row; i++)
{
    arr[i] = temp + (i * col);
}

//setting values in 2-D array
for (int i = 0; i < row; i++)
{
    for (int j = 0; j < col; j++)
    {
        arr[i][j].append("hello"); // CRASH here !!
    }
}

How to store each words in an array??

This is what I have written:

#include "stdafx.h"
#include <cstdlib>
#include <iostream>
#include <vector>
#include <map>
#include <fstream>
#include <string>
#include <algorithm>
#include <assert.h>     /* assert */
using namespace std;

vector<string> readFile(const string file, int& row, int& col)
{
    vector<string> buffer;

    ifstream read(file);
    string line;
    char * writable = NULL;

    if (read.is_open())
    {
        int temp_counter = 0;
        while (!read.eof())
        {
            std::getline(read, line);
            writable = new char[line.size() + 1];
            std::copy(line.begin(), line.end(), writable);
            writable[line.size()] = '\0'; // don't forget the terminating 0
            if (temp_counter == 0)//
            {
                row = std::stoi(line);
                ++temp_counter;
            }
            else if (temp_counter == 1)
            {
                col = std::stoi(line);
                ++temp_counter;
            }
            else
            {
                buffer.push_back(line);
            }       
        }
    }
    // don't forget to free the string after finished using it
    delete[] writable;
    return buffer;
}

void create2DDynamicArray(std::vector<string>&v, int row, int col)
{
    string** arr;
    string* temp;

    arr = (string**)malloc(row*sizeof(string*));
    temp = (string*)malloc(row * col * sizeof(string));
    for (int i = 0; i < row; i++)
    {
        arr[i] = temp + (i * col);
    }


    //setting values in 2-D array
    for (int i = 0; i < row; i++)
    {
        for (int j = 0; j < col; j++)
        {
            arr[i][j].append("hello");
        }
    }
}
int main()
{
    vector<string> myvector;
    int row=0;
    int col=0;

    myvector = readFile("D:\\input.txt", row, col);
    create2DDynamicArray(myvector, row, col);

    getchar();
    return 0;
}

txt file look like:

4

5

aa bbb cc dddddddd eeee

aa bbbbbbbbbbbb cc ddddddddddd eeee

aaaaaaaaaa bb cc d e

a b c d eeee

6
  • You change int to char. You allocate the space for string and not for int. Commented Aug 25, 2016 at 7:27
  • Add allocate an extra entry for the null-character of each string. Commented Aug 25, 2016 at 7:28
  • 2
    Why not choose one of C and C++? If you are going to use C, they say you shouldn't cast the result of malloc() in C. If you are going to use C++, why not use new[] instead of malloc()? Commented Aug 25, 2016 at 7:30
  • "But, when I am trying to do the same thing for strings, its crashing." How? Why not post a Minimal, Complete, and Verifiable example? Commented Aug 25, 2016 at 7:30
  • If you are going to use C++, why even care about allocating like this. Commented Aug 25, 2016 at 7:31

5 Answers 5

4

Don't use malloc in C++. It does not run the constructor of the strings, thus not allocating space for the dynamic char array stored in them. Try the new[] operator or smart pointers instead.

string **arr;
arr = new string*[height];
for (int i = 0; i < height; i++)
    arr[i] = new string[width];

A c++ string is just a kind of wrapper around a dynamic char array, which must be initialized (it should have memory assigned to it). By using malloc you don't call the constructor, resulting in accessing a non allocated memory area.

Sign up to request clarification or add additional context in comments.

Comments

2

I suggest to avoid fragmentation and use a real 2d array.

In C, since C99 you can use VLA's (variable length arrays):

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    int rows = 4, cols = 5;
    char *(*arr)[cols];
    int i, j;

    arr = malloc(sizeof(*arr) * rows);
    for (i = 0; i < rows; i++) {
        for (j = 0; j < cols; j++) {
            arr[i][j] = "hello"; /* For read only, to be writable use strdup */
        }
    }
    for (i = 0; i < rows; i++) {
        for (j = 0; j < cols; j++) {
            printf("%s\t", arr[i][j]);
        }
        printf("\n");
    }
    free(arr);
    return 0;
}

Output:

hello   hello   hello   hello   hello   
hello   hello   hello   hello   hello   
hello   hello   hello   hello   hello   
hello   hello   hello   hello   hello   

arr[i][j].append("hello"); // CRASH here !!

There are not methods in C and this wont compile, why are you mixing C and C++? pick one of them.

6 Comments

Even if C99 isn't available, this method works even on ancient C compilers or C++ compilers, as long as rows and cols are compile-time constants. I personally prefer to use the style arr = malloc(sizeof(char*[rows][cols])); as that makes the intent clearer, it is self-documenting code.
@Lundin are you sure? with gcc -std=c89 : ISO C90 forbids variable length array ‘arr’
The warning disapears when cols is defined as enum {cols = 5}; or #define cols 5 but is still there using with int cols = 5; even using const: related question: stackoverflow.com/q/436300/1606345
Yes that's what I meant, you have to make it a compile-time constant. Unfortunately, C doesn't treat const variables as compile-time constants (but that might work in C++).
@Lundin Ah, ok ;)
|
1

Don't use malloc, avoid new/new[] and use RAII containers:

std::vector<std::vector<std::string>> readFile(const std::string& filename)
{
    std::ifstream file(filename);
    int row;
    int col;
    file >> row >> col;

    std::vector<std::vector<std::string>> words(row, std::vector<std::string>(col));

    for (auto& rows : words) {
        for (auto& word : rows) {
            file >> word;
        }
    }
    return words;
}

Comments

1

enter image description here

Vectors are also Dynamic Arrays , but with all the work of keeping track of pointers hidden from the user.

If you decide to use vectors instead then coding a 2D dynamic array is as easy as this:

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


int main () {

    cout<<"\nDynamic 2D Array.\n\n";

    // create string vector
    vector<string> vArray;

    // create one line string
    string line;

    // open file for reading
    ifstream fileToRead("d2d.txt");
    while (getline(fileToRead, line)){

        //  fuse (store) line from file in vector
        vArray.push_back(line);
    }
    fileToRead.close();

    // display results
    for (int i=0; i< vArray.size();i++){
        cout<<" [ "<< vArray[i] <<" ] \n";
    }

cout<<"\nPress ANY key to close.\n\n";
cin.ignore(); cin.get();
return 0;
} 

Comments

0

If you really want to use 2D array with memory allocated with malloc my suggestion is to shift from string ** to string *** type, like:

    ifstream f(your_file_name);

    string*** arr;

    arr = (string***)malloc(row*sizeof(string**));

    for (int i = 0; i < row; i++)
    {
        arr[i] = (string**)malloc(col * sizeof(string*));
    }

    //setting values in 2-D array
    for (int i = 0; i < row; i++)
    {
        for (int j = 0; j < col; j++)
        {
            arr[i][j] = new string();
            f >> *arr[i][j]; // or arr[i][j] -> append("hello");
        }
    }

But if it really C++ project consider using vector<vector<string>> or even use new instead of malloc, like:

    ifstream f("tmp.txt");

    string** arr;

    arr = new string*[row];

    for (int i = 0; i < row; i++)
    {
        arr[i] = new string[col];
    }

    //reading 2-D array from file
    for (int i = 0; i < row; i++)
    {
        for (int j = 0; j < col; j++)
        {
            f >> arr[i][j];
        }
    }
    // show file content
    for (int i = 0; i < row; i++)
    {
        for (int j = 0; j < col; j++)
        {
            cout << arr[i][j] << " ";
        }
        cout << endl;
    }

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.