Robert J Robert J - 2 months ago 22
C++ Question

C++ readline and write to file (line sanitation)

I seem to be running into some odd issues with a portion of my code that involves reading a line from an existing file and writing a portion to another file:

Here is an example of what I am seeing (I only want the vowels).

image

Here are my three functions involved with this. I got a little

.c_str()
happy while trying figure out the cause:

void do_file_magic(string file){
fstream source;
string outfile,
line,
vowels,
temp;

// Name the outfile
outfile = "vowels_" + file;

source.open(file);
if (!source.is_open()) {
die_a_clean_death("Unable to open source file:", file);
};

ofstream destination(outfile);
if (!destination.is_open()) {
source.close();
die_a_clean_death("Unable to open destination file:", file);
};

// read source file and output vowels to destination file.
do {
for (int i = 1; !source.eof(); i++ ){
getline(source, line);
temp = vowels_on_a_line(line) + "\n";
destination << temp.c_str();
};
} while (!source.eof());

// Close the files
source.close();
destination.close();
};

string vowels_on_a_line(string input){
int input_size = input.size(),
vowel_counter = 0;

// this will not be larger than input_size
char vowelarray[input_size];

// find the vowels with the vowel test
for (int i = 0; i < input_size; i++){
if (vowel_test(input[i])){
vowelarray[vowel_counter] = input[i];
vowel_counter++;
};
};

// convert array to string
string vowels(vowelarray);

// return the stringi
printf("%s\n", vowels.c_str());
return vowels;
};

bool vowel_test(char c){
if(
c=='a'||c=='A'||
c=='e'||c=='E'||
c=='i'||c=='I'||
c=='o'||c=='O'||
c=='u'||c=='U'
) {
return true;
} else {
return false;
};
};


Does anyone see what I am doing wrong here?

Here is terminal output while running this. I note that there is
?U?
in lieu of text editor output:

Mac Shell: Homework2/>$ ./Homework2

Enter a filename:
-----------------
test.txt
oeiuooiaeoeeuaiiieiaeeaiiaoeiea
uueeaoaeaoiouaiueeiiuaeeeueiiueia?U?
uuoeuaeoeiiuoeeauueuiuioiiuieiuuaaoi?
aeueeieoioooeauaieoaiuiaeuaoeuaiiu?U?
oieuuuiiauoeuoiiaeieieiaeuaaiii
UeaooaiuaeuueieieiauiiaIeeoioeieiiue?
aueuuuuaueieuiaaeuaauaeeeaeeeeuee?U?
aauueiuauaiuoeieeoeeooiiuiiaiaueiuuo?
aeieeaiaieouo

auiooiiaeauiaeuuuaeeuouuaaauoua
eueuoeeuiaeeuuaoiiiuoeieuiuaue
iaeeoaoiaieoiauiuauouiaeiaeuuoi
eueeeueeeiueeieuioauieeuaeuaa
?
iaueeiaeeeueuaoeauueuiauiiauiuieuu?U?
eeeueeeoaeuoioiuIauioeieueiua
eeeuiiieaeeoiiuioueiaoaiuaaiiai
aeaiaeiuauaeeauieoiaeeiiuieeeuui??U?
aiuaaaeuaaoooiouiaiaaiueaeuaa
?
aeeeueuouauueauaeeuUeeoieueioioeua?U?
eeaueueiuaaeuuuooeeeiuaeuuiie
auiieuioeuaaaaieieeeeuiaiieieeuIee?U?
aeaieaeiiaeuaoeauieiuaeueieeeeueua?U?
uoueuuuiaai

euaeioaeuieuiaeaiiaiaeoiouaiuaeeeuauue
iauoieuauiuaeauaoeAeeaiiauiuUeaiueoe?
eaiiaeieiuuoueaeeieuuaoeaeeaiuuaea#

iieuoeuaeeaauEiauiieuaoeaiueaaeoi?U?
auiaeaeiaeeuiauioeiieiieaaoeeuioeeu

uieueeeueuieoeuauiieauieeiueaiueuiiU?
eiuuoiuiieooaaiuiauoaeeiuaiaeuio??U?
H?U?
Mac Shell: Homework2/>$

Answer

There are multiple bugs in the shown code.

   for (int i = 1; !source.eof(); i++ ){
         getline(source, line);

Checking for eof() in a loop condition is always a bug.

 char vowelarray[input_size];

 // You put something into vowelarray.

 string vowels(vowelarray);

The shown code instantiates the vowelarray. The vowelarray is not initialized. The subsequent code then proceeds to fill the initial contents of vowealarray.

Passing vowelarray to std::string's constructor decays the char array to a const char *.

The const char * parameter to a std::string constructor must be a `\0'-terminated string.

The shown code fails to terminate the string with a \0 byte. As such the resulting string will typically contain random garbage, which is what you're seeing.

You need to increase the maximum size of the array by 1, in order to account for an extra '\0' character:

char vowelarray[input_size+1];

And then properly add a terminating '\0' to the char array, before constructing a std::string from it.