FIXED: Access Violation Reading Location (pointer to string array) - c++

FIXED: http://pastebin.com/71QxqGk5
first post/question.
So this is C++ and I am trying to print an array of words.
#include <cstdlib>
#include <iostream>
#include <fstream>
#include <string>
#include <cstring>
#include <cctype>
#include <ctime>
using namespace std;
//structs
struct Input
{
int size;
string* word;
bool is_palindrome[];
};
//prototypes
bool openInputFile(ifstream &ifs);
void File_to_Array(string* word, int &size);
void PrintArray(string* word, int size);
//main
int main()
{
Input myInput = { 0, nullptr, false };
File_to_Array(myInput.word, myInput.size);//copy arr and get size
cout << myInput.word; //this outputs 00000000
cout << *myInput.word; //this breaks and throws exception as commented below
//Exception thrown at 0x0098BB6B in Project1.exe: 0xC0000005: Access violation reading location 0x00000014.
PrintArray(myInput.word, myInput.size);//print array of strings
system("PAUSE");
return 0;
}
//functions
bool openInputFile(ifstream &ifs)
{
string filename;
cout << "Enter the input filename: " << endl;
getline(cin, filename);
ifs.open(filename.c_str());
return ifs.is_open();
}
void File_to_Array(string* word, int &size)//copies file to dyn arr and assigns size from first elem
{
ifstream myFile;
while (!openInputFile(myFile))
cout << "Could not open file" << endl;
string tempstr = "";
getline(myFile, tempstr);//first line is size of dyn arr
size = stoi(tempstr);//now we have max size of dyn arr of strings
word = new string [size];//now we have the array of strings, *word[index] = string1
int i;
for (i = 0; getline(myFile, word[i]) && i < size; ++i);//for each line
//copy line of string from file to string arr within "bool" test, second param of for loop //copying done
size = i;
myFile.close();//done with file, no need, close it
}
void PrintArray(string* word, int size)
{
//for (int i = 0; i < size; ++i)
//cout used to be here, but now its in main, for debugging
}
So I'm wondering if my problem is with passing a member of a struct, and if I should have instead passed the entire struct type "myInput" into the functions and use the -> operator to access the members of myInput.
below is an example of a text file
5
month
Runner
NEON
digit
ferret
nothing
the 5 would be the size of the dynamically allocated array, the rest are strings, as you can see there are 6 strings, so I have in the for loop a test for whether the file is still transferring strings to the array.

This part of the File_to_Array is causing the problem:
word = new string [size];
You think that you are setting the pointer of myInput object to point to the string array, but you're not. When you pass the pointer to the function here:
File_to_Array(myInput.word, myInput.size)
^^^^^^^^^^^^
you are really passing a copy of the pointer. So inside the File_to_Array, this copy is re-pointed to the newly-created string array, but the real pointer inside myInput is not changed. You should pass a reference to the pointer instead:
void File_to_Array(string*& word, int &size)
\___________/
^--reference to a pointer
I would also suggest you to use a vector[string] instead. Finally, your bool is_palindrome[]; member and it's initialization look very strange, but it's hard to comment further since they are never used in the code.

Related

Expected Primary-Expression before ']' token?

I'm trying to be able to call a function with the vector and for some reason it's saying "expected primary expression before ']'. The vector could hold any number of files, depending on the amount of numbers in myfile, so I'm not sure what I should put there.
#include <fstream>
#include <string>
#include <vector>
#include <iostream>
using namespace std; // not recommended
double averageCalc(string[],int);
int main () {
double average;
string line;
ifstream myfile ("array_pgmdata.txt");
//int index = 0; // not needed
//string myArray[index]; // UB - if it even compiles, it's a VLA of size 0.
std::vector<std::string> myArray; // use this instead to be able to grow it
// dynamically
if (myfile) // open and in a good state
{
// while (! myfile.eof() ) // It'll not be eof when you've read the last line
// only when you try to read beynd the last line,
// so you'll add "line" one extra time at the end
// if you use that. Use this instead:
while(getline(myfile, line))
{
// myArray[index++] << line; // you have 0 elements in the array and
// can't add to it in any way
myArray.push_back(line);
}
}
else cout << "Unable to open file";
for(size_t idx=0; idx < myArray.size(); ++idx) {
std::cout << myArray[idx] << "\n";
}
average = averageCalc(myArray[], line); // error here
return 0;
}
double averageCalc(string nums[], int count)
{
int a, total, elements, averaged1, averaged2;
// string averaged2;
for(a = 0; a < count; a++)
{
total+=a;
elements++;
}
averaged1 = total / elements;
return averaged2;
}
There's a few problems here. Firstly, your function averageCalc expects a parameter of type string[] which is an array of strings. When you call the function, you are trying to pass it a std::vector<string>, which is not an array of strings, it is a class. Presumably, you would want to change your function to take in a vector, like so:
double averageCalc( const std::vector<string> & nums ); // no need for size now
The other issue you have is in calling your function. When you call it, you pass myArray[] as a parameter, which is the error you compiler is giving you. This is not valid syntax, you simply want to pass in myArray.
I think that the error occurs becase firstly you create the array with std::vector<std::string> myArray; so the data is string type but when you want to calculate the average value the function expects a value int, double etc. in order to perform math. Either change the string to int or use a function to convert it:
int main()
{
string s = "12345";
// object from the class stringstream
stringstream geek(s);
// The object has the value 12345 and stream
// it to the integer x
int x = 0;
geek >> x;
// Now the variable x holds the value 12345
cout << "Value of x : " << x;
return 0;
}

Reading number list from file to a dynamic array

I'm having trouble reading a number list from a .txt file to a dynamic array of type double. This first number in the list is the number of numbers to add to the array. After the first number, the numbers in the list all have decimals.
My header file:
#include <iostream>
#ifndef SORT
#define SORT
class Sort{
private:
double i;
double* darray; // da array
double j;
double size;
public:
Sort();
~Sort();
std::string getFileName(int, char**);
bool checkFileName(std::string);
void letsDoIt(std::string);
void getArray(std::string);
};
#endif
main.cpp:
#include <stdio.h>
#include <stdlib.h>
#include "main.h"
int main(int argc, char** argv)
{
Sort sort;
std::string cheese = sort.getFileName(argc, argv); //cheese is the file name
bool ean = sort.checkFileName(cheese); //pass in file name fo' da check
sort.letsDoIt(cheese); //starts the whole thing up
return 0;
}
impl.cpp:
#include <iostream>
#include <fstream>
#include <cstring>
#include <stdlib.h>
#include "main.h"
Sort::Sort(){
darray[0];
i = 0;
j = 0;
size = 0;
}
Sort::~Sort(){
std::cout << "Destroyed" << std::endl;
}
std::string Sort::getFileName(int argc, char* argv[]){
std::string fileIn = "";
for(int i = 1; i < argc;)//argc the number of arguements
{
fileIn += argv[i];//argv the array of arguements
if(++i != argc)
fileIn += " ";
}
return fileIn;
}
bool Sort::checkFileName(std::string userFile){
if(userFile.empty()){
std::cout<<"No user input"<<std::endl;
return false;
}
else{
std::ifstream tryread(userFile.c_str());
if (tryread.is_open()){
tryread.close();
return true;
}
else{
return false;
}
}
}
void Sort::letsDoIt(std::string file){
getArray(file);
}
void Sort::getArray(std::string file){
double n = 0;
int count = 0;
// create a file-reading object
std::ifstream fin;
fin.open(file.c_str()); // open a file
fin >> n; //first line of the file is the number of numbers to collect to the array
size = n;
std::cout << "size: " << size << std::endl;
darray = (double*)malloc(n * sizeof(double)); //allocate storage for the array
// read each line of the file
while (!fin.eof())
{
fin >> n;
if (count == 0){ //if count is 0, don't add to array
count++;
std::cout << "count++" << std::endl;
}
else {
darray[count - 1] = n; //array = line from file
count++;
}
std::cout << std::endl;
}
free((void*) darray);
}
I have to use malloc, but I think I may be using it incorrectly. I've read other posts but I am still having trouble understanding what is going on.
Thanks for the help!
Your use of malloc() is fine. Your reading is not doing what you want it to do.
Say I have the inputfile:
3
1.2
2.3
3.7
My array would be:
[0]: 2.3
[1]: 3.7
[2]: 0
This is because you are reading in the value 1.2 as if you were rereading the number of values.
When you have this line:
fin >> n; //first line of the file is the number of numbers to collect to the array
You are reading in the count, in this case 3, and advancing where in the file you will read from next. You are then attempting to reread that value but are getting the first entry instead.
I believe that replacing your while() {...} with the code below will do what you are looking for.
while (count != size && fin >> n)
{
darray[count++] = n; //array = line from file
std::cout << n << std::endl;
}
This should give you the correct values in the array:
[0]: 1.2
[1]: 2.3
[2]: 3.7
You appear to be writing the next exploitable program. You are mistakenly trusting the first line of the file to determine your buffer size, then reading an unlimited amount of data from the remainder of the file into a buffer that is not unlimited. This allows an evil input file to trash some other memory in your program, possibly allowing the creator of that file to take control of your computer. Oh noes!
Here's what you need to do to fix it:
Remember how much memory you allocated (you'll need it in step #2). Have a variable alleged_size or array_length that is separate from the one you use to read the rest of the data.
Don't allow count to run past the end of the array. Your loop should look more like this:
while ((count < alleged_size) && (cin >> n))
This both prevents array overrun and decides whether to process data based on whether it was parsed successfully, not whether you reached the end-of-file at some useless point in the past.
The less problematic bug is the one #bentank noticed, that you didn't realize that you kept your position in the file, which is after the first line, and shouldn't expect to hit that line within the loop.
In addition to this, you probably want to deallocate the memory in your destructor. Right now you throw the data away immediately after parsing it. Wouldn't other functions like to party on that data too?

Passing structure by reference and assign string

Here is a simple program where I am trying to pass a structure to a function by reference and a string. The function is supposed to detect the length of the string and assign it a member of the structure. Here is the program:
#include <iostream>
#include <string.h>
struct stringy // structure definition
{
char *str;
int ct;
};
void set(stringy &beany, const char *testing); // function definition
int main()
{
stringy beany;
char testing[] = "Reality isn't what it used to be.";
set(beany, testing); // function call
return 0;
}
void set(stringy &beany, const char *testing) // function prototype
{
int i=0;
while (*(testing+i) != '\0') // this loop counts the number of characters
{
i++;
std::cout << i << "\n";
}
beany.str = new char[i]; // dynamic storage allocation
std::cout << strlen(beany.str); // printing the length of the string
}
For some reason the output of the last line in the function set() is 47 while the value of "i" is 33. The last 15 bytes are filled with garbage value. I want that the length of beany.str should be equal to the length of *testing.
You allocate memory for beany.str but you don't initialize that memory. The contents of the allocated memory, without any initialization, is indeterminate (and in practice will be seemingly random).
Also don't forget that old C-style strings needs to be terminated by the special '\0' character (or functions like strlen will not work).
Both of these problems, using uninitialized memory and forgetting the terminator, will lead to undefined behavior.
beany.str = new char[i]; // dynamic storage allocation
std::cout << strlen(beany.str); // printing the length of the string
strlen looks for the terminating null character '\0'. There is no guaranteed one in beany.str, because you assign it the result of new char[i], which does not zero-initialize the elements. It allocates space for i characters that are not initialized to zero.
Even if they were, strlen would return 0, because it would immediately find '\0' at the first position. If you don't somehow remember i yourself, the size information will be lost.
Look at the output of the following program:
#include <iostream>
int main()
{
char *str = new char[100];
for (int i = 0; i < 100; ++i)
{
std::cout << str[i] << "\n";
}
}
The behaviour is undefined. What you will probably see are some seemingly random characters.
If you want zero-initialization, use new char[i]().
But still, strlen will be 0:
#include <iostream>
#include <string.h>
int main()
{
char *str = new char[100]();
for (int i = 0; i < 100; ++i)
{
std::cout << str[i] << "\n";
}
std::cout << strlen(str) << "\n";
}
You should just get rid of array-new and array-delete. Use std::string.

How to copy an array of characters to a string C++

I am writing a function that takes in a string through pass by reference and an array of characters and the size of the array. The string already has characters in it. I am trying to erase the characters in the string and copy the characters from the array.
I tried setting up a for loop to copy, but it doesn't work if the string is too small or too big. I can't use strcopy in this function. Need some guidance.
void functionname(string &first, char arr[], int size) {
int i;
(for i = 0; i < size; i++) {
first[i] = arr[i];
}
}
You can use std::string's default assignment operator = and simply do
first = arr;
std::string has function to do it first.assign(arr, size)
The below works as std::string overrides the assignment operator (=) for char* to allow direct assignment to the string from a character pointer.
#include <iostream>
#include <string>
#include <cstring>
using namespace std;
void functionname(string &first, char arr[], int size)
{
first = arr;
}
int main()
{
std::string x = "mystring";
char buff[x.length()];
strcpy(buff, "other");
cout << x << endl;
functionname(x, buff, x.length());
cout << x << endl;
return 0;
}
string has a constructor that copies a character array and takes a count. This will work no matter what contents are inside the arr array, even embedded null characters.
void functionname(string &first, char arr[], int size) {
first = string(arr, size);
}
Again, the contents of arr are copied into the string, you don't need to keep arr around after this if you don't need it anymore.

pull "firstword secondword" from text file into single char array

I am getting a segmentation fault: core dumped error when I am reading in players file..
I am trying to add both "firstname lastname" to the player struct. I am trying to access the "0th" people and increment their name because i need both first and last, i cant simply fin >> people[i].name in a simply for loop as i do for the card value (not shown) "heart two 2" for example
// deck of cards
// below are initializations
#include <iostream>
#include <fstream>
#include <ctime>
#include <stdlib.h>
#include <string>
using namespace std;
//globals
const int maxCards = 52;
//Structs
struct card {
char suit[8];
char rank[6];
int cvalue;
char location;
};
struct player {
char name[];
int total;
card hand[];
};
//program
int main()
{
char tempfName[100];
char templName[100];
//create struct array(s)
card deck[52];
card shuffledDeck[52];
player people[4];
//set defalt values
for(int i=0;i<4;i++)
{
strcopy(people[i].name,"first last");
}
//open player names file
ifstream fin2;
string fin2Name;
//get file name from user
cout << "Enter player file name...(Players.txt)" << endl;
getline(cin,fin2Name);
fin2.open(fin2Name.c_str());
//check if Players.txt opens correctly
if(!fin2.good())
{
cout << "Error with player file!" << endl;
return 0;
}
else
{
int j =0;
//fin2 >> people[j].name; //prime file
while(fin2.good())
{
//find the length
int index =0, length=0;
while(tempfName[length] != '\0')
{
length++;
}
//now add space after first name
tempfName[length] = ' ';
length++;
while(templName[index] != '\0')
{
tempfName[length] = templName[index];
length++;
index++;
}
tempfName[length]='\0';
int counter =0;
while(templName[counter] != '\0')
{
people[0].name[counter] = templName[counter]; //testing program on "0th" people
counter++;
}
}
}
}
In your struct, name[] and hand[] are of undetermined size. It's hence difficult to read anything into them.
Then, once you've opened the stream, you're trying to determine the length of the unitianalized tempfName[]. This ain't no good: you're not sure it's null terminated and you'll go out of bounds ! This is the origin of your segfault.
Consider initalizing these by declaring them as:
char tempfName[100]{};
char templName[100]{};
Once this is fixed, your code still loops forever on while (fin2.good()) without reading anything, and bravely adding one whitespace to tempfName until you're out of bound.
Now suppose you'd fix all this, set a length to your name and undcomment your stream reading fin2 >> people[j].name; you'd still have a very risky situation: if the data would be longer that what you've foresseen, it would be truncated and the name wouldn't have a terminating '\0'.
Recommendation 1:
Consider using std::string instead of char[] whenever you consider storing a string. Example:
struct player {
string name = "first last" ; // initialisation value: no strcpy() needed !!
int total;
card hand[5]; // length ?
};
Recommendation 2:
Loop using your stream reading as loop condition:
while (fin2 >> people[j].name) { ///!!!
...
j++; // don't foget to increment your counter
}
However be carefull, because the >> will read one string at a time, the string ending at first whilespace (so only firstname).
If you adopt recommendation 1, it would be easy to write:
while (fin2 >> tempfName >> templName) { ///!!!
people[j++].name = tempfName + " " + templName;
}
which should perform pretty muchthe same thing that your loop, but with far less instructions and risks.
Recommendation 3:
If your number of players is fixed, define the max constant and use a for instead of a while to read your data:
const int max_player = 4;
player people[max_player];
...
for (j=0; j<max_player && (fin2 >> people[j].name); j++) // instead of the former while
If your limit of 4 was arbirary, consider using vectors. But that's another story for the moment.
Your struct player definition is not valid:
struct player {
char name[];
int total;
card hand[];
};
The C string fields name and hand need to have a length, e.g.
struct player {
char name[32];
int total;
card hand[32];
};
Your compiler should be giving you an error for this ("incomplete type").
Note also that since you are writing C++ code then it would be better to use std::string rather than C-style char * strings - it will be easier, more robust, and you won't be mixing C and C++ idioms.