cin.getline questions

So I have to write a program that will open a users file then load an array with the contents of the array, and I must use cin.getline() to do this the issue is, when I run this I get an error message that says:

Error: reading characters of string

this is the code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#include <iostream>
#include <string>
#include <fstream>
using namespace std;

int load(char *s[])
{
	int count = 0;
	char *temp[100];
	string file, line;
	ifstream infile;

	cout << "Enter the file name including .txt: " << endl;
	cin >> file;

	infile.open(file, fstream::in);

	if (!infile)
	{
		cout << "File not found" << endl;
	}
	else
	{
		cin.getline(*temp, count, '\n');

		count++;
	}



	return count;
}

int pairs(char *s[], int count, char *two[])
{
	return 0;
}

int main()
{
	char *temp[100];
	int count = 0;

	count = load(temp);
}


the code that is having the issue at is inside the load function.. Any help is much appreciated.. thanks in advance
You're supposed to pass the pointer.
1
2
//Here you are passing a character
cin.getline(*temp, count, '\n');


Just delete that asterisk. Also, be wary of mixing cin >> FOO and cin.getline. cin >> FOO actually leaves a newline character in the buffer that cin.getline will catch.

Edit:
Also, isn't the data coming from the file, so you should be using:
 
infile.getline(temp, count, '\n');

instead?
Last edited on
Thanks that worked!! Yeah I thought it would be that too but my professor strictly said to use cin.getline for some reason.

What loop function should I use to get all the contents of the file and stop at the very end? I tried a while loop with the conditions of it being !infile.eof() but when I use a debugger on it it seems to just be stuck in the loop forever

Here is what I have:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
int load(char *s[])
{
	int count = 0;
	char *temp = new char[];
	string file, line;
	ifstream infile;

	cout << "Enter the file name including .txt: " << endl;
	cin >> file;

	infile.open(file, fstream::in);

	if (!infile)
	{
		cout << "File not found" << endl;
	}
	else
	{
		while (!infile.eof())
		{
			cin.getline(temp, count, '\n');

			count++;
		}
	}



	return count;
}


Line 19 is where I have my loop but like I said it just tends to be in an infinite loop
It is an infinite loop because infile never reaches the end of the file. You aren't reading from the file, so infile is never changed. Usually when you have a check like that, it is because you are reading from the file, not the console, e.g.
1
2
3
4
5
6
unsigned I(0);
while(infile.good()){
    infile.getline(temp, count, '\n');
    s[I++] = temp;
//Alternatively, infile.getline(s[I++], count, '\n');
}


There are other issues I see:
-Line 4 looks very suspicious. You need to specify how much space you're allocating.
-You increment count with each iteration but also use count as the number of characters to read. What if the user enters a string longer than what the array can hold? You'll be writing over memory you shouldn't.
-Your variable s isn't used at all.

Here is what I'm guessing your function is supposed to do:
Read lines from a file, storing each line in an array of C-strings via the parameter, and return the number of lines read.
If so, try the following:
(Note that I use this magic "150" in the following examples. It means nothing other than to make sure the array has enough room for the strings. You are free to use any value you'd like.)
-First do a quick, empty read to count the number of lines.
1
2
3
4
5
unsigned int line_count(0);
while(infile.good()){
    infile.ignore(150, '\n'); //Ignore the information; it is like reading in data then discarding immediately1
    ++line_count;
}

-Then, allocate according to the number of lines and reread the file, this time storing the elements:
1
2
3
4
5
6
//This is pretty messy
char (*s)[150] = new char[line_count][150];
    //char (*s)[150] is a pointer to an array of C-strings, or pointer to an array of char[150]
infile.seekg(0); //Reset position to the beginning of the file2

//Now reread the file 

And don't forget that once you're done using the new strings, you have to free the memory you allocate.
 
delete[] s;


Honestly, I really don't like that code (I had to mess with it a couple times to make sure I had it right), and it'd probably be better for your sanity to use std::string.3

1http://www.cplusplus.com/reference/istream/istream/ignore/
2http://www.cplusplus.com/reference/istream/istream/seekg/
3http://www.cplusplus.com/reference/string/string/

Edit:
Added a bit more explanation.
Last edited on
yeah that is exactly what I have to do thank you for the explanation and I will be sure to read these links also to get a better understanding thank you
Okay so I got it semi working but I ran into another problem here... My file is just pretty simple and small so I can test it and my data is this:

One
Two
Three
Four
Five

when I run my program the output is just:

Five
Five
Five
Five
Five

this is my updated code: there were some errors that I ran into when I wrote the code you said up top so I sort of fixed it up to where there was no errors inside of it but here it is:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
#include <iostream>
#include <string>
#include <fstream>
using namespace std;

int load(char *s[])
{
	int count = 0;
	int line_count = 0;
	string file;
	ifstream infile;

	cout << "Enter the file name including .txt: " << endl;
	cin >> file;

	infile.open(file, fstream::in);

	if (!infile)
	{
		cout << "File not found" << endl;
	}
	else
	{
		while (infile.good())
		{
			infile.ignore(150, '\n');
			line_count++;
		}

		char *temp = new char[line_count];
		infile.seekg(0);

		while (infile.good())
		{
			infile.getline(temp, 150, '\n');
			
			s[count] = temp;

			count++;
		}
	}

	for (int i = 0; i < count; i++)
	{
		cout << s[i] << endl;
	}

	return count;
}

int pairs(char *s[], int count, char *two[])
{
	return 0;
}

int main()
{
	char *temp[100];
	int count = 0;

	count = load (temp);
}
This problem is because you're overwriting the same space and (most importantly), you're only storing one line.
Look carefully at lines 30 to 40.

What actually happens:
-You allocate a string that has the same number of characters as there are lines
--This is okay, but it probably wouldn't end well if your file only had three lines or less.
-Within your loop, you assign the pointer temp to s[count].
--Now, the important thing to note here is that temp itself is never changed, therefore all of the elements in your array s are actually pointing to the same exact spot.
-The fact that temp never changes also creates another problem.
--You read in the line and store it in the array temp points to, but since you're reusing the same array, you're overwriting the old data.

What you can do is actually allocate new memory with each iteration:
30
31
32
33
34
35
36
37
38
39
40
		infile.seekg(0);

		while (infile.good())
		{   //Start each iteration with a fresh, new array
                        char *temp = new char[150];
			infile.getline(temp, 150, '\n');
			
			s[count] = temp;

			count++;
		}


Another issue is that you forget to free the memory at the end of the program. When you allocate memory, you are requesting space to be reserved for your data. That means nothing else is allowed to touch it. However, it is also your responsibility to tell the computer that you're done with it, otherwise it will continue to sit as reserved memory. (Actually the OS is probably smart enough to clean up all the memory when the program is over, but don't depend on the OS to do your work!)
Not freeing your memory is known as a "memory leak".
62
63
64
65
//Be careful with this. Only use this specific code if you've added some code to
//    initialize temp with null pointers
for(unsigned i(0); i < 100; ++i)
        delete[] temp[i];




Extra information (you don't have to read this):
Normally, I'd say this allocation is not needed, because you have no way of knowing how long the line will be (unless you go crazy with rereading each line), so it'd probably be sufficient for you to do:
1
2
3
char temp[150] = "\0";
infile.getline(temp, 150, '\n');
s[count] = temp;


However!... There is one major issue if you attempt to use the above code. The types of s and temp no longer match.

Type of s[count] == char*
Type of temp      == char[150]

The compiler probably and will spit out an error message.

Lets take a look at line 58, where you actually declare your original array:
 
char *temp[100];

There is actually a very big difference between that and this:
 
char (*temp)[100];

Here's the difference:
-The first is an array of pointers
-The second is a pointer to an array

Now this really comes down to intention. When you declared temp on line 58, what was that 100 for? Is it supposed to the maximum number of strings you want to hold? Or is it supposed to be for the maximum size of your individual strings? In other words, do you want to hold an array of 100 strings whose sizes are unknown or hold an array of strings 100 characters long?
Last edited on
So from the instructions is says:

Function 1:
A function that is given an (empty) array of c-string pointers (an array of 'char *' elements) that fills up that array and returns the number of c-strings

Function 2:
A function that is given an (full) array of c-string pointers, and the number of c-strings, as well as an (empty) array of pointers to c-string pointer/line-number pairs, that fills up that array and return the number of pairs.

Function 3:
A function that takes an (filled) array of pointers of c-string-pointers/line-number pairs, and the number of pairs, as well as a second (empty) array of pointers to c-strings-pointer/line-number pairs, and fills up the second array with the same pointers re-ordered so that the c-strings are in alphabetical order.

Function 4:
This just display a selected data and line.

To simplify the assignment, use fixed-length arrays of pointers. For the list of text lines, use an array of 100, and for the list of word/line-number pairs, use an array of 1000.

So do all 3 functions just take an array of pointers?.. Thanks for your help by the way I didn't realize how in depth arrays and pointers can be

Edited:
For function arrays
Last edited on
So do all 3 functions just take an array of pointers?..

Yes. It looks like you're doing alright so far, so I don't think you'd have much trouble with the rest of the functions.

Though I am slightly surprised at your function 2 assignment.
You function declaration on line 51:
int pairs(char *s[], int count, char *two[]);
I am hesitant to say that this incorrect, because I am not entirely sure what your instructor means by "pair".
Because, for all I know, your instructor may simply want you to append each string with the like number, so

One
Two

becomes

1. One
2. Two

But then again, C++ has std::pair, which would mean the declaration could look like:
int pairs(char *s[], int count, std::pair<int, char*> twos[]);
But I really doubt your instructor actually wants a two-type pair.
Yeah I think the pair is like you said just put a number in front of them the full instructions for function 2 says:

Function 2:
A function that is given an (full) array of c-string pointers, and the number of c-strings, as well as an (empty) array of pointers to c-string pointer/line-number pairs, that fills up that array and return the number of pairs. The intent is to take the list of lines of text, extract the words, and build a list of pairs that correspond to each word and its line number. (The line number is just the array index plus one). For this assignment, to keep it simple, we will call a 'word' a consecutive sequenced of visible characters, bounded by spaces, tabs, or new-lines ("whitespaces").

So I am guess that if a user enters a file that has two or more words in one line we just break them up into separate words like:

Hello how are you

would get broken into

1. Hello
2. how
3. are
4. you

at least that is how I understand it? I might ask him tomorrow just to be 100% sure
From what I understand if your text file has:

Hi there
This place is cool

The pairs function would create:

1. Hi
1. there
2. This
2. place
2. is
2. cool


Where this time you're breaking up the line into individual words and each word is marked with the line number it belonged to.
OHHHHH damn that is brilliant haha thanks for all the help!!!
what is the best way to copy this c-string over to a temp array so I do not change the original? I tried to use the:

strcpy(temp, *s)

but when I do this the orignal would be:

One Two Three Four

and the new one gets

O
n
e

T
w
o

F

I am just having trouble getting it over to the new one now
Remember to pass pointers and to make sure the destination has enough space.
1
2
3
4
const char* str = "Hi";

//str ~ pointer (type is const char*)
//*str ~ dereferenced, so not a pointer (type is const char) 
Last edited on
Topic archived. No new replies allowed.