Sign in to follow this  
nickme

C++ what is in string after std::istreambuf_iterator< char >(sourceFile))

Recommended Posts

Hello,

 

I tried to print an text input file and print the line numbers and the line to stdout.  I used std::istreambuf_iterator, but I want to know what its char did it produced. here is the codes that I load the input file.

char * loadFromFile(char * file)
{
	//Open file
	std::string s;
	std::ifstream sourceFile(file);

	if (sourceFile)
	{
		s.assign((std::istreambuf_iterator< char >(sourceFile)),
				  std::istreambuf_iterator< char >());
	}
	else {
		printf("Eror in openning file [%s].\n", file);
		system("pause");
		exit(1);
	}
	return (char*) (s.c_str());
}

when i tried to print the whole char *stream, i got looping until it crashed.  Here is the print func.

void print_string(char *ins) {
	char *c, *ac;
	int i = 1;

	for (c = ins; *c != '\0'; i++) {
		printf(" %06i : ", i);
		for (ac = c; *ac != '\n' || *ac != '\0'; ac++)
			putchar(*ac);
		putchar('\n');
		c = ++ac; // skip the '\n'
	}

}

thank in advance

 

Share this post


Link to post
Share on other sites
Did you step through the code in your debugger?

 

 

HI ApochPiQ,

 

thanks for the reply.

 

I did used the debugger.  when i was in the debugger, the content of *c and *ac are all strange looking char, It is not from my input file.

 

If i printf(the output string loadFromFile()) in the main func, it showed the text in my file with garbage.  i can not use the printf or cout statement becaue i want to print line numbers at the beginning of each lines.

 

the main func :

int main() {
	char * stream = loadFromFile(infile);
	std::cout << stream << std::endl;
//pe(stream);
	system("pause");
	print_string(stream);
}
Edited by nickme

Share this post


Link to post
Share on other sites

I did used the debugger. when i was in the debugger, the content of *c and *ac are all strange looking char, It is not from my input file.

Is the file loaded correctly inside [tt]loadFromFile[/tt]? (Hint, the issue is inside loadFromFile.)

Share this post


Link to post
Share on other sites

Is the file loaded correctly inside loadFromFile? (Hint, the issue is inside loadFromFile.)

 

the print out in loadFromFile() (s.c_str()) looked correctly as in my input file, It was when I print the stream in main() that show garbage.

Share this post


Link to post
Share on other sites

Your function: char * loadFromFile(char * file)

 

returns char pointer which points to local variable s (std::string). That s variable goes out of scope at the end of your function, hence you get garbage. C++ is already hard language and adding usage of raw char to it is asking for trouble. Do yourself a favor and use std::string instead of char *.

 

Some reading to get you started at http://en.cppreference.com/w/cpp/language/scope

Share this post


Link to post
Share on other sites

hi DoctorGlow,

 

thanks for the reply.

 

now my stream is not garbage anymore.  In the print_string(), when *ac = '\n', the inner nested for loop did not break.  In my nested loop, it suppose to get out of the loop when *ac = '\n', why is that.

 

here is my entire project:

#include <stdio.h>
#include <string>
#include <fstream>
#include <iostream>

#define infile "in.txt"

std::string loadFromFile(char * file)
{
	//Open file
	std::string s;
	std::ifstream sourceFile(file);

	if (sourceFile)
	{
		s.assign((std::istreambuf_iterator< char >(sourceFile)),
				  std::istreambuf_iterator< char >());
	}
	else {
		printf("Eror in openning file [%s].\n", file);
		system("pause");
		exit(1);
	}
	return s;
}

void print_string(char *ins) {
	char *c, *ac;
	int i = 1;

	for (c = ins; *c != '\0'; i++) {
		printf(" %06i : ", i);
		for (ac = c; *ac != '\n' || *ac != '\0'; ac++)
			putchar(*ac);
		putchar('\n');
		c = ++ac; // skip the '\n'
	}

}

void pe(char *c) {
	char *t = c;
	while (*t != '\0') {
		putchar(*t);
		t++;
	}
}

int main() {
	std::string stream = loadFromFile(infile);
//	std::cout << stream << std::endl;
//pe(stream);
//	system("pause");
	print_string((char *)stream.c_str());
}

Share this post


Link to post
Share on other sites

Using C++-style casts, instead of dangerous C-style casts, would've also helped highlight the problem.

 

By doing this:

return (char*) (s.c_str());

That's already an indicator that something was wrong, but the (char*) is telling the compiler to shut up and stop telling you that it's wrong.  :)

When you type (char*) or similar, you're saying, "I know you think this is wrong, Mr Compiler, but trust me - I know better than you, just do it anyway.". You disabled the safeguards. 

 

Or, to put it in more technical terms, you unlocked the cage and the raptor ate your face.  :P

 

C++-style casts are also disabling safeguards, but in a more controlled way, whereas (char*)-style casts disable every type-conversion safeguard at once.

We've all been bitten by that kind of mistake numerous times; this is the C++ learning process.  :wink:

Share this post


Link to post
Share on other sites

My error: the for loop should looked like this:

 

for (ac = c; *ac != '\n' && *ac != '\0'; ac++)  // the && solved the problem.
 
how ever, the loop also read 2 line passed the end of file, do you have any idea why?

Share this post


Link to post
Share on other sites

hi

 

I finally solved my problem.  the print_string() is now :


void print_string(char *ins) {
	char *c, *ac;
	int i = 1;

	for (c = ins; *c != '\0'; i++) {
		printf(" %06i : ", i);
		for (ac = c; *ac != '\n' && *ac != '\0'; ac++)
			putchar(*ac);
		putchar('\n');
		if (*ac != '\0')
			c = ++ac; // skip the '\n'
		else
			c = ac;
	}

}


thanks

Share this post


Link to post
Share on other sites
You seem to keep wanting to break back to C'ish behavior. You'll be much happier if you stick to idiomatic C++ instead. Mixing the two is begging for problems.
#include <string>
#include <fstream>
#include <iostream>
#include <iomanip>
#include <sstream>

#define infile "in.txt"

std::stringstream loadFromFile(const std::string& filename) {
  std::ifstream sourceFile(filename);
  std::stringstream ss;

  if(!sourceFile) {
    ss << "Error opening file [" << filename << "].\n";
    throw std::runtime_error(ss.str());
  }

  ss << sourceFile.rdbuf();
  return ss;
}

int main() {
  try {
    std::stringstream stream = loadFromFile(infile);

    std::string line;
    int lineNum = 1;
    while(std::getline(stream, line)) {
      std::cout << std::setfill('0') << std::setw(6) << lineNum++ << "] " << line << "\n";
    }
  }
  catch(std::exception& e) { std::cerr << e.what() << "\n"; }

  std::cin.get();
}

Share this post


Link to post
Share on other sites

 

thanks for the reply.

 

I am not interested in inputting from a file os ascii of text that end each lines with a '\n' and the end of the string with '\0'.  the string is in that format in the ram, not a file.

 

However, if you can process the line more efficiently in print_string(), Or in search for the '\n' char with some c++'s func then it would be really greatly appreciated.

Edited by nickme

Share this post


Link to post
Share on other sites

You seem to keep wanting to break back to C'ish behavior. You'll be much happier if you stick to idiomatic C++ instead. Mixing the two is begging for problems.
 

 

I am only writing this small program to use in my Opengl project.  OpenGL shader are written in C.  hence the C codes.

Share this post


Link to post
Share on other sites

 

You seem to keep wanting to break back to C'ish behavior. You'll be much happier if you stick to idiomatic C++ instead. Mixing the two is begging for problems.
 

 

I am only writing this small program to use in my Opengl project.  OpenGL shader are written in C.  hence the C codes.

 

Actually, they're not written in C, but even if they were, what you've written makes no sense.

 

This "small program" is using C++ (string, ifstream are C++ and won't work in C). You can use this program to read and write shaders, and it doesn't matter what language you write it in ..... java, C#, python ... it's just basic file manipulation and any decent language can do that.

Share this post


Link to post
Share on other sites
Using C++-style casts, instead of dangerous C-style casts, would've also helped highlight the problem.  

 

thanks for the reply.

 

can you give me an example of what you would do? 

Edited by nickme

Share this post


Link to post
Share on other sites

 

Using C++-style casts, instead of dangerous C-style casts, would've also helped highlight the problem.

 
thanks for the reply.
 
can you give me an example of what you would do?

Fast code is important, but you should write clean code first. Clean code can always be made faster when needed, but fast code is harder to make clean. Clean code contains less bugs, and is easier to find the bugs when they do occur. Write clean, not fast. Clean code is often very fast anyway, and can easily be made faster when required.

LoadFileAsString()

std::string LoadFileAsString(const std::string &filepath, bool *successful)
{
	if(successful) *successful = false;

	//Open the file for reading.
	std::ifstream file(filepath.c_str(), std::ios_base::in);

	if(!file)
	{
		Log::Message(MSG_SOURCE("FileFunctions", Log::Severity::Error)) << "Failed to load '" << Log_HighlightCyan(GetFilenameFromPath(filepath)) << "' at " << Log_DisplayPath(filepath)
																		<< "\nDo I have sufficient privileges? Does the file even exist?" << Log::FlushStream;

		return "";
	}

    //Read the file into the stringStream.
    std::ostringstream stringStream;
    stringStream << file.rdbuf();

    if(successful) *successful = true;
    
    //Convert the stringStream into a regular string.
    return stringStream.str();
}

Seperate()

std::vector<std::string> Separate(const std::string &str, char divider)
{
	std::vector<std::string> stringArray;

	size_t startOfSegment = 0;
	for(size_t pos = 0; pos < str.size(); pos++)
	{
		if(str[pos] == divider)
		{
			//Grab the past segment.
                        stringArray.push_back(str.substr(startOfSegment, (pos - startOfSegment)));

			//Mark the beginning of a new segment.
			startOfSegment = (pos + 1);
		}
	}

	//The final segment.
	stringArray.push_back(str.substr(startOfSegment, (str.size() - startOfSegment)));
    
	return stringArray;
}

Share this post


Link to post
Share on other sites

Hi Servant of the Lord,

 

thanks for the reply.

 

the stream variable could had been :

                             stream = "\nthis is the 2nd line.\n\nthis is the fifth line.\n\0";

 

that is the data structure that I have to work with. That is what the Opengl shader compiler understand.

 

a little history.  I learned coding began in 1980 by taking a C program in college.  after that I had not done any coding after that until a few years ago i started to code again as a hobby.  And all these times i learned C++ by myself.  so sorry for the Cish coding style.

 

So after using the separate(), how do i print out the whole file?

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this