Char * buffer to vector<char> compile errors

Hi guys. I am *sorta* new to C++ and sorta not. This is the first serious attempt I have made at trying to understand and implement functions and code. The following program was *designed* to read a text file into ifstream, format the data in the buffer, and write to an output file.

It's a bit of a mess. I realize it's probably very clunky and convoluted. My biggest issue has been with the buffer. My assumption is that at some point it will be doing operations on very large files, and I am not quite sure what I am doing with vector. The whole idea is to have a buffer that can be dynamically allocated but this absolutely refuses to compile. What am I doing wrong here? To clarify the type of data being read into the buffer is meant to basically be one gigantic string literal, the only formatting I would be doing is removing HTML tags for smilies embedded in Facebook posts and increasing the character count in the output file instead, something I will have to figure out later.

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
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <stdio.h>
#include <new>

int main(char argc, char* argv[])
{
	using namespace std;
	string ofileap = NULL;
	string infileap = NULL;
	cout << "Please enter absolute path to input file." << endl;
	cin >> infileap;
	ifstream infile;
	infile.open(infileap);
	if (infile.is_open())
	{
		infile.seekg(0, infile.end);
		long size = infile.get();
		infile.seekg(0);
		char * buffer = new char[size];
		vector<char> postbody;
		postbody.assign (buffer);
		infile.read(*postbody, size);
	/*	if (postbody == NULL)
			{
			cout << "Pointer postbody evaluated to NULL. Check input file." << endl;
			exit(0);
			}        */
		cout << "Input file opened successfully. Creating output file..." << endl;
		ofstream outfile;
		cout << "Please enter a name for output file, absolute path optional: " << endl;
		cin >> ofileap;
		outfile.open(ofileap, ios::app);
		if (outfile.is_open())
		{
			
			strtok(postbody, " !.*'/");
			cout << "Enumerating words..." << endl;
			// printf(postbody, "%s\n" ) >*postbody;
			outfile.write(postbody, size);

			outfile.close();
			infile.close();
		}
		else cout << "Output file failed to open.";

	}
	else cout << "I/O Failed.";

	return 0;
}
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
#include <iostream>
#include <string>
#include <fstream>
#include <regex>

int main()
{
    std::string infile_name ;
    std::cout << "Please enter absolute path to input file.\n" ;
    std::getline( std::cin, infile_name ) ;

    if( std::ifstream infile{ infile_name } )
    {
        std::string outfile_name ;
        std::cout << "Please enter path to output file.\n" ;
        std::getline( std::cin, outfile_name ) ;

        if( std::ofstream outfile{ outfile_name, std::ios::app } )
        {
            std::string line ;
            while( std::getline( infile, line ) ) // for each line in the input file
            {
                // extract the words in the line and write them to the output file
                // word character (alphanumeric character) repeated one or more times
                static const std::regex words_re( "\\w+" ) ;

                // http://en.cppreference.com/w/cpp/regex/regex_iterator
                std::sregex_iterator iter( line.begin(), line.end(), words_re ) ;
                const std::sregex_iterator end {} ;

                for( ; iter != end ; ++iter ) outfile << iter->str() << '\n' ;
            }

            return 0 ; // EXIT_SUCCESS
        }

        else std::cerr << "could not open output file\n" ;
    }

    else std::cerr << "could not open input file\n" ;

    return 1 ; // EXIT_FAILURE
}
This is great, thanks! Regexp functions make a lot of sense, I guess I never thought of that which is funny considering how often I have piped command outputs to regexp in bash or Windows...I realize it's most likely possible to do this as a shell/batch script but am hoping to add many more functions as I learn.

I still have questions about the buffer, though. I was getting a lot of compiler errors telling me I couldn't pass a type char to an object requiring type char*, and vice-versa depending on how I had done it (OP included source that was modified from the original in case I could salvage the old way somehow).
In the original code, we have: char * buffer = new char[size];
The type of buffer is 'pointer to char'

To pass a char* to a function, pass buffer (not *buffer)
For example: infile.read( buffer, size ); // read up to size characters
Looks like I let that slip through the cracks...that said I had tried that syntax in an earlier version and I was getting errors about it needing to have a constant value at compile. I think I was trying to see if I would get a different error or anything that would shine some light on why the compiler couldn't understand that the buffer size was to be determined by the size of the infile given by the line long size = infile.get();. I expected problems at some point but it seemed no matter what I did, Visual Studio wasn't at all having it. It was also pitching a fit about using strtok(postbody, " !.*'/"); not allowing me to compile with the demand I use strtok_s only to find out it won't accept the same arguments passed and isn't portable across all platforms. I had to include a preprocessor directive to forcibly ignore the compiler error after trying several workarounds. My computer isn't available to me right now but later I can share the error VS was giving me. I am pretty sure I got something messed up but don't know what yet.

edit: here is the first version of the source
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
#include "stdafx.h"
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <stdio.h>
#include <new>
#pragma warning (disable : 4996)

int main( char argc, char* argv[])
{
	using namespace std;
	string ofileap;
	string infileap;
	cout << "Please enter absolute path to input file." << endl;
	cin >> infileap;
	ifstream infile;
	infile.open(infileap, ios::in);
	if (infile.is_open())
	{
		infile.seekg (0, infile.end); //streambuffer seek position; in this case the entire file
		long size = infile.get(); //
		char* buffer = new char [size];
		infile.read(buffer, size);
		cout << "Input file opened successfully. Creating output file..." << endl;
		ofstream outfile;
		cout << "Please enter a name for output file, absolute path optional: " << endl;
		cin >> ofileap;
		outfile.open(ofileap, ios::app);
		if (outfile.is_open())
		{
			char * postbody{ buffer };
			char * ptrbody = { strtok(postbody, " !.*'/") };
			cout << "Enumerating words..." << endl;
			while (ptrbody != NULL)
				snprintf(ptrbody, *buffer, "%s\n" );
			outfile.write(buffer, size);
			
			delete[] buffer;
			outfile.close();
			infile.close();
		}
		else cout << "Output file failed to open.";
		
	} 
	else cout << "I/O Failed.";
	
	return 0;
}


char * postbody was being passed the arguments [buffer, size] which was causing the compiler errors. I put it inside braces and it compiled...not sure how well it will run though.

2nd edit: upon execution, program hangs briefly. After entering path to the input file, debug returns this error:

Unhandled exception at 0x00007FFD0D45A388 in ConsoleApplication1.exe: Microsoft C++ exception: std::bad_array_new_length at memory location 0x000000958ECFF6F0. occurred
Last edited on
It would seem the bad_array_new_length exception being thrown was due to long size = infile.get(), maybe because of the position of the stream. I changed it (back) to long size = infile.tellg() and the stream functions both ways without errors again. Because of the bizarre way I was passing stream references to the strtok and printf commands it will still output the text without any formatting operations done on it since it is not referencing the actual object being formatted yet...
Avoid stuff like this: char* buffer = new char [size]; let std::vector<> manage the memory.

If std::strtok must be used,

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>
#include <vector>
#include <cstring>

int main()
{
    std::string infile_name ;
    std::cout << "Please enter absolute path to input file.\n" ;
    std::getline( std::cin, infile_name ) ;

    if( std::ifstream infile{ infile_name } )
    {
        std::string outfile_name ;
        std::cout << "Please enter path to output file.\n" ;
        std::getline( std::cin, outfile_name ) ;

        if( std::ofstream outfile{ outfile_name, std::ios::app } )
        {
            std::vector<char> vec ;
            char c ;
            while( infile.get(c) ) // for each character (including white space) in the input file
                 vec.push_back(c) ; // add it to the vector

            char* buffer = vec.data() ; // get a pointer to the first char in the vector
            const char non_word_chars[] = "\n\t !.;:(){}[]<>/\\~!@#$%^&*-+" ; // etc.

            char* token = std::strtok( buffer, non_word_chars ) ;
            while( token != nullptr ) // for each word in the buffer
            {
                outfile << token << '\n' ; // write it to the output file
                token = std::strtok( nullptr, non_word_chars ) ;
            }

            return 0 ; // EXIT_SUCCESS
        }

        else std::cerr << "could not open output file\n" ;
    }

    else std::cerr << "could not open input file\n" ;

    return 1 ; // EXIT_FAILURE
}
Topic archived. No new replies allowed.