Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Post
  • Reply
blorpy
Jan 5, 2005

TheSleeper posted:

No offense, but isn't it a whole lot better to at most provide a pseudocode solution?

Also, it doesn't really matter much in this case, but with your solution if, for some reason, it fails to open the input file but opens the output file just fine it will never close the output file.

The best solution would be to open the output file after testing to see if the input file was open.

I wasn't trying to provide the completely correct solution, just something that actually does the core part of the problem. Hopefully he/she will go over that code and fix and understand it before turning it in.

Adbot
ADBOT LOVES YOU

Mustach
Mar 2, 2003

In this long line, there's been some real strange genes. You've got 'em all, with some extras thrown in.

TheSleeper posted:

No offense, but isn't it a whole lot better to at most provide a pseudocode solution?

Also, it doesn't really matter much in this case, but with your solution if, for some reason, it fails to open the input file but opens the output file just fine it will never close the output file.

The best solution would be to open the output file after testing to see if the input file was open.
close() doesn't need to be explicitly called, anyhow. The destructors will take care of it.

Zombywuf
Mar 29, 2008

floWenoL posted:

Unless someone overrode operator& for vectors somewhere before. :q:

I think you don't understand how std::swap works for vectors.

almostkorean
Jul 9, 2001
eeeeeeeee
I'm working on big number functions for some Project Euler stuff, but I'm running into some problems. I'm using a Dlist class that I made for my programming course last semester, and I need to change part of it, I'm just not sure how to do it.

Here's my insertFront function:

code:
template <class T>
void Dlist<T>::insertFront(T *o)
{
  node *np = new node;
  np->next = first;
  np->prev = NULL;
  np->o = o;
  if (isEmpty()) {
    last = np;
  }
  else {
    first->prev = np;
  }
  first = np;
}
and here's my incomplete long add function:

code:
Dlist<int> longAdd (Dlist<int> ilist1, Dlist<int> ilist2)
{
   Dlist<int> result;
   int * tmp = new int(0);
   int * carry = new int(0);
   int *d1 = new int;
   int *d2 = new int;

   while(!ilist2.isEmpty())
   {
     d1 = ilist1.removeBack();
     d2 = ilist2.removeBack();
     *tmp = (*d1) + (*d2) + (*carry);
     *carry = (*tmp)/10;
     *tmp = (*tmp) % 10;
     result.insertFront(tmp);
   }
   return result;
}
I know what's going wrong, each new node is pointing to that same tmp, I'm just not sure how to work around it. I could change my Dlist so each node just holds an int instead of a pointer, but I feel like that's kinda cheap. Is there a better way to get around this?

Pooball
Sep 21, 2005
Warm and squishy.
Use an STL vector, with the most significant digit last. Adding to the end of a vector (push_back) is fast.

If you really need to insert stuff at both ends of the decimal representation, use an STL list ("list" is doubly linked; "slist" is singly linked).

If you want to write your own data structure, don't use pointers, use values. You're using templates, so your code is already abstract.

If you want to use pointers, just allocate the int when you need to.

int tmp=0;
...
result.insertFront(new int<tmp>);

rdgb
Sep 24, 2007

I'm the man, and the mans the man, and that's just the way it is.
Learning C++ out of a book called C++ Primer Plus, on the final programming exercise of the chapter I am on I've got a problem.
The exercise is "Do Programming Exercise 6, but, instead of declaring an array of three CandyBar structures, use new to allocate the array dynamically". Exercise 6 is basically there is this CandyBar structure and it has 3 member, one to hold the brand name one to hold the weight which has to be able to hold fractional parts, and one to hold the weight which is an integer. And you have 3 of these structures in an array, you have to initialize it within the program, and then the program will display all these values on screen when run.

code:
#include <iostream>
using namespace std;
struct CandyBar
{
       char name[20];
       double weight;
       int calories;
       };
       main ()
       {
            CandyBar *abcd = new CandyBar[3];
            abcd[1].name = "thing";
            abcd[1].weight = 20.5;
            abcd[1].calories = 40;
            abcd[2].name = "another";
            abcd[2].weight = 34.1;
            abcd[2].calories = 9;
            abcd[3].name = "finally";
            abcd[3].weight = 111.1;
            abcd[3].calories = 1;
            cout << "1st Name: " << abcd[1].name << endl;
            cout << "2nd Name: " << abcd[2].name << endl;
            cout << "3rd Name: " << abcd[3].name << endl;
            cout << "1st weight: " << abcd[1].weight << endl;
            cout << "2nd weight: " << abcd[2].weight << endl;
            cout << "3rd weight: " << abcd[3].weight << endl;
            cout << "1st Calories: " << abcd[1].calories << endl;
            cout << "2nd Calories: " << abcd[2].calories << endl;
            cout << "3rd Calories: " << abcd[3].calories << endl;
            cin.get();
            return 0;
            }
The problem I have is in the name, when I take the lines where I declare the values of the names the program runs fine. But with what I have the 3 lines about the name get the following errors :

code:
12: error: incompatible types in assignment of `const char[6]' to `char[20]'
15: error: incompatible types in assignment of `const char[8]' to `char[20]'
18: error: incompatible types in assignment of `const char[8]' to `char[20]'
So, please help me with not getting this error.

rdgb fucked around with this message at 22:38 on Jul 23, 2008

Avenging Dentist
Oct 1, 2005

oh my god is that a circular saw that does not go in my mouth aaaaagh
Just use std::string instead of an array of char. 99% of the time, char arrays aren't what you want (and it would take a lot more to explain how to do string manipulation the old-school C way).

Standish
May 21, 2001

abc[1].name is an array; you can't assign to it directly like that. You'll need to use strcpy() to copy "thing" into the array.

Or alternatively you could change "CandyBar::name" from an array into a pointer:
code:
struct CandyBar 
{ 
    [b]char *name;[/b] 
    double weight; 
    int calories; 
}; 
Explanation here.

rdgb
Sep 24, 2007

I'm the man, and the mans the man, and that's just the way it is.

Avenging Dentist posted:

Just use std::string instead of an array of char. 99% of the time, char arrays aren't what you want (and it would take a lot more to explain how to do string manipulation the old-school C way).

My compiler doesn't support the use of string class in structures, or at least, it doesn't appear to. When I change it to a string then run it, the program doesn't display anything as if it gets stuck on it or something.

Avenging Dentist
Oct 1, 2005

oh my god is that a circular saw that does not go in my mouth aaaaagh

BloodE posted:

My compiler doesn't support the use of string class in structures, or at least, it doesn't appear to. When I change it to a string then run it, the program doesn't display anything as if it gets stuck on it or something.

It has to support that. That's one of the most basic C++ language features. You're doing something like the following, right?

code:
#include <string>
using namespace std;

struct CandyBar
{
    string name;
    double weight;
    int calories;
};

int main()
{
    // ...
    abcd[0].name = "Foobar";
}

rdgb
Sep 24, 2007

I'm the man, and the mans the man, and that's just the way it is.

Standish posted:

abc[1].name is an array; you can't assign to it directly like that. You'll need to use strcpy() to copy "thing" into the array.

Or alternatively you could change "CandyBar::name" from an array into a pointer:
code:
struct CandyBar 
{ 
    [b]char *name;[/b] 
    double weight; 
    int calories; 
}; 
Explanation here.

strcpy worked fine thanks.

Avenging Dentist posted:

It has to support that. That's one of the most basic C++ language features. You're doing something like the following, right?

code:
#include <string>
using namespace std;

struct CandyBar
{
    string name;
    double weight;
    int calories;
};

int main()
{
    // ...
    abcd[0].name = "Foobar";
}

I am doing it like that and the compiler(Dev-C++)just doesn't display anything other than the black screen and the flashing _ cursor. My book says this of a structure using a string class member :

quote:

Can you use a string class object instead of a character array for the name member? That is, can you declare a structure like this:
code:
#include<string>
struct inflatable
{
std::string name;
float volume;
double price;
};
In principle, the answer is yes. In practice, the answer depends on which compiler you use because some (including Borland C++ 5.5 and Microsoft Visual C++ prior to version 7.1) do not support initialization of structures with string class members.

Of course the compiler I'm using works with string objects fine otherwise, but it doesn't seem to like strings in structures.

Avenging Dentist
Oct 1, 2005

oh my god is that a circular saw that does not go in my mouth aaaaagh

BloodE posted:

Of course the compiler I'm using works with string objects fine otherwise, but it doesn't seem to like strings in structures.

I just tried it in Dev-C++ 4 point whatever and it works fine. Still, Dev-C++ is the shittiest IDE in the world. Just use Visual C++ Express.

Also, this investigation has led me to believe that the author of that book is a complete tool.

Avenging Dentist fucked around with this message at 23:12 on Jul 23, 2008

Vanadium
Jan 8, 2005

You are obviously doing it wrong because every C++ compiler, especially g++ used in Dev-C++, supports strings as struct members.

You will want to get a better book.

Volte
Oct 4, 2004

woosh woosh
I'm not sure why the compiler would discriminate against strings over any other class. And if it compiles at all, it's not the compiler's fault. If it really didn't support strings in structs for some reason, it would likely toss an error.

TheSleeper
Feb 20, 2003

Mustach posted:

close() doesn't need to be explicitly called, anyhow. The destructors will take care of it.

Yes, but it's important to get young programmers in the habit of allocating and freeing resources at appropriate times.

Avenging Dentist
Oct 1, 2005

oh my god is that a circular saw that does not go in my mouth aaaaagh

TheSleeper posted:

Yes, but it's important to get young programmers in the habit of allocating and freeing resources at appropriate times.

And it's more important to get people in the habit of considering the concept of RAII when writing C++. :colbert:

Avenging Dentist fucked around with this message at 23:21 on Jul 23, 2008

more falafel please
Feb 26, 2005

forums poster

quote:

Can you use a string class object instead of a character array for the name member? That is, can you declare a structure like this:
code:
#include<string>
struct inflatable { std::string name; float volume; double price; };
In principle, the answer is yes. In practice, the answer depends on which compiler you use because some (including Borland C++ 5.5 and Microsoft Visual C++ prior to version 7.1) do not support initialization of structures with string class members

I think this is saying that some old compilers don't allow initialization of structs with string members, like:
code:
#include<string>
struct inflatable { std::string name; float volume; double price; };

inflatable foo = { "foo", 3.14f, 3.14 };
Which is a totally different problem. Plus, I think DevC++ uses GCC, (right?) which would not have this problem in the first place. If your program is running with no output, it's because of a different problem. Maybe post the code you were having problems with?

Also, I noticed this:

quote:

code:
CandyBar *abcd = new CandyBar[3];
abcd[1].name = "thing";
abcd[1].weight = 20.5;
abcd[1].calories = 40;
abcd[2].name = "another";
abcd[2].weight = 34.1;
abcd[2].calories = 9;
abcd[3].name = "finally";
abcd[3].weight = 111.1;
abcd[3].calories = 1;

The valid indices of a 3-element array are 0, 1, or 2, not 1, 2, or 3.

Incoherence
May 22, 2004

POYO AND TEAR

Avenging Dentist posted:

And it's more important to get people in the habit of considering the concept of RAII when writing C++. :colbert:
It helps if you know what RAII is supposed to do when you write your own objects, which implies that you know how to free resources when you no longer need them.

more falafel please
Feb 26, 2005

forums poster

Avenging Dentist posted:

And it's more important to get people in the habit of considering the concept of RAII when writing C++. :colbert:

Do you write return 0;?

Avenging Dentist
Oct 1, 2005

oh my god is that a circular saw that does not go in my mouth aaaaagh

more falafel please posted:

Do you write return 0;?

What?

Mustach
Mar 2, 2003

In this long line, there's been some real strange genes. You've got 'em all, with some extras thrown in.
Maybe he's trying to make some veiled commentary on you that's somehow related to how main() doesn't require a return statement, instead of just directly stating his point.

Mustach fucked around with this message at 03:26 on Jul 24, 2008

more falafel please
Feb 26, 2005

forums poster

Avenging Dentist posted:

What?

Yeah, this was not a well-thought out post.

What I meant was that calling close() is kind of like return 0 in main() -- you don't need to do it, but it makes things clearer and is in general good practice, in my opinion. But then when I think about it, that means if I had a scoped RAII mutex class, I should call unlock() on it before it goes out of scope, which I wouldn't do.

So never mind, for some reason I support calling close() on fstreams, even though there's no point.

StickGuy
Dec 9, 2000

We are on an expedicion. Find the moon is our mission.

Pooball posted:

If you really need to insert stuff at both ends of the decimal representation, use an STL list ("list" is doubly linked; "slist" is singly linked).
:psyduck: Why not use an STL deque?

Lexical Unit
Sep 16, 2003

When is it safe to use this idiom:
code:
std::vector<T> v;
T* p = &v[0];
For example I want to do something like this:
code:
const size_t n = 10;
std::vector<int> ints (n);
ints.resize (n);
third_party_c_api_grab_10_ints (&ints[0]); // fill up ints vector with 10 ints
Safe?

That Turkey Story
Mar 30, 2003

Lexical Unit posted:

When is it safe to use this idiom:

Vectors are always guaranteed to take up contiguous space, but after you resize the sequence, any pointer you had into the sequence before becomes invalid.

Edit: So in other words, yes, your second example is safe (though the first one isn't because the vector is empty).

Lexical Unit
Sep 16, 2003

That Turkey Story posted:

Edit: So in other words, yes, your second example is safe (though the first one isn't because the vector is empty).
Awesome. I thought I read somewhere that using that idiom to fill a vector was bad, but it was just on some crappy blog and I never really trusted it. And being that I almost never need to use that idiom, especially for filling up a vector, I never looked into it further. Thanks for the clarification :)

Also, I'm just curious if there's a better way to get a char** out of a std::vector<std::string> than just allocating a char** big enough to store the memory and filling it manually in a loop:

code:
void dress(std::vector<std::string>& pants)
{
	char** fruitloops = new char*[pants.size ()];
	for (size_t i = 0; i < pants.size (); ++i)
	{
		fruitloops[i] = new char[pants[i].size () + 1];
		strncpy (fruitloops[i], pants[i].c_str (), pants[i].size () + 1);
	}
	
	crappy_thrid_party_api (fruitloops, pants.size ());

	for (size_t i = 0; i < pants.size (); ++i)
	{
		delete [] fruitloops[i];
	}
	delete [] fruitloops;
}

Lexical Unit fucked around with this message at 18:19 on Jul 25, 2008

JoeNotCharles
Mar 3, 2005

Yet beyond each tree there are only more trees.

Lexical Unit posted:

Awesome. I thought I read somewhere that using that idiom to fill a vector was bad, but it was just on some crappy blog and I never really trusted it. And being that I almost never need to use that idiom, especially for filling up a vector, I never looked into it further. Thanks for the clarification :)

Off the top of my head, I'd say it's bad because if you miscalculate the size of the vector so you don't actually have enough space, bad things will happen. It's not terribly defensive programming. But if you do everything right it should work fine.

That Turkey Story
Mar 30, 2003

Lexical Unit posted:

Awesome. I thought I read somewhere that using that idiom to fill a vector was bad, but it was just on some crappy blog and I never really trusted it. And being that I almost never need to use that idiom, especially for filling up a vector, I never looked into it further. Thanks for the clarification :)

Also, I'm just curious if there's a better way to get a char** out of a std::vector<std::string> than just allocating a char** big enough to store the memory and filling it manually in a loop:

code:
void dress(std::vector<std::string>& pants)
{
	char** fruitloops = new char*[pants.size ()];
	for (size_t i = 0; i < pants.size (); ++i)
	{
		fruitloops[i] = new char[pants[i].size () + 1];
		strncpy (fruitloops[i], pants[i].c_str (), pants[i].size () + 1);
	}
	
	crappy_thrid_party_api (fruitloops, pants.size ());

	for (size_t i = 0; i < pants.size (); ++i)
	{
		delete [] fruitloops[i];
	}
	delete [] fruitloops;
}

First, watch out because that code isn't exception safe! If any of those new operations in the for loop throw bad_alloc, you are leaking memory. Make sure you handle and rethrow or use RAII. A simple start is to make fruitloops a std::vector instead of a char** (or perhaps better, a smart pointer like boost::scoped_array if you have boost).

Second, do you mean the API takes a char** or char const* const*? If it's just an API not using const correctly, as in it's taking const-unqualified data even though it's guaranteed to not modify the data, you can just make a std::vector or scoped_array of char const* and then const_cast when passing the data through the API.

Lexical Unit
Sep 16, 2003

That Turkey Story posted:

First, watch out because that code isn't exception safe! If any of those new operations in the for loop throw bad_alloc, you are leaking memory.
Oops!

That Turkey Story posted:

Make sure you handle and rethrow or use RAII. A simple start is to make fruitloops a std::vector instead of a char** (or perhaps better, a smart pointer like boost::scoped_array if you have boost).
No boost :( Do you mean a std::vector<const char*>? I've got a std::vector<std::string>, so you mean populate a const char* version by iterating through the std::string version and calling std::string::c_str() on each element? I thought you couldn't do that because of how std::string::c_str() works.

That Turkey Story posted:

Second, do you mean the API takes a char** or char const* const*?
The API is this: http://tronche.com/gui/x/xlib/window-information/XInternAtoms.html (abandon all hope ye who clicks here). In particular I'm trying to construct the char** names parameter for the function's consumption, then I can promptly throw it away.

That Turkey Story posted:

If it's just an API not using const correctly, as in it's taking const-unqualified data even though it's guaranteed to not modify the data, you can just make a std::vector or scoped_array of char const* and then const_cast when passing the data through the API.
I believe that the function in question will leave the char** alone, but I'm a bit confused about how you mean to construct your std::vector regardless.

ShoulderDaemon
Oct 9, 2003
support goon fund
Taco Defender

Lexical Unit posted:

The API is this: http://tronche.com/gui/x/xlib/window-information/XInternAtoms.html (abandon all hope ye who clicks here).

Have you considered using XCB instead of xlib? It's much nicer.

Lexical Unit
Sep 16, 2003

ShoulderDaemon posted:

Have you considered using XCB instead of xlib? It's much nicer.
Yes it certainly is. But xcb is not allowed for pretty much the same reason boost isn't allowed: bureaucracy.

That Turkey Story
Mar 30, 2003

Lexical Unit posted:

Oops!
No boost :( Do you mean a std::vector<const char*>? I've got a std::vector<std::string>, so you mean populate a const char* version by iterating through the std::string version and calling std::string::c_str() on each element? I thought you couldn't do that because of how std::string::c_str() works.

...


I believe that the function in question will leave the char** alone, but I'm a bit confused about how you mean to construct your std::vector regardless.

In other words (untested):

code:
void dress( std::vector< std::string >& pants )
{ 
  std::vector< char const* > fruitloops( pants.size() );

  std::transform( pants.begin(), pants.end()
                , fruitloops.begin()
                , std::mem_fun_ref( &std::string::c_str )
                );
	
  crappy_thrid_party_api( const_cast< char** >( &fruitloops.front() )
                        , fruitloops.size()
                        );
}

Lexical Unit
Sep 16, 2003

Heh, I just wrote something like that (I didn't use the fancy call to std::transform()). I realized this was essentially the same thing with my question about the &vector[0] idiom. The pointer returned by c_str() is valid to use so long as the string remains unchanged, correct? I think I'm getting the hang of this... I hardly ever need to think about this because I'm usually not interfacing with C libraries.

It seems to work just fine, thanks for all the pointers ;)

That Turkey Story
Mar 30, 2003

Lexical Unit posted:

The pointer returned by c_str() is valid to use so long as the string remains unchanged, correct? I think I'm getting the hang of this... I hardly ever need to think about this because I'm usually not interfacing with C libraries.

Yeah.

Avenging Dentist
Oct 1, 2005

oh my god is that a circular saw that does not go in my mouth aaaaagh
Does anyone here know if anything has happened lately with the extensible literals proposal for C++0x? (I'm looking at you, TTS.) I feel like I'm the only one looking forward to it, just because it would allow the following:

code:
tuple<T0,T1,T2,T3,T4> tup;

// Old way:
tup.at<1> = T1("woop woop");
// New way:
tup[1c] = T1("woop woop");

Vanadium
Jan 8, 2005

Avenging Dentist posted:

Does anyone here know if anything has happened lately with the extensible literals proposal for C++0x? (I'm looking at you, TTS.) I feel like I'm the only one looking forward to it, just because it would allow the following:

code:
tuple<T0,T1,T2,T3,T4> tup;

// Old way:
tup.at<1> = T1("woop woop");
// New way:
tup[1c] = T1("woop woop");

Would that not be about making operator[] a constexpr thing?

Avenging Dentist
Oct 1, 2005

oh my god is that a circular saw that does not go in my mouth aaaaagh

Vanadium posted:

Would that not be about making operator[] a constexpr thing?

I guess you could do it with a combination of constexpr and the new function declaration syntax, but I was thinking that the "c" suffix would return an object of type boost::mpl::int_<...>.

Why can't someone just write a compiler that implements all of 0x so I can play with it? :(

AuMaestro
May 27, 2007

I keep having with this code that's pretty much at the core of my program. It's been more or less like this for months, and it works fine until I try to do something special. (in C++)

code:
list<Actor *>::iterator ci;
Actor *actor;
for (ci=actorList.begin();ci != actorList.end(); ++ci)
{
	actor = *ci;
	actor->act();
	actor->maintain();
								
}
All this works fine, except that sometimes I need to be able to change actorList on the fly (through act or maintain). Even that's no problem, of course, as long as I'm adding elements or removing elements other than the current one. So, the behavior I need is to be able to get rid of the current actor without having problems. In other words, removing the element referred to by ci invalidates ci, so there's no way to increment it. I know that this should be really trivial, but I don't have any real documentation on iterators or the list template, and what I can find does stuff that's so unrelated that I can't use it to help me.

Avenging Dentist
Oct 1, 2005

oh my god is that a circular saw that does not go in my mouth aaaaagh
code:
list<Actor *>::iterator ci = actorList.begin();
Actor *actor;
while(ci != actorList.end())
{
	actor = *ci;
	++ci;
	actor->act();
	actor->maintain();
								
}
EDIT: Obviously this only works if your goal is to modify the current element only. Having the ability to remove arbitrary elements is going to cause you headaches no matter how you do it though, especially if the order of the actors isn't important. The behavior of removing an actor before you in the list is different from the behavior of removing an actor after you in the list.

EDIT x2: A super-simple solution would be to have act/maintain return a bool to specify whether actor should suicide.

Avenging Dentist fucked around with this message at 03:11 on Jul 27, 2008

Adbot
ADBOT LOVES YOU

AuMaestro
May 27, 2007

Avenging Dentist posted:


EDIT: Obviously this only works if your goal is to modify the current element only. Having the ability to remove arbitrary elements is going to cause you headaches no matter how you do it though, especially if the order of the actors isn't important. The behavior of removing an actor before you in the list is different from the behavior of removing an actor after you in the list.

Yeah, that code won't work, because that crashes the program if I only have one element. I was working on another solution, but you brought up a point I wasn't expecting: how different is it to remove elements of a list between them being before or after?

If not for that, there's no problem. If I define a static replacement, and use it instead, I can put in this (not yet working) code, that should give me a valid pointer after removing an actor

code:
if ((*Game::actorIterator) == this) 
{
     Game::actorIterator = Game::actorList.erase(Game::actorIterator);
}

quote:

EDIT x2: A super-simple solution would be to have act/maintain return a bool to specify whether actor should suicide.

That's plausible, but I'm not sure if I understand. If I know in the loop whether or not I need to get rid of someone, how does that help me actually keep that iterator from going bad?

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply