• 0

[C++] My Book's examples are not working


Question

Hello again everyone.

I am making this post not because I am not understanding a specific coding error this time, but rather because the examples of code in my book don't work.

The book I am trying to teach myself C++ from is "C++ Without Fear" by Brian Overland.

I've reached a point in my book where I've started doing some work with creating external files (particularly text files, and engaging in the process of writing to them). The problem is, I have begun to find that both the codes I copy for myself from the book into a compiler, as well as the codes from the "Answer Sheet" sort of folder that came with a disc contained within the book, do not work.

The big problem with this of course is that, although the author does a great job of explaining the code and how it works in the "How It Works" part of every section, after any given coding exercise, I find that I learn best by analyzing a code as I run the .exe, examining each process bit by bit by comparing what appears on the console output, to how it is handled within the code itself.

Let me give you an example.

#include <iostream>
#include <fstream>
using namespace std;

int get_int(int default_value);
char name[20];

int main() {
	char filename[81];
	int n;
	int age;
	int recsize = sizeof(name) + sizeof(int);


	cout << "Enter file name: ";
	cin.getline(filename, 80);

	// Open file for binary read and write.	

	fstream  fbin(filename, ios::binary | ios::in | ios::out);
	if (!fbin) {
		cout << "Could not open file " << filename;
		return -1;
	}

//  Get record number to write to.

	cout << "Enter file record number: ";
	n = get_int(0);

	// Get data from end user.

	cout << "Enter name: ";
	cin.getline(name, 19);
	cout << "Enter age: ";
	age = get_int(0);

	// Write data to the file.

	fbin.seekp(n * recsize);
	fbin.write(name, 20);
	fbin.write(reinterpret_cast<char*>(&age), sizeof(int));
	fbin.close();
	system("pause");
	return 0;
}

// Get integer function
// Get an integer from keyboard; return default
//  value if user enters 0-length string.
//
int get_int(int default_value) {
	char s[81];

	cin.getline(s, 80);
	if (strlen(s) == 0)
		 return default_value;
	return atoi(s);
}

This code is from the "answer sheet" folder. Meaning of course that this is the code written by Brian (or someone else, I don't know) but should theoretically be accurate.

Both this code and my own have the same problem.

The program should supposedly create a binary output file with data on the user's name and age.

This is my first time doing things with binary files, and I'm already finding them somewhat complex. Admittedly, having the exercises not work for me is greatly impairing my ability to understand the idea behind certain processes, how to use certain syntax, and more importantly, how these bits of syntax, and things (in this example) such as binary file writing could be at all useful in more productive working programs.

Does anyone have any suggestions on how I could get through this problem?

If anyone is curious, I do have on my computer two other C++ for beginners books by the titles of "C++ - How to program" and "C++ primer fifth edition".

Thanks.

Link to comment
Share on other sites

Recommended Posts

  • 0

Looking at the code, as far as I can tell it won't create the binary file, it will simply open a file that already exists, and then write to it in binary. Is that your problem?

Link to comment
Share on other sites

  • 0
Looking at the code, as far as I can tell it won't create the binary file, it will simply open a file that already exists, and then write to it in binary. Is that your problem?
"Opening" a file that doesn't exist effectively creates a new file. Or am I missing something here?
Link to comment
Share on other sites

  • 0

The problem doesn't seem to lie in the creation of a file, as far as I can tell.

The program successfully prompts the user for a file name, as depicted by the char field.

As I've learned, the line:

fstream  fbin(filename, ios::binary | ios::in | ios::out);

Should create the file. The best way I remember it so far is in an example to a text document.

ofstream file_out(C:\Program Files\My Documents\Randomtext.txt); - Where:

Out File Stream File_output (location of file\ name of file);

This act should create the file in the specified location.

However, after inputting that, the program just turns off as if it finished running.

In the code snippet above:

Fstream = start a file stream

fbin = file binary

(inside brackets) = sets filetype to binary (ios::binary) and allows input and output from that file.

Link to comment
Share on other sites

  • 0
"Opening" a file that doesn't exist effectively creates a new file. Or am I missing something here?

Yeah I think you're right Dr_Asik. Not sure why I thought you had to explicitly specify that the file should be created.

edit: Just tried compiling your the code and I get the "Could not open file message" if the file doesn't exist, but it works if I create the file first. Weird.

Link to comment
Share on other sites

  • 0
However, after inputting that, the program just turns off as if it finished running.

When writing a console application, it's best to test it from a preopened command prompt. In this way, the window remains after the application completes, and you can read any output.

If the application is failing at an unknown place, and you have no access to a debugger, cout some lines of text at various places, so you can see what the last thing it did was before the failure.

If you already know the line at which it is failing, please tell us :)

Link to comment
Share on other sites

  • 0

Managed to fix it. You need to specify the ios::trunc flag when you call the fstream constructor.

fstream  fbin(filename, ios::binary | ios::in | ios::out | ios::trunc);

It now works for me even if the file does not exist.

I'm a bit unsure why you need the truncate though.

Weird. From Wiki:

ios::in - If the file does not exist, a new empty file is created. If the file exists, it is opened and made available for processing as input.

ios::out - If the file does not exist, a new empty file is created, ready to be written to. If the file exists, it is opened, and the previous content in it is deleted, and is then made ready to be written to.

Surely the trunc flag shouldn't be needed?

Link to comment
Share on other sites

  • 0

Okay, I tried what Vizion said and made the file prior to using the program, after running it in an already open command prompt, and it seems to be working.

Thanks for the help.

+Edit.

I really don't know why it would need that flag.

As your article states, just using the ios::in and ios::out should create a file if necessary.

I've tried using this program on both Visual C++ 2008 express and dev-C++ with the same results on either end. Though, I'm just starting to learn what visual C++ is all about and how that works.

Link to comment
Share on other sites

  • 0

It's important to check object validity before use. This may be better for opening the file:

fstream fbin( filename, ios::binary | ios::out );
if ( fbin.is_open() )
{
	// work with fbin
	fbin.close();
}
else
{
	cout << "fstream::ctor failed.\r\n";
}

From looking at your example code, it seems it is intended to work by manipulating a file, appending records to it based on the binary width of each record ( fbin.seekp(n * recsize); ). I think truncating the file each time would, therefore, be improper.

If the file is never going to be read from, as it seems is the case in the example, you should omit the ios::in, as the fstream constructor may fail since the file doesn't yet exist. If you require read/write access upon creation, you may wish to try a flush ( fbin.flush(); ) on the stream after opening it to initialize the file, though I can't guarantee it will work.

Edited by someone64
Link to comment
Share on other sites

  • 0

Line 20: replace

fstream  fbin(filename, ios::binary | ios::in | ios::out);

with

fstream  fbin(filename, ios::binary | ios::out);

or (better style)

ofstream fbin(filename, ios::binary);

And file creation occurs normally. I think the issue is that C++ won't create the file if you specify ios::in, which is read access. If you later need read access, just close the stream and reopen it specifying ios::in. Or create an ifstream.

Thanks to someone64 for the explanation, I originally didn't get why the first line was failing.

Gotta love C++. After working with it for two years I still can't answer beginner questions. :p

Edited by Dr_Asik
Link to comment
Share on other sites

  • 0

This might work best if you require read/write access.

fstream fbin;

fbin.open( filename, ios::binary | ios::in | ios::out );
if ( !fbin.is_open() )
{
	// cout << "fstream::open failed. file does not exist.\r\n";
	fbin.clear();
	fbin.open( filename, ios::binary | ios::trunc | ios::in | ios::out );
}

if ( fbin.is_open() )
{
	// work with fbin
	fbin.close();
}
else
{
	cout << "fstream::open failed.\r\n";
}

Dr_Asik's ofstream suggestion for write-only access is best, if you don't need simultaneous read/write. Considering your example code, I think that may be the best solution. :)

Edited by someone64
Link to comment
Share on other sites

  • 0
Gotta love C++. After working with it for two years I still can't answer beginner questions.

lol I feel the same way; in fact, if anyone has access to a compiler, could they try the flush method above without an existing file and see if it works? I'd love a confirmation!

Link to comment
Share on other sites

  • 0
lol I feel the same way; in fact, if anyone has access to a compiler, could they try the flush method above without an existing file and see if it works? I'd love a confirmation!
It won't work, because fbin.is_open() will be false, and you won't even reach the flush.
Link to comment
Share on other sites

  • 0

Oh, so it's confirmed that it fails at the constructor then? I just wanted to be certain that the failure wasn't happening at seekp with a file that doesn't yet exist. A flush would create the file. Thanks for the reply!

Link to comment
Share on other sites

  • 0

Hi again.

I wasn't sure where to put this question, so I decided to use my old post even though it isn't really related.

I tried to figure this problem out to the best of my ability but have really had no luck in understanding what was going on here.

So here's the console output:

error.jpg

And here's the code:

#include <iostream>
#include <fstream>
using namespace std;

int get_num();
char value1[4];
char value2[4];

int main() {
	int x0, x1, x2, x3;
	int y0, y1, y2, y3;
	int y, x;
	int i;

	cout << "The setup for this system of equations is: \n";
	cout << "_X_|_Y_\n";
	cout << " X0| Y0\n";
	cout << " X1| Y1\n";
	cout << " X2| Y2\n";
	cout << " X3| Y3\n";
	cout << endl;
	system ("pause");

	cout << "The equation is Y = A(x * x) + B(x) + C\n";

	for (i = 0; i < 4; i++) {
		cout << "Enter the value of X" << i << ": ";
		value1[i] = get_num();
		}
	for (i = 0; i < 4; i++) {
		cout << "X" << i << " is: " << value1[i] << endl;
		}
	system ("pause");
	return 0;
		}



int get_num() {
	   char s[100];

	   cin.getline(s, 99);
	   if (strlen(s) == 0) {
					 return 0;
					 }
	   return atoi(s);
	   }

I'm trying to write a program that will do this system of equations (predicting) and later add steps to stream each process onto a text document. It's more or less just for the sake of further practice getting used to using cin.getline(s, number) rather than just cin >>, as well as getting a better handle on file streaming.

I've been testing each part of it as I write, which is why I added the part of the code to show that each part of the array had been successfully stored, but as you can see, they have not.

Now, when I compiled this code before testing it, for some reason my computer made a beeping sound as if you had tapped the shift button several time (which I suppose is possible for me have done by mistake) and I somehow ended up with the stored values of my arrays being smiley faces and, with other number inputs, unusual symbols.

Does anyone know what I may have done to change the array storage to convert input to symbols?

Using the get_num(); function is an example from my book, and using the variable = get_num(); function has worked perfectly in the past. In fact, I even copied the function definition from a working example, in case I had made an error, but that does not seem to be the case.

Any advice would be greatly appreciated as I really have no idea what I'm doing here with this problem.

Oh, and I use Dev-C++ to compile. I believe it's the version 4.9.9.2 or something along those lines.

Thanks.

+Edit:

I decided to get rid of the get_num(); function and stick to the cin >> function and everything seems to be working now.

I guess it doesn't really matter that I use get_num(); since I won't be using the cin.getline function anyway.

Edited by Ryuurei
Link to comment
Share on other sites

  • 0

Quick look over the code, you need to change the value1 and value2 variables to be int's rather than chars. Your get_num() is returning an int but you're trying to display it as a character and hence the funny ASCII values.

Making those changes, it seems to work for me :)

Link to comment
Share on other sites

  • 0

I had a quick question about modules here.

I have reached the point in my book where I have begun to learn "Advanced programming techniques" and this one particularly interests me.

That is of course, the topic of using "modules" from external files in order to include functions from other sources (.o files, I believe) so that you don't have to write functions in every single .cpp file and whatnot.

The problem is, my book doesn't really cover them well or show how to use them, saying that they would make the small examples in the book a bit over-cooked.

So, all I really know is that you use a #include "myproj.h" inclusion file to do it, and that you have to:

A.) State every function that is going to be used from the external source in the main file. Simple enough.

B.) Write the definition for each function in the other, supporting, file.

However, I tried to do so with this code:

#include <iostream>
#include "myproj"
using namespace std;

int get_num();

int main() {
	int x;
	cout << "Enter a number: ";
	x = get_num();
	cout << endl;

	cout << "The number you entered was " << x << endl;
	cout << endl;

	system("pause");
	return 0;
}

Just a little something I whipped together to give it a try with the get_num(); function.

However, upon compiling, I am told that the myproj.h file or directory does not exist.

Could someone properly explain how to do this?

I understand the concept, and it seems incredibly useful, so I'd love to be able to use them, but obviously have no idea how.

Thanks.

Link to comment
Share on other sites

  • 0

You should just have to have myproj.h in the same folder as your main.c for it to be included correctly. So you'll actually have 3 files: main.c, myproj.h and myproj.cpp

main.c contains your main program

myproj.h contains your function prototypes such as int get_num(), and then myproj.cpp contains your implementation of get_num(). Then for any file you want to be able to use get_num() simply have do a #include "myproj.h"

so maybe something like this:

main.c
======

#include "myproj.h"

int main()
{

	blah blah blah
}


------------------

myproj.h
========

int get_num();


--------------------



myproj.cpp
==========

#include "myproj.h"

int get_num()
{
	blah blah blah
}

One problem you will probably run into soon especially if you're including the header in multiple source files is multiple inclusions, but it's easy to fix if that occurs :)

Hopefully I'm making some sense :p

edit: Ooh almost my 3000th post!

Link to comment
Share on other sites

  • 0

So in doing that, how do I name and compile each file?

Do each of the three files contain only the sorts of information you listed there?

Congratulations on 3000 posts, by the way!

Link to comment
Share on other sites

  • 0

Thanks :)

Simply name the files as I have done above (although it will be main.cpp, not main.c :blush:. I think they're case sensitive. How are you compiling your code right now? If you're using Visual Studio / Dev C++ / Code::Blocks it should handle the compilation for you. If you're compiling from the command line you should just be able to do this:

g++ -Wall main.cpp myproj.cpp -o myproj

That should create an exe called myproj.exe

edit:

Here's an example

main.cpp

#include <iostream>
#include "myproj.h"

using namespace std;

int main()
{
	get_num();

	return 0;
}

myproj.h

#ifndef MY_PROJ_H
#define MY_PROJ_H /* Prevent multiple inclusions */

int get_num();

#endif /* MY_PROJ_H */

myproj.cpp

#include <iostream>
#include "myproj.h"

using namespace std;

int get_num()
{
	int num;

	cout << "Enter a num: ";
	cin >> num;

	cout << "You entered: " << num;

	return 0;
}

Should compile with the above line although obviously you'll need gcc/g++ to compile it. I normally compile my code using Cygwin, which comes with g++. You could also use the Microsoft compiler although I'm not sure of the syntax. Google is your friend :)

Edited by ViZioN
Link to comment
Share on other sites

  • 0

Well, first I wrote and compiled myproj.h

which is:

int get_num();

and saved it as a .h file.

then I tried to compile the third (of the three) files, myproj.cpp

#include <iostream>
#include "myproj.h"
using namespace std;

int get_num() {
	char s[100];

	cin.getline(s, 99);
	if (strlen(s) == 0) {
				  return 0;
				  }
	return atoi(s);
}

which returned the errors:

[Link error] undefined reference to 'WinMain@16'

Id returned 1 exit status

Then, trying to compile main:

#include <iostream>
#include "myproj.h"
using namespace std;

int main() {
	cout << "Enter a number: ";
	int x = get_num();
	cout << x << endl;

	system ("pause");
	return 0;
}

gives me the same errors as above.

Link to comment
Share on other sites

  • 0

What program you using to compile the code? From what I can see your code is fine. It's simply the way you're compiling the code as the linker can't find get_num() as it's somehow not being included.

I've got to go to bed now as I've got work tomorrow (it's late in the UK), but I'm sure Dr_Asik or someone else will be about to answer your questions. Failing that i'll try and help tomorrow.

Link to comment
Share on other sites

This topic is now closed to further replies.
  • Recently Browsing   0 members

    • No registered users viewing this page.