I am trying to read integers from a text file and put them into a dynamic array that will be represented as vectors and matrices for an assigment.
An example of a few lines from the input file:
3#456
33#123456789
The numbers before the pound sign represent the elements of the vector or matrix, so 3# would mean a three element vector and 33# would mean a matrix with 3 rows and 3 columns.
Reading those isn't really a problem as we were told we can assume we know which lines are matrices and which are vectors, however, I have never working with C++ file I/O so I don't know how to iterate through the numbers 4,5,6 and put them into a 3, 9, 12, etc, element dynamically created array. Here's somewhat of a sample of what I'm working with.
int *a;
int size_a;
char x;
ifstream infile("input.txt");
if (infile.is_open())
{
infile >> size_a;
// The x is basically a junk variable used to go past the '#'
// when reading the file
infile >> x;
a = new int[size_a];
}
After that, I have no real idea of how to loop until the end of the line and put the remaining elements in the array. For example in this line, the numbers 4, 5, and 6 would need to be put into the a array, then break from adding elements and go to the next line to work on the next array, which I don't know how to do either. Any ideas?
The below code will do this for you. Note that you do not need to use new here - you should just use a std::vector. In that case, the number before the '#' is unneeded as you do not need to specify the size of the array when you create it.
For that reason I have used new here anyway to show you how to read both parts of the file.
#include <iostream>
#include <fstream>
#include <string>
int main()
{
std::ifstream file("input.txt");
if(file.good()) {
std::string line;
std::getline(file, line);
std::string::size_type pos = line.find('#');
std::string strSize = line.substr(0, pos);
std::string strValues = line.substr(pos + 1);
int size = 0;
for(char c : strSize) {
if(size == 0)
size = static_cast<int>(c - '0');
else
size *= static_cast<int>(c - '0');
}
int* values = new int[size];
for(int i = 0; i < size; ++i) {
values[i] = static_cast<int>(strValues[i] - '0');
}
std::cout << "Array of size " << size << " has the following values:" << std::endl;
for(int i = 0; i < size; ++i) {
std::cout << values[i] << std::endl;
}
delete[] values;
}
}
Related
I am trying to store a sentence to a 2d array by separating each words. In the 2d array each row will contain each word from the sentence. Here is what I think I should do.
//Logic
//given string mystring
string mystring = "testing the arrays";
//create a 2d char array to hold 4 words with 10 max size
char 2darr[4][10] = {" "};
int x = 0;
for (int i = 0,j=0; i <mystring.length(); i++)
{
if (mystring(i) != ' ')
2darr[x][j++] = mystring(i); //copy the each character to the first row
else
2darr[x][j++] = '\0';
++x; // goes to next row
j = 0; //reset j for new row
}
Is there a better way to do this? I think my logic is a little off as well
The better way to do this is:
1) There is no need to check spaces. For this to occur, you can use std::istringstream with operator >> to obtain each word in a loop.
2) Use strncpy to copy the string into the 2 dimensional array
3) You need to make sure that the string does not exceed the bounds of the array, and that you have no more than 4 separate words.
Here is an example:
#include <iostream>
#include <string>
#include <vector>
#include <sstream>
#include <cstring>
int main()
{
char arr2d[4][10] = {};
std::string mystring = "testing the arrays";
// create an input stream containing the test string
std::istringstream strm(mystring);
std::string word;
// this is the word count
int curCount = 0;
// obtain each word and copy to the array
while (strm >> word && curCount < 4)
strncpy(arr2d[curCount++], word.c_str(), 9);
// output the results
for (int i = 0; i < curCount; ++i)
std::cout << arr2d[i] << "\n";
}
Output:
testing
the
arrays
this expression char 2darr[4][10] = {" "} will only set the first element to be " ", the others will be '\0' or NULL. But it is probably OK, since it is the default terminator of C-strings.
Variables can't start with a digit, call it arr2d instead.
String character access is mystring[i], not mystring(i)
You only indented the lines in the else block, in C++ if you don't enclose a block with curly braces, it only captures the first row, what you basically wrote is:
else {
2darr[x][j++] = '\0';
}
++x; // goes to next row
j = 0; //reset j for new row
Corrected code is
std::string mystring = "testing the arrays";
//create a 2d char array to hold 4 words with 10 max size
char arr2d[4][10] = { };
int x = 0;
for (int i = 0, j = 0; i < mystring.length(); i++)
{
if (mystring[i] != ' ') {
arr2d[x][j++] = mystring[i]; //copy the each character to the first row
}
else {
arr2d[x][j++] = '\0';
++x; // goes to next row
j = 0; //reset j for new row
}
}
I'm using dynamic 2D array and need the value of particular index but it is not printing the correct value.
```int u=5;//No. of elements
int S[u];
int i=0;
while(i<u)//elements in universal set
{
cin>>S[i];
i++;
}
int n;
cin>>n;//no. of subset
i=0;
int subcost[n];
int **subset;
subset=new int*[n];
while(i<n)
{
int l,c;
cin>>l;//size of ith subset
subset[i]=new int[l];
int j=0;
while(j<l)//Elements in each subset
{
cin>>subset[i][j];
j++;
}
cin>>c;//cost for each subset
subcost[i]=c;
i++;
}
i=0;
while(i<n)
{
int j=0;
int s=*subset[i];
while(j<s)
{
cout<<subset[i][j]<<"\n";
j++;
}
i++;
}```
I expect the output to be value of each subset, but the actual output is totally different.
arr[i]=new int[n1];
There's a misunderstanding of what new does. (Perhaps you come from Java?) This doesn't store an integer with the value of n1. It instead creates an array with a size of n1.
Just one pointer level should be enough for an array:
int n = 5;
int i = 0;
int *arr;
arr = new int[n];
arr[i] = 100;
cout << arr[i] << endl; // output: 100
delete[] arr; // remember to deallocate – otherwise memory leaks will haunt your system!
If you're looking for a 2D array, a pointer to a pointer (**) will work.
int **arr;
arr = new int[n]; //
arr[0] = new int[n]; // allocate first array
arr[0][0] = 100; // set first element of first array
delete[] arr[0];
delete[] arr; // deallocate
Here
arr[i]=new int[n1]; /* allocating memory for arr[i], equal to n1*sizeof(int) bytes & arr[i] gets points to address returned by new */
cout<<"Value of "<<i<<"th row is :- "<<arr[i]<<"\n";
I expect the output to be value of n1, but the actual output is some
random address ?
yes, arr[i] is dynamically created array & printing it will prints its base address only.
Try this version where I tried to explain code changes in comments.
int main(void) {
std::cout<<"Enter the value of n"<<"\n";
int n;
std::cin>>n;
int **arr;
/* allocate memory for arr. arr holds base address of array of n int ptr */
arr=new int*[n];
int i=0;
int n1;
std::cout<<"Enter the value of n1"<<"\n";
std::cin>>n1;
/* allocate memory for arr[0], arr[1] .. */
while(i < n1) {
arr[i]=new int[n1];
i++;
}
/* put the data into dynamically allocated array */
for(int row = 0; row < n; row++) {
for(int col = 0; col < n1; col++) {
std::cin>>arr[row][col];
}
}
/* printh te data */
for(int row = 0; row < n; row++) {
for(int col = 0; col < n1; col++) {
std::cout<<"Value of "<<i<<"th row is :- "<<arr[row][col];
}
std::cout<<"\n";
}
return 0;
}
And since you created dynamic array using new you need to free the dynamically allocated memory to avoid memory leakage, use delete operator accordingly.
As pointed by others std::vector is better option than above one.
While you have a good answer from #Achal for dynamically allocating, as mentioned, you really should use the container vector provided by C++ to make things much easier and more robust. All C++ containers provided automatic memory management freeing you from having to allocate manually (and with much less chance of getting it wrong)
When using containers, such as a vector of vectors to store your data, you can simply read and discard your "//elements in universal set", "//no. of subset" and "//Elements in each subset". Those values are not required when using containers. You simply read the value you want and add it to your container, the container will grow as needed to accommodate.
While it is not 100% clear what your input data looks like, we can deduce from your file it looks something like:
Example Input File
Where your first integers is your "//elements in universal set" which isn't needed to read the data. Likewise the second line, your "//no. of subset" is irrelevant for reading the data. Finally the 1st element on each data row, your "//Elements in each subset" is also not needed. Each of these values is simply read and discarded to arrive at your final data set.
$ cat dat/universal_sub.txt
5
4
5 1 2 3 4 5
3 1 2 3
4 1 2 3 4
6 1 2 3 4 5 6
The Final Dataset You Want To Store
From the full file, these appear to be the actual data values you want to store (there can be an even number, but there is no requirement for that)
1 2 3 4 5
1 2 3
1 2 3 4
1 2 3 4 5 6
There are many different ways you can put the pieces together. A short example of how to get your final dataset from your input file could be:
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
#include <limits>
int main (void) {
std::string line; /* string for reading each line */
std::vector<std::vector <int>> subset; /* vector<vector<int>> */
int universal, nsubsets; /* two int to read/discard */
if (!(std::cin >> universal >> nsubsets)) { /* read/dicard 2 values */
std::cerr << "error: failed to read universal.\n";
return 1;
}
/* read/discard '\n' (any chars) left in input buffer line by cin above */
std::cin.ignore (std::numeric_limits<std::streamsize>::max(), '\n');
while (getline (std::cin, line)) { /* read each remaining data line */
int unneeded, i; /* 1st value and i for rest */
std::vector<int> tmp; /* vector<int> for each line */
std::stringstream ss (line); /* stringstream to read from */
if (ss >> unneeded) { /* read/discard 1st value */
while (ss >> i) /* read rest from stringstream */
tmp.push_back(i); /* add to tmp vector */
subset.push_back(tmp); /* add tmp vector to subset */
}
}
for (auto& i : subset) { /* loop over subsets */
for (auto& j : i) /* loop over each value in subset */
std::cout << " " << j; /* output value */
std::cout << '\n'; /* tidy up with newline */
}
}
(note: the output loops make use of the Range-based for loop (since C++11) but you are free to use the .begin() and .end() container functions with a traditional for loop if your compile does not support std=c++11)
Exaple Use/Output
Reading your data into a vector of vectors allows accessing each element:
$ ./bin/vector_2d_subset < dat/universal_sub.txt
1 2 3 4 5
1 2 3
1 2 3 4
1 2 3 4 5 6
Look things over and let me know if you have further questions or if I interpreted your data file format incorrectly.
let's say we have a matrix in a matrix.txt file, stored like this:
and we want to transform it into:
Number 8 (first number) means how big will 2D array be. After that it means:
1 is connected to 2 (value of connection is 1, it will always be 1)
1 is connected to 8
3 is connected to 4
And when transformed into 2D dynamical array, we want the value 1 in ARRRAY 0,1...0,7...2,3 and soo on (i didnt use square brackets because stackoverflow read them as links).
int number;
int **a = new int*[number];
for (int i = 0; i<number; i++) {
a[i] = new int[number];
}
for (int i = 0; i<number; i++) {
delete[]a[i];
}
delete[]a;
string line;
ifstream myfile("matrix.txt");
if (myfile.is_open())
{
getline(myfile, line);
istringstream(line)>> number;
while (getline(myfile, line)){
cout << line << '\n';
//HERE I SHOULD TURN THOSE NUMBERS INTO VALUES IN 2D ARRAY
}
myfile.close();
}
So my question is: How do i turn this numbers into matrix in 2d array?
Thank you
The easy way, but possibly not the fastest way, is to write the line into a std::stringstream, then read back out of the stringstream into row, column, and value variables. If you are reading from a file the cost of reading the file in the first place usually dwarfs the cost of parsing the file the slow way. If it matters in your case (and profile the code first to make sure it does) look into manually parsing the file. That said, this basic logic will hold.
while (getline(myfile, line)){
cout << line << '\n';
std::stringstream linestream(line);
int row;
int column;
int value;
if (linestream >> row >> column >> value)
{
a[row-1][column-1] = value;
a[column-1][row-1] = value;// mirror
}
else
{
// handle file formatting error
}
}
Off topic, consider using a matrix class to manage a for you rather than a raw 2D Array. The matrix class here at isocppp.org is good and fast, as well as wrapped in some very good general-purpose advice.
The above code with the isocpp matrix looks like:
while (getline(myfile, line)){
cout << line << '\n';
std::stringstream linestream(line);
int row;
int column;
int value;
if (linestream >> row >> column >> value)
{
a(row-1,column-1) = value;
a(column-1,row-1) = value;// mirror
}
else
{
// handle file formatting error
}
}
Nearly identical and a lot easier to use because you don't have to worry about managing the memory yourself, passing the array dimensions around, or a bit of bad code (such as a[4] = 0;) nuking a row of your array.
Addendum
This code
int number;
int **a = new int*[number];
for (int i = 0; i<number; i++) {
a[i] = new int[number];
}
for (int i = 0; i<number; i++) {
delete[]a[i];
}
delete[]a;
has two serious problems:
a is sized with number, and number hasn't been assigned yet. number could be anything from an instantly fatal negative number (can't have an array with a negative size) to a potentially fatal huge number (Your computer have 9,223,372,036,854,775,807 squared bytes of RAM? Didn't think so.)
It deletes the storage immediately after allocating it. Freeing the memory is a great habit to get into, but it's best to free the memory after using it, not before.
So:
// define `a` here
string line;
ifstream myfile("matrix.txt");
if (myfile.is_open())
{
getline(myfile, line);
istringstream(line)>> number;
// allocate storage for `a` here
while (getline(myfile, line)){
cout << line << '\n';
//line reading code goes here
}
myfile.close();
}
// delete `a` somewhere down here after it's been used.
I suggest you use C++ vector from the STL instead of 2d C array which are unsafe.
You could do something like :
ifstream myfile("matrix.txt");
// Read matrix size
size_t matrix_size = 0; myfile >> matrix_size;
vector<vector<int> > matrix(matrix_size);
for(size_t i=0; i < matrix.size(); ++i) matrix[i].resize(matrix_size);
while( myfile.good() )
{
// Read row,col,val and set matrix value
int row=0, col=0, val=0; myfile >> row >> col >> val;
--row; --col; // Since your indices go from 1 to N
if(row < matrix_size && row >= 0 && col < matrix_size && col >= 0) {
matrix[row][col] = val; matrix[col][row] = val;
}
}
I just started a small project which reads a txt file like this:
4
XSXX
X X
XX X
XXFX
So my question is how to read this and put the labyrinth to 2D char array in C++. I tried to use 'getline' but I just make my code more complex. Do you know if there is an easy way to solve this problem ?
char temp;
string line;
int counter = 0;
bool isOpened=false;
int size=0;
ifstream input(inputFile);//can read any file any name
// i will get it from user
if(input.is_open()){
if(!isOpened){
getline(input, line);//iterater over every line
size= atoi(line.c_str());//atoi: char to integer method.this is to generate the size of the matrix from the first line
}
isOpened = true;
char arr2[size][size];
while (getline(input, line))//while there are lines
{
for (int i = 0; i < size; i++)
{
arr2[counter][i]=line[i];//decides which character is declared
}
counter++;
}
Your error is due to the fact that you are trying to declare an array with a size that is a non-constant expression.
In your case size representing the number of elements in the array, must be a constant expression, since arrays are blocks of static memory whose size must be determined at compile time, before the program runs.
To solve it you could either leave the array with empty brackets and the size will be automatically deduced by the number of elements you place in it or
you could use std::string and std::vector and then to read the .txt file you could write something like:
// open the input file
ifstream input(inputFile);
// check if stream successfully attached
if (!input) cerr << "Can't open input file\n";
string line;
int size = 0;
// read first line
getline(input, line);
stringstream ss(line);
ss >> size;
vector<string> labyrinth;
// reserve capacity
labyrinth.reserve(size);
// read file line by line
for (size_t i = 0; i < size; ++i) {
// read a line
getline(input, line);
// store in the vector
labyrinth.push_back(line);
}
// check if every character is S or F
// traverse all the lines
for (size_t i = 0; i < labyrinth.size(); ++i) {
// traverse each character of every line
for (size_t j = 0; j < labyrinth[i].size(); ++j) {
// check if F or S
if (labyrinth[i][j] == 'F' || labyrinth[i][j] == 'S') {
// labyrinth[i][j] is F or S
}
if (labyrinth[i][j] != 'F' || labyrinth[i][j] != 'S') {
// at least one char is not F or S
}
}
}
As you can see this vector is already "a kind of" 2D char array only with a lot of additionally provided facilities that allow a lot of operations on its content.
My code basically is to list ASCII codepoints of a string that is input, my following code is simple, here:
#include <iostream>
#include <string.h>
using namespace std;
int main() {
char str[20];
int result[20];
cin >> str;
for(int i = 0; i != strlen(str); i++) {
result[i] = (int)i;
}
for(int i = 0; i != 20; i++)
cout << result[i] << ", ";
}
when I run it, no matter what the input it outputs a pile of gibberish like undefined memory like so:
0, 1, 2, 3, 4, 5, 1, -1217349408, -1220040795, -1220041307, -1076427112, 134514781, -1218903292, 134519344, -1076427096, 134514004, -1217411568, 134519344, -1076427048, 134514681,
Am I missing something simple in how I append each integer to the array?
Just note this is a simple example, my input will not be larger than 20 characters.
EDIT Typo in my result.. cin>>result was cin>>str
This loop will iterate a number of times equal to the length of 'str'. That is, it will iterate once for each character in 'str', and stop at the 'null terminator' (char value of 0) which is how c strings are ended. In each loop, the value of 'i' is the loop number, starting at 0 - and this is the value you assign to that index in the results array.
for(int i = 0; i != strlen(str); i++) {
result[i] = (int)i;
}
So for example, for a string of length 5, you will assign the values '0, 1, 2 ,3, 4' to the result array at those indexes, respectively. The other values in the result array are not assigned - and so could hold any value (generally, whatever was in that bit of memory before you started using it). If your string is longer than 20 characters, you're in trouble, because you will start trying to access the array at index 20 and beyond, which is not memory that belongs to your program.
This loop prints out all the values in the 'result' array, from the value at index 0 to the value at index 19:
for(int i = 0; i != 20; i++)
cout << result[i] << ", ";
So it will print the initialised values, and, if the string was less than 20 characters long, the uninitialised values as well.
At a minimum, to start getting anything like the results you're after, you want to change
result[i] = (int)i;
to
result[i] = str[i];
but as mentioned by others, and to escape some of the memory access issues I mentioned above, it would be much better if you use an iterator to get the character values.
for(string::iterator i = str.begin(); i != str.end(); i++)
// access char here using '*i'
strlen(str) will give you an undefined output, because you haven't initialised the contents of str[].
Essentially, you failed to correctly initialize the string and you didn't check that it was the correct size. Correct code:
#include <iostream>
#include <string> // NOT <string.h>, <string>
int main() {
std::string str;
std::cin >> str;
std::cin.ignore();
for(std::string::iterator it = str.begin(); it != str.end(); it++) {
std::cout << (int)(*it);
if (it + 1 != str.end())
std::cout << ", ";
else
std::cout << "\n";
}
std::cin.get();
}
You have 3 problems:
You didn't initialise str with a proper string, thus strlen will return an unpredictable value.
You initialise the first strlen(str) positions of result, but later you print it until the index 20. You should use the same condition on both loops.
You should definitely use std::string and its iterator.
You've not initialized str and you are taking its strlen
When you did
cin >> result; // this does not even compile!!!
I guess you meant
cin >> str;
Its not clear what you are trying to do. But you can try this to get some meaningful result:
char str[20];
int result[20] = {0};
cin >> str;
...// rest all unchanged.
stlen( str ) will give the number of characters before the null terminator.
This means that only strlen(str) integers are valid. The rest are uninitialized.
Also: have a look at std::transform. You can avoid the temporary array of integers to achieve the same, or transform right into one.
int to_codepoint( char c ) { return (int) c; }
// ...
char cs[] = "abcd";
std::transform( cs, cs+strlen(cs)
, std::ostream_iterator<int>( std::cout, ", " ), to_codepoint);
// or transform into an array:
int is[ 1000 ]; // 1000 enough?
std::transform( cs, cs+strlen(cs)
, is, to_codepoint );
(test code at codepad.org)