array of ifstream objects in C++ - c++

I am trying to create an array of ifstream objects, the code compiles and I am able to create the array of ifstream objects of size sizeargs-1 however once I try to open a file in one of the ifstream objects the program crashes, it's very frustrating.
the reason I am trying it this was is that I have to dynamically create ifstream objects based on the number of .ppm files in memory and this seemed like the perfect solution, just being able to ifstream_array[1].open(args[0]); since I need to read text from multiple .ppm files simultaneously.
If doing this is impossible; is there an alternative way of doing it?
int main(int argc, char ** args)
{
//counts number of .ppm files in array
int sizeargs = (sizeof(args)/sizeof(*args));
ifstream inputfiles[sizeargs-1];
int incounter = 0;
//this is where the program crashes
inputfiles[incounter].open(args[0]);
}

int sizeargs = (sizeof(args)/sizeof(*args)); //counts number of .ppm files in array
No, it doesn't. This evaluates to sizeof(char**) / sizeof(char*), which is always 1. sizeargs-1 is thus 0 and you have no items in your array. You cannot find the size of an array via a pointer to it. You need to use argc, which is the number of elements in args.
Based on the comments, you should also avoid variable length arrays, as they are availabe only with compiler extensions and are not part of the C++ standard. I would recommend using a vector instead:
std::vector<std::ifstream> inputfiles(sizeargs-1);

This statement:
int sizeargs = (sizeof(args)/sizeof(*args)); //counts number of .ppm files in array
will always yield sizeargs = 1 on *a modern compiler, since the size of a basic data pointer divided by the size of a basic data pointer, is 1.
In C++11 and earlier this statement:
ifstream inputfiles[sizeargs-1];
is invalid, since the size of a (not dynamically allocated) raw array must be a compile time constant.
However, g++ offers C99 variable length arrays (VLAs) as a language extension.
Instead, use a std::vector.
* As James Kanze points out in a comment to another answer, there have been machines where sizeof(char*) was larger than sizeof(char**). Since char is the basic addressable unit, a char* pointer is the largest ordinary pointer. I didn't think that distinction would be relevant here, but reading James' comment (and we have discussed this in the past), I realized that my attitude to the "worth" of an SO answer, is wrong, and adjusted accordingly.

Related

How to save a vector to a file without "printing" it? [duplicate]

first sorry for my bad english. i am just joined this forum and search for
how to correctly write vector to binary file. i just got from this forum an answer like this(i have modified it a little):
#include <iostream>
#include <string.h>
#include <vector>
#include <fstream>
using namespace std;
class Student
{
public:
char m_name[30];
int m_score;
public:
Student()
{
}
Student(const char name[], const int &score)
:m_score(score)
{
strcpy(m_name, name);
}
void print() const
{
cout.setf(ios::left);
cout.width(20);
cout << m_name << " " << m_score << endl;
}
};
int main()
{
vector<Student> student;
student.push_back(Student("Alex",19));
student.push_back(Student("Maria",20));
student.push_back(Student("muhamed",20));
student.push_back(Student("Jeniffer",20));
student.push_back(Student("Alex",20));
student.push_back(Student("Maria",21));
ofstream fout("data.dat", ios::out | ios::binary);
fout.write((char*) &student, sizeof(student));
fout.close();
vector<Student> student2;
ifstream fin("data.dat", ios::in | ios::binary);
fin.seekg(0, ifstream::end);
int size = fin.tellg() / sizeof (student2);
student2.resize(size);
fin.seekg(0, ifstream::beg);
fin.read((char*)&student2, sizeof(student2));
vector<Student>::const_iterator itr = student2.begin();
while(itr != student2.end())
{
itr->print();
++itr;
}
fin.close();
return 0;
}
but when i run it. on my linux mint i got this result:
Alex 19
Maria 20
muhamed 20
Jeniffer 20
Alex 20
Maria 21
*** glibc detected *** ./from vector to binary: corrupted double-linked list: 0x0000000000633030 ***
i am new to c++.
some one please help me, been stuck in this problem last 2 weeks.
thanks in advance for the answer.
You are writing to file the vector structure, not its data buffer. Try change writing procedure to:
ofstream fout("data.dat", ios::out | ios::binary);
fout.write((char*)&student[0], student.size() * sizeof(Student));
fout.close();
And instead of calculation size of vector from file size, it's better write vector size (number of objects) before. In the case you can write to the same file other data.
size_t size = student.size();
fout.write((char*)&size, sizeof(size));
To store a vector<T> of PODs in a file, you have to write the contents of the vector, not the vector itself. You can access the raw data with &vector[0], address of the first element (given it contains at least one element). To get the raw data length, multiply the number of elements in the vector with the size of one element:
strm.write(reinterpret_cast<const char*>(&vec[0]), vec.size()*sizeof(T));
The same applies when you read the vector from the file; The element count is the total file size divided by the size of one element
(given that you only store one type of POD in the file):
const size_t count = filesize / sizeof(T);
std::vector<T> vec(count);
strm.read(reinterpret_cast<char*>(&vec[0]), count*sizeof(T));
This only works if you can calculate the number of elements based on the file size (if you only store one type of POD or if all vectors contain the same number of elements). If you have vectors with different PODs with different lengths, you have to write the number of elements in the vector to the file before writing the raw data.
Furthermore, when you transfer numeric types in binary form between different systems, be aware of endianness.
For functions read() and write(), you need what is called "plain old data" or "POD". That means basically that the class or structure must have no pointers inside them, and no virtual functions. the implementation of vector certainly has pointers - I'm not sure about virtual functions.
You will have to write a function that stores a student at a time (or that translates a bunch of students to a array [not a vector] of bytes or some such - but that's more complex).
The reason you can't write non-POD data, in particular pointers, to a binary file is that when you read the data back again, you can almost certainly bet that the memory layout has changed from when you wrote it. It becomes a little bit like trying to park in the same parking space at the shops - someone else will have parked in the third spot from the entrance when you turn up next time, so you'll have to pick another spot. Think of the memory allocated by the compiler as parking spaces, and the student information as cars.
[Technically, in this case, it's even worse - your vector doesn't actually contain the students inside the class, which is what you are writing to the file, so you haven't even saved the information about the students, just the information about where they are located (the number of the parking spaces)]
You probably cannot write in binary (the way you are doing) any std::vector because that template contains internal pointers, and writing and re-reading them is meaningless.
Some general advices:
don't write in binary any STL template containers (like std::vector or std::map), they surely contain internal pointers that you really don't want to write as is. If you really need to write them, implement your own writing and reading routines (e.g. using STL iterators).
avoid using strcpy without care. Your code will crash if the name has more than 30 characters. At least, use strncpy(m_name, name, sizeof(m_name)); (but even that would work badly for a 30 characters name). Actually, m_name should be a std::string.
serialize explicitly your container classes (by handling each meaningful member data). You could consider using JSON notation (or perhaps YAML, or maybe even XML -which I find too complex so don't recommend) to serialize. It gives you a textual dump format, which you could easily inspect with a standard editor (e.g. emacs or gedit). You'll find a lot of serializing free libraries, e.g. jsoncpp and many others.
learn to compile with g++ -Wall -g and to use the gdb debugger and the valgrind memory leakage detector; also learn to use make and to write your Makefile-s.
take advantage that Linux is free software, so you can look into its source code (and you may want to study stdc++ implementation even if the STL headers are complex).

How to pull text out of a .txt and store it into a dynamic 2d array?

I need to pull text line by line out of my .txt file and store it into a dynamic array that has new space allocated every time I pull a new line out of the .txt file. My code seems to pull out the first line just fine and store it into the first pointers array, but on the second loop, it seems to reset all the pointers arrays which gives me memory allocation errors when I later try to access it. Why does this happen especially when I don't touch the pointers and their arrays after I store stuff into them?
char** temp = nullptr;
char buffer[256];
int index = 0;
// Open File
fstream myFile;
myFile.open("pantry.txt", ios::in);
if (myFile.is_open())
{
while (!myFile.eof())
{
myFile >> buffer; // Pull line out of txt.file
temp = new char* [index + 1]; // Create new pointer
temp[index] = new char[strlen(buffer)+1]; // Create char array pointed at by new pointer
#pragma warning(suppress : 4996) // Turns off complier warning
strcpy(temp[index], buffer); //Copy buffer into new char array
index++; // Increment our index counter int
}
for (int i = 0; i < index; i++)
{
cout << temp[i] << endl;
}
If allocated and stored correctly I want it to just print out the txt file exactly.
Instead, I get
Exception thrown at 0x7B9A08CC (ucrtbased.dll) in PE 12.4.exe: 0xC0000005: Access violation reading location 0xCDCDCDCD.
pantry.txt
Basil
Flat Leaf Parsely
Thyme
Sage
Cumin
Steak Seasoning
Mace
Garlic Powder
There are multiple bugs in the shown code.
while (!myFile.eof())
This is always a bug that also must be fixed, in addition to the main problem with the shown code:
temp = new char* [index + 1];
To help you understand the problem with this line, it's helpful to remember The Golden Rule Of Computer Programming:
Your computer always does exactly what you tell it to do instead of
what you want it to do.
According to the Golden Rule, the above line tells your computer, exactly: "new something, and assign it to temp".
And this is what your computer will do every time it executes this line. This line is executed once, on each iteration of this loop. The next time this loop runs, the previously newed temp will be replaced by another one, leaking everything that it pointed to before. Why should your computer do anything else, on this line? After all, this is exactly what you told your computer to do. And this is why you observed that this will "reset all the pointers arrays" on every iteration of the loop, resulting in "memory allocation errors".
In any case, this entire chunk of logic needs to be scrapped and rewritten from scratch, this time using the right logic. The simplest thing to do is to actually use the C++ library's std::vector and std::string objects, which will do all the memory allocation for you, correctly. Modern C++ code rarely needs to new anything, and will use C++ library's containers, instead.
It is possible that the goal of your assignment is to demonstrate proper use of low-level memory allocation and deallocation logic. In this case you will need to find some other way of doing this. Since you don't know the number of lines in advance, one approach will be to build a linked list, one line at a time, as each line gets read from the file. The final array, with all the character pointers gets allocated only after the entire file is read (and the number of lines is known), the pointers moved to the array, and the temporary linked list deleted. Or, perhaps implement a std::vector-like algorithm that progressively allocates a new pointer array, when it is full, copies over all the character pointers to a bigger array and then deletes the original one.
Of course, that's a lot of work. But unless the purpose of your assignment or task is to correctly implement low-level memory allocations and deallocation, why go through all the work and pain to do what std::vector and std::string already do, when you can simply use them, in just five or six lines of code, that will replace all of the above?

Is size of an array flexible in C++?

After declaring a character array, say char s[20], and eventually getting inputs using cin.getline(s,100) change the size of the array to 100, change (exactly) to the number of characters entered as input, or does it change at all? What happens to the array size that I initially declared?
I'm new to programming, so your simple explanation will be greatly appreciated. Thank you!
The size does not change what happens is that you are writing past the buffer size. If you write far enough through the buffer you will end up causing a buffer overflow.
You should use std::vector whenever you can instead of c-style arrays.
As Ted Lyngmo commented, in this case std::string will be better to use than std::vector or the c-style array:
std::string input;
std::getline(std::cin, input);
The answer is: No.
The size of the character array s doesn't changes to 100, but when you exceed the limit of the array's length, you cause a buffer overflow, which is really bad.
Let's consider an incorrect program, which is based on your assumption:
#include <iostream>
int main(void) {
char s[20];
std::cout << "Enter a sentence: ";
std::cin.getline(s, 100);
std::cout << s << std::endl;
return 0;
}
Here I just try to expand the size of array s, it actually doesn't.
If you enter an example sentence, like: hello-world-how-are-you-today (which contains 29 characters including a null-terminator), it'll just store:
hello-world-how-are-
And notice that it doesn't contains a null-terminator since all the containers are used and it just keeps reading which may cause undefined behavior (UB).
Arrays don't have dynamic memory. If you want dynamic memory allocation, you can use std::string for an array of characters, or std::vector.
std::string works like char s[x];, but it is more flexible and it has a few different things.
std::vector is basically like an array, but you can add / remove elements.
Syntax:
std::vector<type> name; // this is the classic syntax, I won't get more in-depth
Example:
std::vector<int> myVect;
You can add elements using myVect.insert(position, element); or something similar, I don't remember exactly, or you can use myVect.push_back(element); to add an element at the end of the vector.
Search it on cplusplus reference or GeeksForGeeks, you'll find a lot of information.
C++ doesn't have a variable-length array.
To handle this situation, you can have below data structures.
std::string
std::vector
dynamic array, using new[] in C++ or malloc() in C.
Click on the links, and you will find the description and usages.

Char array returns four times more data than expected

Before I continue, here's the code:
#include <iostream>
using namespace std;
int main() {
char array[] = {'a','b','c'};
cout << array << endl;
return 0;
}
My system:
VisualStudio 2019, default C++ settings
Using Debug build instead of release
When I run this code sample, I get something like this in my console output:
abcXXXXXXXXX
Those X's represent seemingly random characters. I know they're from existing values in memory at that address, but I don't understand why I'm getting 12 bytes back instead of the three from my array.
Now, I know that if I were doing this with ints which are four bytes long, maybe this would make sense but sizeof(array) returns three (ie. three bytes long, I know the sizeof(array) / sizeof(array[0] trick.) And when I do try it with ints, I'm even more confused because I get some four-byte hex number instead (maybe a memory address?)
This may be some trivial question, I'm sorry, but I'm just trying to figure out why it behaves like this. No vectors please, I'm trying to stay as non-STL as possible here.
cout takes this char array and addresses it as a null-terminated string.
Since the terminating character in this array is not the null character (i.e., char(0)), it attempts to print until encountering the null character.
At this point, it attempts to read memory outside of the array which you have allocated, and technically, anything could happen.
For example, there can be different data in that memory every time the function is called, or the memory access operation may even be illegal, depending on the address where array was allocated at the time the function was called.
So the behavior of your program is generally considered undefined (or non-deterministic).

Length of pointer to pointer

I searched and I didn't find anything that is like my situation. I have a float** and well I know that it is a special type of pointer because it is an array of elements that have a float* that points to another zone of memory. So I write a simple code to detect the length of this matrix, to be more precise the length of the float + elements inside float**; But it results in a segmentation fault.
Here there is my code:
int Loader:: Length(float** length)
{
int count=0;
while(*length[count]!='\0'){
count++;
}
std::cout<<count<<std::endl;
return count;
}
Sorry for my english and sorry for the stupid question. Thanks to all.
I have a float** and well I know that it is a special type of pointer
Not really. A double pointer is just a special case of a single pointer. It is still a pointer to T, and that T happens to be float*.
because it is an array of elements
No! It is not an array. It may point to the first element of an array.
that have a float* that points to another zone of memory.
So, more precisely, a float** may point to the first element of an array full of float*. Where those individual float*s point to is another story.
So I write a simple code to detect the length of this matrix,
You cannot. When all you have is a pointer to the beginning of an array, then the size information is already lost.
That is, unless you have a convention for the last element, like C-style strings or string literals with their '\0' terminator. Which brings us to the next point...
int Loader:: Length(float** length)
{
int count=0;
while(*length[count]!='\0'){
Here's the culprit. Not all arrays are terminated by '\0'. In fact, it's not typical at all for arbitrary arrays containing a zero separator.
So unless the array to whose first element length points to actually contains an element which compares to '\0', then your loop will go one element past the end of the array and try to read from there. In that very moment, undefined behaviour is invoked and your program can do anything, including random crashes.
The best solution to your problem is to use std::vector, because a std::vector always knows its own size. So make it std::vector<float*>. Or better yet, a std::vector<std::vector<float>>.
In fact, if it's really a matrix, then make it std::vector<float>, store all contents contiguously, additionally store the matrix' width somewhere, and always calculate the offset for X/Y.
The problem is caused by your expectation that all arrays operate in the same way as literal character strings, ie that they are automatically terminated by a 0 value. Neither C++ or C work that way.
If you want the array length you need to do one of the following:
Pass the length along with the array everywhere.
Use a std::vector, std::deque or std::array instead of an array, and get the length from that.