Why am i getting "Access violation error reading " on the following program:
The error is on the while loop to read the file.
#include <iostream>
class fileReader
{
public:
FILE *fp;
char** lines;
fileReader()
{
fp = NULL;
}
fileReader(const char* path)
{
int i=0;
fp = fopen(path,"r");
while ( fgets(lines[i], 100, fp) )
i++;
}
};
int main(int argv, char** argc)
{
const char* path = "D:\\PS4263-2.txt";
fileReader *p = new fileReader(path);
for (int i=0; i<2; i++)
std::cout<<p->lines[i];
return 0;
}
EDIT
As mentioned by the answers I changed my code to (below), but I am still getting the same error.
#include <iostream>
class fileReader
{
public:
FILE *fp;
char** lines;
fileReader()
{
fp = NULL;
}
fileReader(char* path)
{
int j=0;
fp = fopen(path,"r");
if (fp == NULL)
return;
else
{
lines = (char**) malloc(sizeof(char *)*56000);
for (int i=0; i<56000; i++)
lines[i] = (char*)malloc(sizeof(char)*1440);
while ( fgets(lines[j], 1440, fp) )
j++;
fclose(fp);
}
}
};
int main(int argv, char** argc)
{
char* path = "D:\\testfile.txt";
fileReader *p = new fileReader(path);
for (int i=0; i<2; i++)
std::cout<<p->lines[i];
return 0;
}
There are a number of problems with this code. But primarily, the problem is that you're writing some evil C/C++ hybrid. Pick one of the two languages, and use that.
Here's a revised version of your code:
#include <iostream>
class fileReader
{
public:
FILE *fp;
char** lines;
fileReader() : fp(NULL) // initialization of members happens here
{
//fp = NULL; // anything here happens *after* initialization
lines = new char*[100]; // let's just assume max 100 lines. We have to allocate space for them
for (int i = 0; i < 100; ++i) {
lines[i] = new char[100]; // allocate space for the contents of each individual line
}
}
fileReader(const char* path)
{
lines = new char*[100]; // let's just assume max 100 lines. We have to allocate space for them
for (int i = 0; i < 100; ++i) {
lines[i] = new char[100]; // allocate space for the contents of each individual line
}
int i=0;
fp = fopen(path,"r");
while ( fgets(lines[i], 100, fp) )
i++;
}
~fileReader() {
// deallocate and close our members:
fclose(fp);
for (int i = 0; i < 100; ++i) {
delete[] lines[i]; // delete the contents of each line
}
delete[] lines; // delete the lines array
}
};
int main(int argv, char** argc)
{
const char* path = "D:\\PS4263-2.txt";
fileReader p(path); // don't use new unless you really really have to
for (int i=0; i<2; i++)
std::cout<<p.lines[i];
return 0;
}
Now at least it works, if each line contains less than 100 characters and there are fewer than 100 lines and the file exists and a dozen other conditions that we really should protect against. In particular, we spend a lot of effort on memory management: allocating and deallocating space for all the line data.
But we can do a lot better with just a few changes, if we actually start writing C++.
#include <iostream> // we need this for the standard streams (cout)
#include <fstream> // we need proper C++ file streams too
#include <string> // C++ has strings. Don't waste your time on char pointers
#include <vector> // C++ has a dynamic array class. Don't use pointers as ad-hoc arrays
class fileReader
{
public:
// FILE* fp; // no point in making this a class member, when it's only used in one function
std::vector<std::string> lines; // use a vector of strings. Much easier to manage
fileReader() // vectors are automatically initialized, no need to do anything
{
}
fileReader(std::string path)
{
std::ifstream fp(path); // create an input file stream
std::string result; // store the contents of the current line here
while (std::getline(fp, result)) {
lines.push_back(result); // append the resulting line to the end of the vector
}
}
};
int main(int argv, char** argc)
{
std::string path = "blah.txt";
fileReader p(path); // don't use new unless you absolutely have to
for (int i=0; i<2; i++)
std::cout<<p.lines[i];
return 0;
}
Note that we no longer have to manage our array memory. Vectors and strings automatically clean up after themselves when they go out of scope. And because we no longer use new to allocate the fileReader, it automatically gets deleted when it goes out of scope. This effectively starts a chain reaction where its members start cleaning up after themselves: the file stream closes, the vectors deallocates its memory after asking its stored strings to clean up and shut down. And the entire program folds over and closes down without us having to write a single line of code to handle it.
char** lines;
Was never allocated any memory!
To be able to do anything meaningful with it, You need to allocate it enough memory to hold the contents that you intend to hold in it.
Also on a sidenote,
You never deallocate the dynamic memory allocated to p by calling delete p; once done with its usage, this gives you an Undefined Behavior.
You never check for return value of standard library functions, You should always do so.
There are many problems in your codes:
char** lines has not been allocated. You need to allocate lines and
lines[i].
You never check if the file is really open. Check fp before using it.
You forgot to close the file pointer at the end. Call fclose(fp).
EDIT :
You are not deallocating lines, lines[i] and p. Be careful, you must use free() for lines and lines[i] and delete for p.
Related
I got an issue with sprintf buffer.
As you can see in the code down below I'm saving with sprintf a char array to the buffer, so pFile can check if there's a file named like that in the folder. If it's found, the buffer value will be assigned to timecycles[numCycles], and numCycles will be increased. Example: timecycles[0] = "timecyc1.dat". It works well, and as you can see in the console output it recognizes that there are only timecyc1.dat and timecyc5.dat in the folder. But as long as I want to read timecycles with a for loop, both indexes have the value "timecyc9.dat", eventhough it should be "timecyc1.dat" for timecycles[0] and "timecyc5.dat" for timecycles1. Second thing is, how can I write the code so readTimecycles() returns char* timecycles, and I could just initialize it in the main function with char* timecycles[9] = readTimecycles() or anything like that?
Console output
#include <iostream>
#include <cstdio>
char* timecycles[9];
void readTimecycles()
{
char buffer[256];
int numCycles = 0;
FILE* pFile = NULL;
for (int i = 1; i < 10; i++)
{
sprintf(buffer, "timecyc%d.dat", i);
pFile = fopen(buffer, "r");
if (pFile != NULL)
{
timecycles[numCycles] = buffer;
numCycles++;
std::cout << buffer << std::endl; //to see if the buffer is correct
}
}
for (int i = 0; i < numCycles; i++)
{
std::cout << timecycles[i] << std::endl; //here's the issue with timecyc9.dat
}
}
int main()
{
readTimecycles();
return 0;
}
With the assignment
timecycles[numCycles] = buffer;
you make all pointers point to the same buffer, since you only have a single buffer.
Since you're programming in C++ you could easily solve your problem by using std::string instead.
If I would remake your code into something a little-more C++-ish and less C-ish, it could look something like
std::array<std::string, 9> readTimeCycles()
{
std::array<std::string, 9> timecycles;
for (size_t i = 0; i < timecycles.size(); ++i)
{
// Format the file-name
std::string filename = "timecyc" + std::to_string(i + 1) + ".dat";
std::ifstream file(filename);
if (file)
{
// File was opened okay
timecycles[i] = filename;
}
}
return timecycles;
}
References:
std::array
std::string
std::to_string
std::ifstream
The fundamental problem is that your notion of a string doesn't match what a 'char array' is in C++. In particular you think that because you assign timecycles[numCycles] = buffer; somehow the chars of the char array are copied. But in C++ all that is being copied is a pointer, so timecycles ends up with multiple pointers to the same buffer. And that's not to mention the problem you will have that when you exit the readTimecycles function. At that point you will have multiple pointers to a buffer which no longer exists as it gets destroyed when you exit the readTimecycles function.
The way to fix this is to use C++ code that does match your expectations. In particular a std::string will copy in the way you expect it to. Here's how you can change your code to use std::string
#include <string>
std::string timecycles[9];
timecycles[numCycles] = buffer; // now this really does copy a string
I am in need of some help with this program. I am in my first ever programming class and have run into wall trying to getting my program to work. I have included what I have written so far but still it doesn't compile. It is giving the error: argument list for class template "std::vector" is missing.
Here is the question:
When you read a long document, there is a good chance that many words occur multiple times. Instead of storing each word, it may be beneficial to only store unique words, and to represent the document as a vector of pointers to the unique words. Write a program that implements this strategy. Read a word at a time from cin. Keep a vector <char *> of words. If the new word is not present in this vector, allocate memory, copy the word into it, and append a pointer to the new memory. If the word is already present, then append a pointer to the existing word.
Below is code snippet:
#include "stdafx.h"
#include <string>
#include <iostream>
using namespace std;
/* Create a vector of char pointers to hold the individual words.
Create a string input to hold the next input through cin. */
int main() {
vector words;
string input;
/* Keep the while loop running using cin as the condition to read an entire document.
This will end when a document has reached its end. */
while (cin >> input) {
/* For every word read as a string, convert the word into a c-string by allocating
a new character array with the proper size and using c_str and strcpy to copy
an identical c-string into the memory heap. */
char* temp = new char[input.length() + 1];
strcpy(temp, input.c_str());
/* Next, check if the word is already in the words array. Use a boolean variable
that updates if the word is found. Compare words by using the strcmp function;
when they are equal, strcmp equals 0. */
bool already_present = false;
for (int i = 0; i < words.size(); i++) {
if (strcmp(temp, words[i]) == 0) {
already_present = true;
}
}
/* If the word is already present, delete the allocated memory.
Otherwise, push the pointer into the words vector. */
if (already_present) {
delete temp;
} else {
words.push_back(temp);
}
}
}
I hope below code snippet could be helpful:
#include <string>
#include <iostream>
#include <string.h> // String.h for strcmp()
#include <vector> // Vector Header file is added
using namespace std;
int main() {
vector <char *> words; // vector of char *
string input;
while (cin >> input) {
char *temp = new char[input.length() + 1];
strcpy(temp, input.c_str());
bool already_present = false;
for (unsigned int i = 0; i < words.size(); i++) {
if (strcmp(temp, words[i]) == 0) {
already_present = true;
}
}
if (already_present) {
delete temp;
} else {
words.push_back(temp);
}
}
/* Print the desired output */
for(unsigned int i=0; i<words.size(); i++) {
cout << words[i] << endl;
}
return 0;
}
Any doubt, comments most welcome.
EDIT: After reading your comments, I came to the conclusion that you use Microsoft Visual Stdio. See, the reason you were getting warning is that strcpy() is potentially unsafe because it can lead to buffer overflow if you try to copy a string to a buffer that is not large enough to contain it.
Consider a code snippet for a moment:
char foo[10]; /* a buffer able to hold 9 chars (plus the null) */
char bar[] = "A string longer than 9 chars";
strcpy( foo, bar ); /* compiles ok, but VERY BAD because you have a buffer overflow
and are corrupting memory. */
strcpy_s() is safer because you have to explicitly specify the size of the target buffer, so the function will not overflow:
strcpy_s( foo, 10, bar ); /* strcpy_s will not write more than 10 characters */
The limitations of this strcpy_s() is that, it is non-standard and MS specific. Therefore if you write code to use it, your code will not be portable any more.
How can I make an array of n strings using char**?
char** lit;
*lit = (char*)calloc(this->nr_param, sizeof(char*));
for(int i = 0; i < this->nr_param; i++)
lit[i] = (char*) calloc(this->nr_param, sizeof(char));
Is this the way?
If so, how can i access elements? Lets say my array will contain the following elements:
aaab, abba, baab;
I want this structure:
lit[0] = "aaab";
lit[1] = "abba";
lit[2] = "baab";
It's ok how I declared them?
Like this:
// allocate memory for n char pointers dynamically.
char ** lit = static_cast<char**>(::operator new(n * sizeof(char*)));
for (unsigned int i = 0; i != n; ++i)
{
lit[i] = static_cast<char*>(::operator new(length_of_string_i)); // #1
// populate lit[i] with data
}
You need some method of determining the length of the ith string, which you need to paste appropriately in the line marked #1. Note that sizeof(char) == 1, so you don't need to multiply anything in the inner allocation.
(You can use std::malloc instead of ::operator new if you prefer, but then you have to #include <cstdlib>.) Don't forget to clean up when you're done!
This is of course only the literal translation of what you asked for. In C++, you would usually prefer object creation over raw memory allocation, which looks like this:
// construct n char pointers dynamically
char ** lit = new char*[n];
for (unsigned int i = 0; i != n; ++i)
{
lit[i] = new char[length_of_string_i];
// populate lit[i] with data
}
But you should seriously never use array-new. It's not a good concept, and rarely good C++.
So, you shouldn't be doing this at all, and instead you should use:
std::vector<std::string> lit(n);
You can use c++ vector and strings in a similar way:
#include <vector>
#include <string>
#include <iostream>
int main() {
std::vector<std::string> lit;
lit.push_back("aaab");
lit.push_back("aab");
lit.push_back("aabb");
lit[0][0] = 'z';
std::cout << lit[0] << std::endl;
}
I am getting heap corruption error while trying to free memory with delete
Here's code
char** split(char* inputstr, char delim, int& count){
char** ostr=NULL;
int numStr = 0;
int i=0,j,index=0;
while(inputstr[i]){
if(inputstr[i++]==delim)
numStr++;
}
if(inputstr[i-1]!=delim)
numStr++;
count= numStr;
ostr = new char*[numStr];
i=0;
while(inputstr[i])
{
j=i;
while(inputstr[j] && inputstr[j] != delim)
j++;
ostr[index] = new char[j-i+1];
//istr[j] = 0;
strncpy(ostr[index], inputstr+i,j-i);
ostr[index++][j-i]=0;
i=j+1;
}
return ostr;
}
for(int i=0,countStr;i<_numComp;i++){
char** _str = split(str[1+i],':',countStr);
message.lastTransList.cmpName[i] = new char[strlen(_str[0])+1];
strcpy(message.lastTransList.cmpName[i],_str[0]);
message.lastTransList.price[i] = atof(_str[1]);
for(int i=0; i<countStr;i++)
{
delete[] _str[i]; //this is working fine
_str[i] = 0;
}
delete[] _str; //exception is thrown at this line
}
I am not able to find the problem. Please help !
It's hard to see any error, there could be something wrong with your indexing that's causing a buffer overrun in the split function that's caught only when you try to delete the char** array.
How about converting to std::string and std::vectors like carlpett recommends (it's a good recommendation).
something like this:
void split(const std::string& str_, char delimiter_, std::vector<std::string>& result_)
{
std::string token;
std::stringstream stream(str_);
while( std::getline(stream, token, delimiter_) ) result_.push_back(token);
}
Then, you just call it with your string, delimiter and an empty std::vector and end up with a populated vector of substrings. You don't have to use new/delete and worry about the memory issues.
I have a problem with simple reading from the file that shares file pointer between a few objects (It works for me with just simple istream, but not when I am using shared pointer of istream pointers).
I am trying to read the whole file to the buffer (file itself is a few lines long.
The code compiles, but throws segmentation fault.
The class that uses shared_ptr:
RecordsSplitter::RecordsSplitter(char *filename):iStream( new ifstream(filename, ifstream::in|ifstream::binary))
{
}
string RecordsSplitter::buildRecord() {
char *buffer;
int buffer_length;
iStream->seekg (0, ios::end)_
buffer_length = iStream->tellg();
cout << buffer_length;
iStream->seekg(0, ios::beg);
iStream->read(buffer,buffer_length);
iStream->close();
cout << buffer;
return 0;
}
int main(int argc, char* argv[]) {
RecordsSplitter *splitter;
splitter = new RecordsSplitter(argv[2]);
int return_num = splitter->buildRecord();
return 0;
}
You declare your buffer but you don't initialise it anywhere.
You need this in your buildRecord function or a use of malloc if you so desire.
buffer = new char[buffer_length];
Your seg fault is caused by this uninitialised pointer
Don't forget to clean up!
delete[] buffer;