Magic cin/input buffer problem please help! :)

M

Morgan

Hi,

I'm aware that cin.getline has the issue where you've got to use
cin.ignore () to discard the newline, but sadly I'm unable to figure
this one out and it's driving me nuts.

My code is very simple, an array of strings is outputted before the
user, they choose a number which represents eg: sony or paramount or
whoever, and then I copy that string into an array of char belonging
to a structure.

It sounds simple enough, ya, but I've begun using cin.ignore() all
over the shop at this point trying to pinpoint the error.

The Problem is basically that the code absolutely refuses to output
the last cout statement. No can do. Instead, it zips past that and the
program ends.

cin.get() and cin.ignore appear to be of no avail and I'm at a loss to
say why. I did search the forum, but couldn't find an issue like it
before.

Clearly there is a ton of input flying into the cin statements in my
code after the
cout << endl << newDVD.production_company << endl;
statement, but I can't seem to clear the input from the input buffer.

I thought cin.ignore flushed the buffer completely? What the hell is
going on!! :-|


// start of my code

string production_companies[9] = {
"Paramount Pictures",
"Sony Entertainment",
"Fox Entertainment",
"Universal Studios",
"NBC Universal",
"Walt Disney",
"Time Warner",
"Dreamworks",
"Lionsgate",
};

int y = x; // these are just for positioning the output,
that's all.
for(int i = 0; i < 9; i++)
{
gotoxy(25, y+=2); // gotoxy places the cursor at a (x,y) or
(column,row) coord on the console screen
cout << i << " = " << production_companies;
}

gotoxy(25, y+=2);
int production_company_choice = -1;
cout << "Choice : ";
cin >> production_company_choice;
cin.ignore();

if(production_company_choice > 8 ||
production_company_choice < 0)
{
gotoxy(25, y+=2);
cout << "Choice " << production_company_choice << "
does not exist.";
gotoxy(25, y+=1);
cout << "Press Enter and re-enter your choice.";
cin.get();
add_dvd_screen(); // this works fine actually,
it's the else that screws up.
}
else
{
for(int i = 0; i < 20; i++)
{ // here I assign a character from a
string to an element in an array of char (need to use char)
newDVD.production_company = production_companies
[production_company_choice].at(i);
}
}
cin.ignore();
cout << endl << newDVD.production_company << endl;
// many more cin, cin.getline statements follow, but they
are magically bypassed somehow.
// end of code.
 
M

Morgan

Forgive the horrible line wrapping! :-o
I forgot usenet is strict about it being 40 chars or
whatever.


// start of my code


string production_companies[9] = {
"Paramount Pictures",
"Sony Entertainment",
"Fox Entertainment",
"Universal Studios",
"NBC Universal",
"Walt Disney",
"Time Warner",
"Dreamworks",
"Lionsgate",
};

// these are just for positioning the output, that's all.
int y = x;

for(int i = 0; i < 9; i++)
{
// gotoxy places the cursor at a (x,y) or (column,row) coord
// on the console screen
gotoxy(25, y+=2);
cout << i << " = " << production_companies;
}


gotoxy(25, y+=2);
int production_company_choice = -1;
cout << "Choice : ";
cin >> production_company_choice;
cin.ignore();


if(production_company_choice > 8 || production_company_choice < 0)
{
gotoxy(25, y+=2);
cout << "Choice " << production_company_choice << " does not
exist.";
gotoxy(25, y+=1);
cout << "Press Enter and re-enter your choice.";
cin.get();
add_dvd_screen();
// this works fine actually, it's the else that screws up.
}
else
{
for(int i = 0; i < 20; i++)
{
// here I assign a character from a string to an
// element in an array of char (need to use char)
newDVD.production_company =
production_companies[production_company_choice].at(i);
}
}
cin.ignore();
cout << endl << newDVD.production_company << endl;

// many more cin, cin.getline statements follow, but they
// are magically bypassed somehow.

// end of code.
 
M

Morgan

Can you post a complete program that shows the problem?

Ok, but it's little big! You'll need to include two header files.
Make a folder called header_files and then put two header files in it
called pretty_code.h and cursor.h respectively:

Anyways, here is the code:

-------------------------------
header_files/pretty_code.h
-------------------------------
#ifndef pretty_code_h
#define pretty_code_h

#include <iomanip>
#include <iostream>
#include "cursor.h"

using namespace std;

// begin code:


void header(bool clear_screen, string text, string table_type, string
table_filler, int cols_across, int rows_down)
{

if(clear_screen == true)
{
system("CLS");
}
// table text variables.
int top_left_corner = 0;
int top_right_corner = 0;
int horizontal_line = 0;
int vertical_line = 0;
int bottom_left_corner = 0;
int bottom_right_corner = 0;

if(table_type == "single")
{
top_left_corner = 218;
top_right_corner = 191;
horizontal_line = 196;
vertical_line = 179;
bottom_left_corner = 192;
bottom_right_corner = 217;
}
else if(table_type == "double")
{
top_left_corner = 201;
top_right_corner = 187;
horizontal_line = 205;
vertical_line = 186;
bottom_left_corner = 200;
bottom_right_corner = 188;
}

int string_length = text.length();
int cell_internal_fill = 0;

if(table_filler == "blank") cell_internal_fill = 0;
else if(table_filler == "dots") cell_internal_fill = 46;
else if(table_filler == "white") cell_internal_fill = 219;
else if(table_filler == "music") cell_internal_fill = 14;
else if(table_filler == "matrix") cell_internal_fill = 177;
else if(table_filler == "hearts") cell_internal_fill = 3;
else if(table_filler == "zigzag1") cell_internal_fill = 176;
else if(table_filler == "zigzag2") cell_internal_fill = 178;
else if(table_filler == "diamonds") cell_internal_fill = 4;

gotoxy(cols_across, rows_down);

cout << char(top_left_corner);

for(int i = 0; i < string_length + 6; i++)
{
cout << char(horizontal_line);
}

cout << char(top_right_corner);
gotoxy(cols_across, rows_down + 1);
cout << char(vertical_line);
cout << setfill(char(cell_internal_fill));
cout << setw(string_length + 7);
cout << char(vertical_line);
gotoxy(cols_across, rows_down + 2);
cout << char(vertical_line);

for(int i = 0; i < 3; i++)
cout << char(cell_internal_fill);

cout << text ;

for(int i = 0; i < 3; i++)
cout << char(cell_internal_fill);

cout << char(vertical_line);

gotoxy(cols_across, rows_down + 3);
cout << char(vertical_line);
cout << setfill(char(cell_internal_fill));
cout << setw(string_length + 7);
cout << char(vertical_line);
gotoxy(cols_across, rows_down + 4);

cout << char(bottom_left_corner);

for(int i = 0; i < string_length + 6; i++)
{
cout << char(horizontal_line);
}

cout << char(bottom_right_corner);

}

// :end code

#endif


-------------------------------
header_files/cursor.h
-------------------------------
#ifndef cursorh
#define cursorh

#include<iostream>
#include<windows.h>

//Redifine functions that could clash with conio.h
#define clrscr cursorh_clrscr
#define gotoxy cursorh_gotoxy
#define wherex cursorh_wherex
#define wherey cursorh_wherey

using namespace std;

HANDLE cursorhConsoleOut = GetStdHandle( STD_OUTPUT_HANDLE );
HANDLE cursorhConsoleIn = GetStdHandle( STD_INPUT_HANDLE );
CONSOLE_SCREEN_BUFFER_INFO cursorhScreen_info;
DWORD cursorhConModeNum = ENABLE_WINDOW_INPUT|ENABLE_MOUSE_INPUT;

static int cursorhFOREGROUND = 15;//Bright white
static int cursorhBACKGROUND = 0;//Black
static int cursorhOLDFOREGROUND = 15;
static int cursorhOLDBACKGROUND = 0;

inline void gotoXY(int x, int y)
{
cout << flush;

GetConsoleScreenBufferInfo
(cursorhConsoleOut,&cursorhScreen_info);

cursorhScreen_info.dwCursorPosition.Y = y;
cursorhScreen_info.dwCursorPosition.X = x;

SetConsoleCursorPosition
(cursorhConsoleOut,cursorhScreen_info.dwCursorPosition);
}

inline void cursorh_gotoxy( int x, int y)
{
gotoXY(x, y);
}

inline int whereX()
{
GetConsoleScreenBufferInfo(cursorhConsoleOut, &cursorhScreen_info);

return cursorhScreen_info.dwCursorPosition.X;
}

inline int whereY()
{
GetConsoleScreenBufferInfo(cursorhConsoleOut, &cursorhScreen_info);

return cursorhScreen_info.dwCursorPosition.Y;
}

inline int cursorh_wherex()
{
return whereX();
}

inline int cursorh_wherey()
{
return whereY();
}

inline void where_mouse(int & x, int & y)
{
INPUT_RECORD event_info;
MOUSE_EVENT_RECORD mouse_info;

DWORD oldConsoleMode;

GetConsoleMode(cursorhConsoleIn,&oldConsoleMode);
SetConsoleMode(cursorhConsoleIn,cursorhConModeNum);

DWORD count;

while(true)
{
if(ReadConsoleInput(cursorhConsoleIn, &event_info, 1, &count))
{
if(event_info.EventType == MOUSE_EVENT)
{
mouse_info = event_info.Event.MouseEvent;

if(mouse_info.dwEventFlags == 0)
{
break;
}
}
}
Sleep(100);
}

x = mouse_info.dwMousePosition.X;
y = mouse_info.dwMousePosition.Y;

SetConsoleMode(cursorhConsoleIn,oldConsoleMode);
}


//////////////////////////////clrscr()///////////////////////////
//// called cursor_clrscr() to distinguish between it and one
//// that might be in conio.h
//// This one uses the present colors to fill the screen. If you
//// want the old colors, use resetcolors() first.
///////////////////////////////////////////////////////////////
inline void cursorh_clrscr()
{

GetConsoleScreenBufferInfo(cursorhConsoleOut,
&cursorhScreen_info);

DWORD written;
int x = cursorhScreen_info.dwSize.X;
int y = cursorhScreen_info.dwSize.Y;

int z = x * y;

COORD top_left;
top_left.X = 0;
top_left.Y = 0;

FillConsoleOutputAttribute (cursorhConsoleOut,
cursorhFOREGROUND|cursorhBACKGROUND,
z,
top_left,
&written);


FillConsoleOutputCharacter (cursorhConsoleOut,
' ',
z,
top_left,
&written);

cursorhOLDFOREGROUND = cursorhFOREGROUND;
cursorhOLDBACKGROUND = cursorhBACKGROUND;

gotoXY (0, 0);
}

//////////////////////////////// setbackgroundcolor
() /////////////////////
////// Use all or any of:-
// BACKGROUND_RED|BACKGROUND_GREEN|BACKGROUND_BLUE|
BACKGROUND_INTENSITY
///// as colors inside the brackets
//// e.g for bright yellow use
//// setbackgroundcolor( BACKGROUND_RED|BACKGROUND_GREEN|
BACKGROUND_INTENSITY);
//// for bright cyan use
//// setbackgroundcolor( BACKGROUND_BLUE|BACKGROUND_GREEN|
BACKGROUND_INTENSITY);
//// for bright magenta use
//// setbackgroundcolor( BACKGROUND_RED|BACKGROUND_BLUE|
BACKGROUND_INTENSITY);
//// for black use
//// setbackgroundcolor(0);
/// for bright white use
//// setbackgroundcolor( BACKGROUND_RED
// |BACKGROUND_GREEN
// |BACKGROUND_BLUE
// |BACKGROUND_INTENSITY);
//////////////////////////////////////////////////////////////////////
inline void
setbackgroundcolor(int color)
{
SetConsoleTextAttribute (cursorhConsoleOut, cursorhFOREGROUND|
color);
cursorhBACKGROUND = color;
}

//////////////////////////////// settextcolor() /////////////////////
////// Use all or any of:-
// FOREGROUND_RED|FOREGROUND_GREEN|FOREGROUND_BLUE|
FOREGROUND_INTENSITY
///// as colors inside the brackets
//// e.g for bright yellow use
//// settextcolor( FOREGROUND_RED|FOREGROUND_GREEN|
FOREGROUND_INTENSITY);
//// for bright cyan use
//// settextcolor( FOREGROUND_BLUE|FOREGROUND_GREEN|
FOREGROUND_INTENSITY);
//// for bright magenta use
//// settextcolor( FOREGROUND_RED|FOREGROUND_BLUE|
FOREGROUND_INTENSITY);
//// for black use
//// settextcolor(0);
/// for bright white use
//// settextcolor( FOREGROUND_RED
// |FOREGROUND_GREEN
// |FOREGROUND_BLUE
// |FOREGROUND_INTENSITY);
//////////////////////////////////////////////////////////////////////
inline void
settextcolor(int color)
{
SetConsoleTextAttribute (cursorhConsoleOut, cursorhBACKGROUND|color);
cursorhFOREGROUND = color;
}

inline void
resetcolors()
{
settextcolor(cursorhOLDFOREGROUND);
setbackgroundcolor(cursorhOLDBACKGROUND);

cursorhBACKGROUND = cursorhOLDBACKGROUND;
cursorhFOREGROUND = cursorhOLDFOREGROUND;
}

#endif


-------------------------------
main code file
-------------------------------

#include <iostream>
#include <iomanip>
#include "header_files/pretty_code.h"
#include "header_files/cursor.h"

using namespace std;

// structures:
struct DVD
{
int id_number;
char title[50];
char production_company[20];
char censor_rating[3];
char category[20];
char rental_period[2];

};

// functions:

// Console user interface screens (procedures):
// note: the procedures are listed in the same order as their
prototypes.
void main_screen(void);
void dvd_database_screen(void);
void add_dvd_screen();
void remove_dvd_screen();
void customer_database_screen(void);
void dvd_loan_screen(void);
void exit_program_screen(void);

int main()
{

main_screen();


cout << "\nbroken out from main screen!\n";
cin.get();
cin.get();
}

// main screen
void main_screen(void)
{
// display heading
header(true," ", "double", "matrix", 25, 1);

// list choices capable of being made
int x = 7;
gotoxy(25, x);
cout << " 1 " << char(16) << " DVD Database";
gotoxy(25, x+=2);
cout << " 2 " << char(16) << " Customer Database";
gotoxy(25, x+=2);
cout << " 3 " << char(16) << " DVD Loan";
gotoxy(25, x+=2);
cout << " 0 " << char(16) << " Exit Program";

// ask user for their choice
gotoxy(25,x+=2);
cout << "Choice: ";
int choice = 0;
cin >> choice;

// react to their choice
switch(choice)
{
case 1 : {
dvd_database_screen();
}
break;
case 2 : {
customer_database_screen();
}
break;
case 3 : {
dvd_loan_screen();
}
break;
case 0 : {
exit_program_screen();
}
break;
default: {
gotoxy(25, x+=2);
cout << "Choice " << choice << " does not exist.";
gotoxy(25, x+=1);
cout << "Press Enter and re-enter your choice.";
cin.get();
cin.get();
main_screen();
}
}
}

void dvd_database_screen()
{
header(true," DVD Database ", "double", "matrix", 25,
1);

int x = 7;
gotoxy(25, x);
cout << " 1 " << char(16) << " Add DVD";
gotoxy(25, x+=2);
cout << " 2 " << char(16) << " Remove DVD";

gotoxy(25,x+=2);
cout << "Choice: ";
int choice = 0;
cin >> choice;

if(1 == choice)
{
add_dvd_screen();
}
else if(2 == choice)
{
remove_dvd_screen();
}
else
{
gotoxy(25, x+=2);
cout << "Choice " << choice << " does not exist.";
gotoxy(25, x+=1);
cout << "Press Enter and re-enter your choice.";
cin.get();
cin.get();
main_screen();
}
}

void add_dvd_screen()
{
header(true," Add DVD ", "double", "matrix", 25, 1);
int x = 7;
DVD newDVD;
gotoxy(25, x);
cout << "DVD Title: ";
cin.ignore(2);
cin.getline(newDVD.title,50);

header(true," Add DVD ", "double", "matrix", 25, 1);
gotoxy(25, x);
cout << "DVD Production Company: ";

string production_companies[9] = {
"Paramount Pictures",
"Sony Entertainment",
"Fox Entertainment",
"Universal Studios",
"NBC Universal",
"Walt Disney",
"Time Warner",
"Dreamworks",
"Lionsgate",
};

int y = x;
for(int i = 0; i < 9; i++)
{
gotoxy(25, y+=2);
cout << i << " = " << production_companies;
}

gotoxy(25, y+=2);
int production_company_choice = -1;
cout << "Choice : ";
cin >> production_company_choice;
cin.ignore();

if(production_company_choice > 8 ||
production_company_choice < 0)
{
gotoxy(25, y+=2);
cout << "Choice " << production_company_choice << "
does not exist.";
gotoxy(25, y+=1);
cout << "Press Enter and re-enter your choice.";
cin.get();
add_dvd_screen();
}
else
{
for(int i = 0; i < 20; i++)
{
newDVD.production_company = production_companies
[production_company_choice].at(i);
}
}
cin.ignore();
cout << endl << newDVD.production_company << endl;
cin.get();
cin.get();

//header(true," Add DVD ", "double", "matrix", 25, 1);
gotoxy(25, x);
cout << "DVD Classification: ";
cin >> newDVD.censor_rating;

//header(true," Add DVD ", "double", "matrix", 25, 1);
gotoxy(25, x);
cout << "DVD Category: ";
cin >> newDVD.category;

//header(true," Add DVD ", "double", "matrix", 25, 1);
gotoxy(25, x);
cout << "DVD Rental Period: ";
cin >> newDVD.rental_period;

cin.get();
cin.get();
}

void remove_dvd_screen()
{
header(true," Remove DVD ", "double", "matrix", 25, 1);
cin.get();
cin.get();
}

void customer_database_screen()
{

}

void dvd_loan_screen()
{



}

void exit_program_screen()
{
header(true," Exit Program? ", "double", "matrix", 25, 1);

int x = 7;
gotoxy(25, x);
cout << " 1 " << char(16) << " Yes";
gotoxy(25, x+=2);
cout << " 2 " << char(16) << " No";

gotoxy(25,x+=2);
cout << "Choice: ";
int choice = 0;
cin >> choice;

if(1 == choice)
{
exit(1);
}
else if(2 == choice)
{
main_screen();
}
else
{
gotoxy(25, x+=2);
cout << "Choice " << choice << " does not exist.";
gotoxy(25, x+=1);
cout << "Press Enter and re-enter your choice.";
cin.get();
cin.get();
exit_program_screen();
}




}
 
M

Morgan

I ran it in the command prompt (ya windows, but at least it's not
vista!) and discovered this wonderful error msg:

----------------------------------------------------------------
¥                    ¨
¡‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘¡
¡‘‘‘ Add DVD ‘‘‘¡
¡‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘¡
«                    ®

DVD Production Company:

0 = Paramount Pictures

1 = Sony Entertainment

2 = Fox Entertainment

3 = Universal Studios

4 = NBC Universal

5 = Walt Disney

6 = Time Warner

7 = Dreamworks

8 = Lionsgate

Choice : 2

This application has requested the Runtime to terminate it in an
unusual way.
Please contact the application's support team for more information.
----------------------------------------------------------------
LOL! I guess that's me and you guys!

Anyways, I'm still baffled (and have been all afternoon), but I'll
keep working away at it and if anyone has suggestions, please make
them!
 
M

Morgan

Let me rephrase:  Can you post a short, self-contained, compilable example?

Ok, this should run ok in your complier:

===================================
#include <iostream>
#include <iomanip>


using namespace std;

// structures:
struct DVD
{
int id_number;
char title[50];
char production_company[20];
char censor_rating[3];
char category[20];
char rental_period[2];

};

void main_screen(void);
void dvd_database_screen(void);
void add_dvd_screen();

int main()
{

add_dvd_screen();


cout << "\nbroken out from main screen!\n";
cin.get();
cin.get();
}


void add_dvd_screen()
{
int x = 7;
DVD newDVD;

cout << "DVD Title: ";
cin.ignore(2);
cin.getline(newDVD.title,50);



cout << "DVD Production Company: ";

string production_companies[9] = {
"Paramount Pictures",
"Sony Entertainment",
"Fox Entertainment",
"Universal Studios",
"NBC Universal",
"Walt Disney",
"Time Warner",
"Dreamworks",
"Lionsgate",
};

int y = x;
for(int i = 0; i < 9; i++)
{
cout << endl;
cout << i << " = " << production_companies;
}

cout << endl << endl;
int production_company_choice = -1;
cout << "Choice : ";
cin >> production_company_choice;
cin.ignore();

if(production_company_choice > 8 ||
production_company_choice < 0)
{

cout << "Choice " << production_company_choice << "
does not exist.";

cout << "Press Enter and re-enter your choice.";
cin.get();
add_dvd_screen();
}
else
{
for(int i = 0; i < 20; i++)
{
newDVD.production_company = production_companies
[production_company_choice].at(i);
}
}
cin.ignore();
cout << endl << newDVD.production_company << endl;
cin.get();
cin.get();

//header(true," Add DVD ", "double", "matrix", 25, 1);

cout << "DVD Classification: ";
cin >> newDVD.censor_rating;

//header(true," Add DVD ", "double", "matrix", 25, 1);

cout << "DVD Category: ";
cin >> newDVD.category;

//header(true," Add DVD ", "double", "matrix", 25, 1);

cout << "DVD Rental Period: ";
cin >> newDVD.rental_period;

cin.get();
cin.get();
}

===================================
 
M

Morgan

Ok folks!

Problem is solved :)

It is a bit odd though:

Apparently using .at() with a string is NOT equivalent to using index
notation i.e. mystr[] is not mystr.at()

I mean, logically it should be, but whatever difference between the
two of them mananged to seriously screw up my code.

Any ideas why this happened?
 
T

Thomas J. Gritzan

Morgan said:
Ok folks!

Problem is solved :)

It is a bit odd though:

Apparently using .at() with a string is NOT equivalent to using index
notation i.e. mystr[] is not mystr.at()

It is equivalent if your index is not out-of-bounds, that is
mystr.at(i) is ok as long as 0 <= i < mystr.size().

If the index is out-of-bounds, at() will throw an exception you need to
catch, and operator[] will yield undefined behaviour that you have to avoid.
I mean, logically it should be, but whatever difference between the
two of them mananged to seriously screw up my code.

Any ideas why this happened?

You try to access a string with a wrong index.

Your problem is here:
for(int i = 0; i < 20; i++)
{
// here I assign a character from a string to an
// element in an array of char (need to use char)
newDVD.production_company =
production_companies[production_company_choice].at(i);
}

newDVD.production_company is char[20], production_companies is an array
of std::string.
You can't access an element in a string with index >= string::size().
You have to stop right before this element, and append the terminating
'\0' character.
 
M

Morgan

As others have noted, your issue is using string::at() beyond the end
of the string.  Because you are not catching the exception thrown by at
(), your code is falling into std::terminate().

It doesn't terminate naturally, it crashes the program and displays a
huge amount of bletch on the console. Unless that is what you meant by
std::terminate()?!

I'm pretty surprised that the complier (Bloodshed's Dev C++, which I
still think is pretty good, esp: that I can run it off my flash drive
cos it's so small) didn't catch it, it seems kind of obvious now to
me, I don't see why the complier couldn't have picked it up, it's not
as if it was a run-time decision that lead to this problem. (I suppose
you'll tell me that I should be my own complier ;-)
 
M

Morgan

Morgan said:
Ok folks!
Problem is solved :)
It is a bit odd though:
Apparently using .at() with a string is NOT equivalent to using index
notation i.e. mystr[] is not mystr.at()

It is equivalent if your index is not out-of-bounds, that is
  mystr.at(i) is ok as long as 0 <= i < mystr.size().

If the index is out-of-bounds, at() will throw an exception you need to
catch, and operator[] will yield undefined behaviour that you have to avoid.
I mean, logically it should be, but whatever difference between the
two of them mananged to seriously screw up my code.
Any ideas why this happened?

You try to access a string with a wrong index.

Your problem is here:
   for(int i = 0; i < 20; i++)
   {
      // here I assign a character from a string to an
      // element in an array of char (need to use char)
      newDVD.production_company =
      production_companies[production_company_choice].at(i);
   }

newDVD.production_company is char[20], production_companies is an array
of std::string.
You can't access an element in a string with index >= string::size().
You have to stop right before this element, and append the terminating
'\0' character.



Cool, thanks! I forgot that null isn't automatically inserted into
arrays of char at the end. <groan>
 
M

Morgan

I sent you a reply, but google groups appears to have lost it, I'll
reply later; Morgan GOTO: Class :D
 
R

red floyd

Morgan said:
It doesn't terminate naturally, it crashes the program and displays a
huge amount of bletch on the console. Unless that is what you meant by
std::terminate()?!
No, that's not what I meant. std::terminate() is a function that gets
invoked when an uncaught exception occurs. Other than causing the
the program to terminate, it's behavior is (I believe) implementation
defined.

On many Unix platforms, it causes a core dump. On MSVC, it puts up the
message that you are seeing.
I'm pretty surprised that the complier (Bloodshed's Dev C++, which I
still think is pretty good, esp: that I can run it off my flash drive
cos it's so small) didn't catch it, it seems kind of obvious now to
me, I don't see why the complier couldn't have picked it up, it's not
as if it was a run-time decision that lead to this problem. (I suppose
you'll tell me that I should be my own complier ;-)
How, exactly, should the "pick it up"? The footprint of at() does not
carry an exception specification, and even if it did, a function is not
required to catch or forward any exceptions in the specifications of
functions that it calls.
 
M

Morgan

No, that's not what I meant.  std::terminate() is a function that gets
invoked when an uncaught exception occurs.  Other than causing the
the program to terminate, it's behavior is (I believe) implementation
defined.

On many Unix platforms, it causes a core dump.  On MSVC, it puts up the
message that you are seeing.
Ok!

How, exactly, should the "pick it up"?  The footprint of at() does not
carry an exception specification, and even if it did, a function is not
required to catch or forward any exceptions in the specifications of
functions that it calls.

Well, I would have assumed (incorrectly obviously, but still) that if
your program was using an end-index in a for loop that could never be
reached by a string's at() function because the String object knows
that how large it is, then that should produce an error, or at least a
warning message.

You said a function isn't required to forward exceptions? For my
functions that makes sense, but surely not for functions built into
the language like mystring.at()?

Why is that? Shouldn't (standard language functions like at()) give
useful information to the complier which could then be used to create
an informative error message? eg: the index out of bounds error I've
had on other occasions.

Or am I flying on past what you were saying at a height of 20km? ;-)
 
M

Morgan

Morgan said:
Ok folks!
Problem is solved :)
It is a bit odd though:
Apparently using .at() with a string is NOT equivalent to using index
notation i.e. mystr[] is not mystr.at()
I mean, logically it should be, but whatever difference between the
two of them mananged to seriously screw up my code.
Any ideas why this happened?

The problem you're seeing is here:

     for(int i = 0; i < 20; i++) {
         newDVD.production_company =
             production_companies[production_company_choice].at(i);
     }

Your production company names are not 20 characters long, so you are
trying to access memory past their end.  std::string::at is correctly
reporting the error by throwing an exception.  std::string::eek:perator[]
does not check its range, so you're getting "lucky."

You should not have to deal with such low-level details as
character-by-character input.  I don't think I've ever seen
std::cin.ignore used in production code.

Here are some suggestions:

1. Get rid of the using-directive for namespace std.

2. Stop using raw arrays as generic container types.  Most of the arrays
in this example probably be replaced by std::string and std::vector.  If
memory layout is important, at least wrap the arrays in a class template
that is parameterized by a Value_type, a Size, and an Index_check_policy.

3. Factor all of the hard-coded numbers and strings out of the business
logic, and into a configuration namespace.

4. Break up your code into much smaller functions.  You should almost
never need a function whose definition exceeds 80 columns by 24 rows.

5. Write little test programs as you go, and save them to be run as a
test suite.

Good luck.


I'll try your suggestions, particully the bit about seperating the
output presentation from the functionality into configuration
namespaces (albeit I don't know how yet! :cool: because I think that
would hit two birds with one stone (smaller functions + they would be
better because it would be easier to see ways to improve them)

I don't know how to (& a lot of things!) use vectors, or class
templates, which is why I'm using the whole string/array of char
conservsion business. (have to use char array because like you say,
the distrubtion of memory is important as I'm using files + random
access, using strings for the reason that I imagined it to be easier
than arrays of char)

Anyways, thanks!
 
R

Richard Herring

In message
Well, I would have assumed (incorrectly obviously, but still) that if
your program was using an end-index in a for loop that could never be
reached by a string's at() function because the String object knows
that how large it is,

The string doesn't "know" until runtime what its size is. Granted, in
this case the compiler might be able to work it out, but mostly that's
not possible, and the compiler overhead to analyse every possible use
would be enormous. That's why at() performs a runtime test.
then that should produce an error, or at least a
warning message.

And that's exactly what it does. The at() call throws a
std::eek:ut_of_range exception. That property is precisely why you would
choose to use at() instead of []. But _you_ need to provide code that
will catch that exception, extract the message it contains, and do
something with it. For example

// warning: untested code
try
{
// do stuff...
}
catch (std::exception & e)
{
std::cerr << e.what();
}

Note that it's up to you to decide what to do with the exception. C++
doesn't automatically write it to the console for you, because there
might not _be_ a console.
You said a function isn't required to forward exceptions? For my
functions that makes sense, but surely not for functions built into
the language like mystring.at()?

You misunderstand. What Red is saying is that there's no requirement for
the function which calls at() to catch any exceptions it throws, because
it might make more sense for some function further out to handle it.
Why is that? Shouldn't (standard language functions like at()) give
useful information to the complier

Not the compiler, the runtime environment.
which could then be used to create
an informative error message? eg: the index out of bounds error I've
had on other occasions.

Add a catch clause and see for yourself...
Or am I flying on past what you were saying at a height of 20km? ;-)
<whooosh>
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,764
Messages
2,569,566
Members
45,041
Latest member
RomeoFarnh

Latest Threads

Top