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
nielsm
Jun 1, 2009



Mopp posted:

oh, sorry. i'm looking for something that I can just show my files, and let it do all the linking needed to create the makefile. a makefile generator, in other words.

Let's say you have three source files, file1.cpp file2.cpp file3.cpp

You want to compile those and link into a program named awesome.

Here's a makefile that should accomplish that:

code:
awesome: file1.o file2.o file3.o
        $(CXX) file1.o file2.o file3.o -o awesome
I think there is some way to simplify it further, but I couldn't make it work at this time. (I'm quite sure it's possible to get make to write the linking commandline as well, just by defining an appropriate target.)
You can set variables such as CXXFLAGS in the makefile too, to affect the default targets that produce objects from C and C++ source files.

Adbot
ADBOT LOVES YOU

nielsm
Jun 1, 2009



User0015 posted:

This isn't so much a C/C++ coding question but a C/C++ IDE question. Namely, I've been learning MSVC-10.0 lately, and one thing about it really bothers me (at least). It leaves its garbage around in my local include folder such as object files, makefiles, and MSVC specific files (.dev, .layout, etc..).

How can I make MSVC clean up its act and throw that garbage in a sub-folder?

Design your project files accordingly.

Start by creating an empty project somewhere else. Set the various output file locations for the project configurations to something useful, I prefer making them relative to the solution directory. Then when you've got all of that fixed, add your source files to the project. MSVC won't pollute any other folders than those you've explicitly given then.
Also learn how to use property files to make re-usable project configuration shards.
If you want to get really advanced, look into the MSBuild project file format, it can do a whole lot of things.

Oh, and of course you can move your project and solution files around outside the IDE to put them in locations that fit your needs better. They're just text files you can edit, with a bit of care.

nielsm
Jun 1, 2009



Along with the Solution Explorer tab in the (default) left pane, there is also a Property Manager tab. There you can create/add property files and edit them. You can stack multiple property files, and use different stacks for each project configuration. Do note that property files have a Save button of their own, in the Property Manager pane!
The basics are quite simple and I think it took me around 30 minutes to catch on to.

One of the useful features is also that you can define custom macros, you can use in other property values.

Some kind of overview
Custom macros
MSBuild (for hand-editing project and property files, to add more complex logic than the IDE lets you configure)

nielsm
Jun 1, 2009



pr0metheus posted:

I took That Turkey Story's advise and here is my second iteration of SharedPtr class:

I don't quite understand why -> operator works by just returning *. Can somebody explain semantics of it and why returning the pointer works?

Careful about that operator =, you're forgetting to unref the previous pointer, leaking ref counts.

As for operator ->, I'm pretty sure it's just supposed to return the pointer that the object wraps and the compiler then handles all the fancy stuff. You'd need a lot of crazy RTTI if the operator should be able to completely customise the look-up on the right-hand side of the ->. (I think that's what you're getting at.)

nielsm
Jun 1, 2009



wlokos posted:

Right, I'm trying to turn the char argv[1][i] into an int. Would that look like
code:
int key[i] = (int)argv[1][i];
?

I thought wrapping it in apostrophes made it an int because I did things like
code:
if(message[i]>='a')
and it worked in the past, which I think I got from an example somewhere. But clearly I'm misunderstanding something about that.

The latter works because it's the value of a literal 'a' you want, not the value of something stored in a variable named 'a'.

The quotes signify a literal value: Single quotes (apostrophes) are character values, and double quotes are string values (character arrays implicitly terminated by a \0 character).

When you want to convert the value stored in a variable to a different data type, you use a typecast operator, as you do in your first code block here.

nielsm
Jun 1, 2009



litghost posted:

std::_Tree is a utility classed used to implement std::set and std::map. What it likely means is you are using a library that was built against MSVC, and tried to build the new shared library using gcc. That will never work because of the differences in the C++ implementation's between MSVC and gcc. Whichever library brought in std::_Tree needs to be recompiled with gcc compiler (assuming that is your target compiler).

If he's actually building on Linux, as I understand, then it won't be a case of libraries built with the wrong compiler (MSVC for Linux? Nah.), but source code depending on implementation details of the Dinkumware STL.

Check if there isn't somewhere you can configure something about the compiler or standard library being used, because it sounds like it's some wrong code being pulled in. Also look for std::_Tree in the Ogre source code, and if they actually do use that explicitly anywhere, write an angry mail to the developers telling them to stop relying on implementation details.

nielsm
Jun 1, 2009



That function is a remote exploit waiting to happen, too. You should at the very least also pass the length of the message to the function, so you don't read past the end of it, in case the dataSize field is wrong, intentionally or not.
(That might even be what is really happening.)

Also this:
code:
struct NetworkData {
    int type;
    int count;
    char data[1];
};
char *message = ...;
NetworkData *nd = static_cast<NetworkData*>(message);
While the data field in the struct is declared as just a single byte, neither C nor C++ will complain if you address it past that index. By declaring the struct in network order, you can simply cast the raw data to it and use it directly.
That's quick and dirty.

The safe way is to cross-check everything and copy every field over to something more convenient to work with.
Are you sure you won't have to deal with machines with different byte order (endianness) or different size of the basic int type?

nielsm
Jun 1, 2009



Mustach posted:

Unless he's in a world where sizeof int == sizeof char, that's very dirty, because nothing about that struct definition ensures that those ints will be in network byte order (or unpadded). It would also have to be a reinterpret_cast; that static_cast won't compile.

I wrote network order (order the data fields are transmitted in), not network byte order. I'm fully aware that my code assumes that the byte order of the data from the network is the same as the machine byte order. nop's original code assumes that as well. My code also assumes that packing is set appropriately. Yes I should have mentioned that.
You're right about the cast.

nielsm
Jun 1, 2009



Unless you're required to use GCC, setting Visual C++ Express is easy and won't cost you a penny.

Although, if your class is going to include anything about Makefiles you won't be able to follow that since VC++ doesn't have a (fully?) Unix-compatible Make tool.


Or install some Linux distro on some machine, which could be a virtual machine.

nielsm
Jun 1, 2009



Brecht posted:

Precompiled headers.

/game set match: Brecht

Disable it? VC doesn't force you to use PCH, and the standard AppWiz even asks if you want to use them.

nielsm
Jun 1, 2009



On Win32, windows are owned by threads and each thread that owns windows should have a message loop. You can send messages to windows belonging to other threads and processes, and most programmatic interactions with windows happen through messages. (Those that don't are generally thread safe.)

GTK, I believe, requires all GUI access to be done through one thread, generally the main one. It should be possible to use Xlib in multiple threads if it's initialised correctly.

I don't know much about how threads interact with GUI in Mac OS X. I think it's safest to assume it also wants GUI stuff to be done in the main thread.


There's two reasonable designs I can see for your problem. One would be a function the students can call from their code, that takes a callback function pointer, or a pointer to an object type with a virtual entry point method. In the provided function you'd set up the GUI and spawn a new thread for the students' graphics code to run in, this thread would then call the student's callback.
The other would be providing an implemented main function and mandating that the students implement a function by a different name, that will then be their main function.
Both of those ways should ensure that the GUI code will be running in the main thread and the students' code in another. I see the first as more flexible, but also requiring more advanced concepts to use. (Function pointers or virtual inheritance.)

nielsm
Jun 1, 2009



I think the linker is supposed to warn, or even error, about duplicate symbols there.

Standish: What's wrong with putting implementation details in source files? Only, those details should be hidden in a namespace unless there isn't a good reason not to.

nielsm
Jun 1, 2009



Lowclock posted:

I know it's probably something simple and stupid, but I've poured over this for a while and can't seem to figure out what's wrong with that one part.

code:
int FancyDateClass::subtract(FancyDateClass &obj1)
{
        int day1;
        day = julianDate();
        day1=obj1.julianDate();
        int d=day-day1;
        return d;
}
The "day" variable you're assigning on the second line in the body happens to be the member variable of the class, you're overwriting the stored day of month value with the absolute day number.
(This is easy to tell because you're assigning to a variable not declared locally in the function. I'm guessing you haven't touched the subject of const correctness in class, but it's something that could have prevented this mistake in the first place.)

When calculating a difference between two objects or values, or writing a comparison function of sorts, I like to simply call the two values "a" and "b", or for member functions that take another object of the same class, call the parameter "other". (So you're comparing either "a" and "b", or "this" and "other".)

In this case, I wouldn't store the intermediate values from the julianDate() calls nor the intermediate difference. Simply make the function body:
return julianDate() - other.julianDate();
Clear and to the point.


Also, I would cringe if I saw that julianDate() function in real code. It's a really complex calculation you're doing there and you're probably better off doing it with a number of explicit intermediate results and with comments explaining what's going on.
For instance, I can't tell how it deals with leap years, if at all. That stuff needs to be documented!

nielsm fucked around with this message at 02:12 on Feb 7, 2011

nielsm
Jun 1, 2009



Jam2 posted:

What do I need to get started writing code and compiling C on windows?

Visual C++ Express

Jam2 posted:

What about on OS X?

Xcode Tools from your OS X install DVD.

nielsm
Jun 1, 2009



First, the cat command is here just used to print the contents of a file. (Cat is for concatenate, write contents of input files serially on stdout.)


I'm not sure what level of guidance you're otherwise asking for. You'd probably want to construct a DFM (deterministic finite-state machine) that matches the input pattern, but it really depends on the class you're taking. (Are you learning C++ or are you learning text processing?)

nielsm
Jun 1, 2009



I think the easiest way might be to do a recursive algorithm.

Pseudocode:
code:
partial_match (pattern, text):
	if pattern is empty:
		return true

	get first character in pattern
	if character is escape character (\):
		first character is next character in pattern
	else if next character in pattern is optional character marker (?):
		set optional match flag to true

	// see if current character matches
	set direct match flag to: match first character in pattern against first character in text

	// if this character doesn't match and it isn't optional, the match has failed
	// this should also fail when the end of input is reached and there is at least
	// one non-optional character left in the pattern
	if not direct match and not optional match:
		return false

	// the further result of the matching depends on whether
	// the rest of the string matches the rest of the pattern
	set result to: partial_match (pattern[except used characters], text[except first character])

	if optional match:
		// if this character was an optional one, also see whether the rest of the string
		// can match if the optional character isn't used
		boolean 'or' result with: partial_match (pattern[except used characters], text[entire input])

	return result


anywhere_match(pattern, text):
	while text is not empty:
		// test every position in text, whether the pattern matches starting there
		if partial_match(pattern, text):
			return true
		else:
			eat first character of text

	// all of the text was used up with no match
	return false
Seriously, this is a hard problem.

nielsm
Jun 1, 2009



Nalin posted:

Oh yeah, that would definitely work. If we find an optional character, we just recursively call our pattern_match function to match WITHOUT the character. This should take care of all cases.
code:
int pattern_match(char *pattern, char *str)
{
  // Loop through every character in the string.
  for (int i = 0; i <= strlen(str) - strlen(pattern); ++i)
  {
    // Search our pattern against our position.
    for (int j = 0; j < strlen(pattern); ++j)
    {

That's bad, you can't use it recursively that way.
If you do this, any number of characters can appear between each character in the pattern.

Assuming the rest of your code is right (I didn't read it in detail), it would still allow the pattern "AB" to match "xxA__1234__Byy".
When the matching begins at position 3 in the input text, "A" from the pattern matches the first character in "A__1234__Byy". Then the pattern "B" is attempted matched against "__1234__Byy" which will also succeed because the same "match anywhere" algorithm is employed.

You need to have a partial_match function called by the pattern_match function, or if you don't want to have a helper function (by far the clearest) then keep a stack of your own inside the function.


Oh yeah, and don't ever use strlen() in a loop condition! Remember that strlen() is O(n) on the length of the string! The best way to loop over a string (in C) is the walking pointer method.

nielsm
Jun 1, 2009



Nalin posted:

No, the code works. Well, it works now.
Actually no it doesn't. I just tried building it and it has exactly the problem I described.

code:
> rgrep-nalin.exe "ii" < rgrep-test.txt
this file is fine.txt
the filename s.txt is too short
and reallylong.txt is too long
but super.txt is just right!
All of the lines in the file have at least two "i"s, but none of them have two "i"s in succession.

Nalin posted:

If anybody else wants to try to solve it a different way, it would be interesting to see how you do it.

I implemented my algorithm from above almost verbatim:
code:
int partial_match(char *pattern, char *str)
{
	char matchchar;
	int optional_match;
	int matches_here;
	
	matchchar = pattern[0];
	
	if (matchchar == '\0')
	{
		/* empty pattern matches anything */
		return 1;
	}
	
	if (matchchar == '\\')
	{
		pattern++;
		if (pattern[0] == '\0')
			/* pattern ends with an escape character, invalid syntax, match fails */
			return 0;
		matchchar = pattern[0];
	}
	else if (matchchar == '.')
	{
		/* an unescaped dot is a wildcard, distinguish it from an escaped dot
		   by making a nul char mean wildcard */
		matchchar = '\0';
	}
	
	pattern++;
	
	if (pattern[0] == '?')
	{
		optional_match = 1;
		pattern++;
	}
	else
	{
		optional_match = 0;
	}
	
	if (!optional_match && str[0] == '\0')
	{
		/* end of input text but not of pattern, fails.
		   this check is needed because matchchar=='\0' is used for wildcard */
		return 0;
	}
	
	matches_here = (str[0] == matchchar || matchchar == '\0');
	
	if (optional_match)
	{
		/* either the current character matches and the rest of the pattern matches
		   the rest of the string,
		   or the current character is skipped and the rest of the pattern matches
		   the entire input string. */
		return (matches_here && partial_match(pattern, str+1))
		    || partial_match(pattern, str);
	}
	else
	{
		/* the current character has to match and the rest of the pattern must match
		   the rest of the string */
		return matches_here && partial_match(pattern, str+1);
	}
}

int pattern_match(char *pattern, char *str)
{
	/* try matching at every position in the string */
	/* left as an exercise to the reader */
	return 0;
}
I blanked out a little part to make it not a complete solution to the homework :rolleyes:

nielsm
Jun 1, 2009



Nalin posted:

EDIT: My solution returns -1 on failure. Maybe that is the cause of the discrepancy?

I was simply inserting it into the skeleton program, assuming you were following the same API, so possibly yes.

nielsm
Jun 1, 2009



Bunch of options, maybe I'm missing something.

1. Let your header just define a pure abstract class (i.e. an interface), and implement the interface in your source files. Also have the header declare a factory function or class of a kind.

2. Forward-declare a class that will hold the implementation details, and let your public class hold a private pointer to that helper class.

3. Forward declare a class that will hold the implementation details, as just static methods. (A class used as a namespace.) Declare the actual class to have the implementation class as friend. I'm not sure if this is possible.

I think the first is the "purest" regarding OOP theory. The second is rather ugly.

nielsm
Jun 1, 2009



You may be able to set a breakpoint at the entry to the function and then set a data breakpoint on the return address on the stack.

nielsm
Jun 1, 2009



If you allocate memory dynamically (with the new operator, for example) and don't free it, and run for any amount of time, then yes it will stay allocated and eventually you will run out of address space, or memory in really bad situations.
If you use auto-allocated objects (i.e. things not allocated with operator new, or other dynamic allocation functions) then those are released when they go out of scope.

This function will leak memory:
code:
void foo ()
{
  std::vector<int> *v = new std::vector<int>(1000);
}
This function will not leak:
code:
void bar()
{
  std::vector<int> v(1000);
}
With proper usage of RAII, memory management won't be a major headache, however. (But it still requires care in design.)

nielsm
Jun 1, 2009



Yes std::string means referring to the name string in the std namespace and yes the std is redundant if you're using namespace std.
Thing is, it's often a bad idea to actually be using things, especially entire namespaces. What happens is that you import a large number of symbols (potentially) outside your control into the current namespace, so you get a greater risk of clashing names, and you risk making the code more confusing because it's less obvious where a certain name is defined.

I'd say it's fine to have using namespace std in small throw-away programs, since it'll probably save you some typing, but if you start writing real software you should try to avoid it.

nielsm
Jun 1, 2009



Mirconium posted:

I'm feeling retarded at the moment.

int length = 10;
int index = length;
index--;

Length is still 10, right?

And if so, why? Isn't index technically pointing at length?

If not, how do I go about copying integers? I know you use strdup for strings...

Anyway, yes. Sorry, brainfart moment, it's midnight, and I still have a ways to go on some code.

No, index is not of a pointer or reference type. You are making a copy of the value, or rather you assign the value of length to index.


This would make index reference length:
code:
int length = 10;
int &index = length;
index--;
// length has value 9 now, and you get that value too when you use index
This would make index a pointer to length:
code:
int length = 10;
int *index = &length;
(*index)--;
// length has value 9 now, and index still points to it
index--;
// length still has value 9, and index now points to undefined data
(*index)--;
// the stack is now corrupted

nielsm
Jun 1, 2009



Hmm this is more of a design philosophy thing, but I think your approach sounds bad in some way.

The way I view software, the user interface drives the program, so the user interface is always the "main" program. Examples: The user launches a GUI that creates some backend objects the GUI will then drive to let the user do work. The user enters a command on a commandline, the CLI frontend parses the commandline, creates the appropriate backend objects, and drives them to perform the work the user requested. A remote client makes a request to the server interface, which drives the backend to serve the request.

What I want to say is, IMO you should not have the backend drive the UI, but the UI drive the backend. The backend should then have a notification interface where the UI can register to get updates on the work being performed. The result will be that the UI is aware of the backend and calls that directly, while the backend is only aware that someone has registered for change notifications.
For those change notifications, boost::bind sounds like a good choice. (Remember to wrap some appropriate synchronisation mechanism around this.)


On a side note, remember that it isn't uncommon for GUI libraries to require that all GUI code takes place in the main thread, i.e. the initial thread your main() function runs on. You're probably better off having a "main" thread that does GUI, and a "work" thread that does work. Of course this depends entirely on your platform, but if you're multi-platform you really want to have the main thread be the GUI thread.

nielsm
Jun 1, 2009



brc64 posted:

I'm not asking for you to do my homework for me, but I could use a bit of help to come up with the right algorithm for this assignment. I feel like I'm close, but I must be missing something simple. The assignment is to take a line of input ending with a '.' and format it so it looks like a proper sentence. Capitalize the first letter, remove extra spaces between words, and make the other letters lowercase. I've got the case stuff down... that's easy, but I'm stuck on the space problem.

Are you required to modify the string in-place?
It might be easier to copy the source to a destination, one character at a time, and keep a bit of state. E.g. whether you are at the beginning of a sentence, whether the last copied character was a space. So sometimes you modify the character you copy, and sometimes you skip over a character without copying.

nielsm
Jun 1, 2009



Ghost Town Perv posted:

Say I have a class and two derived classes

Is it possible to create a single STL vector that holds objects of all three of those types?

You can't create a vector that contains objects of any of those three types, but you can create a vector that contains pointers to objects of any of those types.

code:
CBase o1;
CDerived o2;
CDerived o3;

std::vector<CBase> v1;
v1.push_back(o1); v1.push_back(o2); v1.push_back(o3);
// v1 now contains three CBase objects, the specifics of the derived classes
// were lost on insertion: The vector creates a copy using the CBase copy
// constructor.

std::vector<CBase *> v2;
v2.push_back(&o1); v2.push_back(&o2); v2.push_back(&o3);
// v2 now contains three CBase pointers, pointing respectively to one object
// of the CBase class, one of the CDerived class and one of the CDerived2
// class.
// Of course in this case, those objects are auto-allocated so when they go
// out of scope the pointers in the vector will no longer be valid.
When you pull the objects back out, you'll get CBase pointers and if you want to use them as a specific subclass you'll have to cast. If you want to be able to know what specific subclass an object is you must make sure that CBase has at least one virtual method (at least the destructor should be virtual) you can use dynamic_cast<>() to attempt casting the objects up to a more specific class, the dynamic_cast will return null if the attempted cast wasn't possible.

But you should not be attempting to cast up that way, in general. You should instead define an appropriate virtual method interface in CBase and implement it in the derived classes, to get the functionality you want through polymorphism.

When doing this, you'll need to be careful about memory management. You'll most often be allocating the objects on the heap (with operator new) so you need to remember to delete them again, which implies you need to figure out which part of your code should be responsible for deleting the objects. You can also look into using smart pointers instead.

nielsm
Jun 1, 2009



MutantBlue posted:

That #define tells the preprocessor to replace "length" with "16" everywhere it sees it. This makes the next line look like "void sort (int *array1, int 16)" and the "int 16" is where the error is.

Lesson to take: Always write macros with uppercase, like LENGTH. Or, since you're actually writing C++ (your file is named .cpp), make a proper constant:
code:
const int length = 16;

nielsm
Jun 1, 2009



MutantBlue posted:

If you're actually writing C++ use std::sort()

It looks like it might be some kind of homework or other. The C standard library also has a qsort() function.

nielsm
Jun 1, 2009



As far as I know, you simply need to have the functions forward-declared appropriately. Then, on your linking commandline, use the -L flag to add any additional library directories to the search path, and the -l flag (lowercase L) to specify the names of the libraries.

g++ -L/home/tastemyhouse/lib -lsfml foo.o bar.o -o baz

That should look for libsfml.so in /home/tastemyhouse/lib and use it for resolving symbols. Note that you don't specify the lib part nor the .so part of the library filename on the commandline.

nielsm
Jun 1, 2009



Screeb posted:

I'm having troubles with mixing SSE and thread-local storage (VS2008). I get an "access violation reading location 0x00000000" when trying to use _mm_store_pd (or other similar functions I imagine) on a TLS array.

This is only a guess, but perhaps the SSE-ness and array-ness don't play together with TLS, and you need to add some indirection: Make a TLS pointer to your array, or do that but wrapped in a class (for easier memory management).

nielsm
Jun 1, 2009



Either my_program needs to be in a directory on the path, or you need to include the directory name in the commandline.

If the program is in the current directory, and that isn't on the path, you'd do:
./my_program arg1 arg2 ...

The dot refers to the current directory, and is followed by a slash to refer to something inside it.


Edit: And if you're actually asking how to access the command line arguments, go look up what the argc and argv parameters to your main() function mean.

nielsm
Jun 1, 2009



You shouldn't be using strcmp(), it's for comparing strings (character arrays), not individual characters. If you want to compare two characters, just use the == operator, like if (s1[i]==s2[i]).

You say "it doesn't even run", but that's a really bad error description.
Do you mean that it doesn't compile? In that case, what error message does the compiler give you?
If it does compile, then what actually happens when you try to run it, does it crash, or hang, or does the OS give some loading error, or does it just seem to not do anything?

Your assignment says "write a new function", but you haven't done that. I understand that you are being asked to declare and implement a callable, reusable function to compare two strings. In fact, you're asked to write something similar to what the strcmp() standard library function does. (But not exactly the same thing.)

Lastly, some thing you shouldn't worry about right now (get the basics working first), but consider what happens if you enter more than 40 characters for either string, where do the excess characters go? (Hint: They are not just discarded. scanf() doesn't know how large your buffers are so it will happily overflow them.)

nielsm
Jun 1, 2009



Clobbersaurus posted:

I isolated the memory increase to the map insertion step, and it occurs to me that I don't really need a pair with a key and a value, I just need a map of keys (without values).

That's called a set, std::set.

nielsm
Jun 1, 2009



You could just as well use strdup() there, less code and less risk of fuckup.

nielsm
Jun 1, 2009



Seafea posted:

code:
while (fgets(acBuffer, 50, fp) != NULL) 
	{
		char *word = malloc(sizeof(char) * 20);
		strcpy(word, acBuffer);
		word[strlen(word) - 1] = '\0';
		dictionary[i] = word;
		i++;
	}

So what I would suggest instead:

code:
char acBuffer[50];
while (fgets(acBuffer, sizeof(acBuffer), fp)) {
    dictionary[i] = strdup(acBuffer);
    i++;
}
C++ (and I'm quite sure C as well) defines sizeof(char) as 1, and all sizes are measured in units of the char size.
I assume that fgets() writes at most the given number of bytes to the buffer, and it always terminates with a \0 character.
strdup() uses malloc for allocation, so memory allocated by it should be released with free().


Awesome Andrew:
Your program looks extremely convoluted and it seems you're repeating yourself in several places. I'm also not sure you're actually recursing as you're supposed to, as I read it you're just creating a single level of sub-processes.
Have you tried implementing the algorithm you want to use with a single process first, but still with recursion? (Presumably the idea is to use the sub-processes to run calculations in parallel.)
Also, your way of storing the matrices seems odd, why would you actually want to store the coordinates of each value, instead of letting the coordinates be implicit through the values' indices in the array?
I didn't read your code in detail, nor try it, so if any of what I wrote is wrong you should try to explain what you're doing (or trying to do) better :)

nielsm
Jun 1, 2009



I'd say initially use a map for counting:

std::map<package*,int> packagemap;
for each city { packagemap[city.package] += 1; }

Something like that, I'm honestly not sure if I've understood the problem completely. (Using the fact that the default construction of an int yields a zero.)

After counting everything, copy the contents of the map into a vector as pairs and sort the vector on the int in the pair. I think that should still keep you at O(n log n) complexity, although it does have a bunch of copying. Reserve space in the vector before copying to make it a little less bad.

nielsm
Jun 1, 2009



mobby_6kl posted:

2. Resetting the display resolution. I can set my display resolution to any supported combination smaller than my native resolution (1920x1080). If my current resolution is below that and I try to set it to 1920x1080, ChangeDisplaySettings returns DISP_CHANGE_BADMODE (display mode not supported). However, if the current resolution is already 1920x1080, it successfully changes it, pointlessly. Here's the relevant part of main():
code:
DEVMODE display_data;
display_data.dmSize = sizeof(DEVMODE);
display_data.dmDriverExtra = 0;

if (EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &display_data)) {
	display_data.dmPelsWidth = 1920;
	display_data.dmPelsHeight = 1080;
	display_data.dmDisplayFrequency = 60;

	switch (ChangeDisplaySettings(&display_data, 0)) {
		case DISP_CHANGE_BADMODE:
			printf("The graphics mode is not supported. Supported modes are:\n");
			enum_modes();
			break;
                [more cases here]
	}
}


enum_modes just lists the supported modes, where 1920x1080@60 is listed. Any ideas on what I'm doing wrong here?

You should probably make sure you zero out the entire DEVMODE structure. The easy way:
code:
DEVMODE display_data = {0};
Give an incomplete initialiser list. I customarily provide the first element as zero, but if the first element is a struct size field you could also provide the size there directly. When you provide an incomplete initialiser list, the remaining part not specified will be filled with zero bytes. Effectively, you just zeroed the entire structure. If you don't provide the initialiser, the structure may be filled with junk data.

Edit: Another thing you're missing:

"DEVMODE posted:

dmFields
Specifies whether certain members of the DEVMODE structure have been initialized. If a member is initialized, its corresponding bit is set, otherwise the bit is clear. A driver supports only those DEVMODE members that are appropriate for the printer or display technology.
You need to fill that.

nielsm fucked around with this message at 13:43 on Apr 2, 2011

nielsm
Jun 1, 2009



It doesn't sound like there is anything meaningful you could return, apart from possibly a success/failure code. (E.g. you might discover that those two persons actually exist in two separate trees, and that might be an error condition.)

I don't know exactly what your function is doing, but I'll assume that it adds the ID of the other person to each of the passed person objects, allocating a new buddyList struct for each, adding it somewhere in the buddy list of each tree node.

So what could you return?
- A pointer to a buddyList struct? Which one, you allocated two of them.
- A pointer to a tree_node struct? But those were passed in as parameters already, so that isn't much use either. Also, again which of the two would you return?
- A new count of buddies? For which of the persons? You could just as well read it out of the tree_node struct you already hold a pointer to.
- An error code? If the operation can fail in any way, this may be a good choice.
- Nothing, i.e. void? Why not, if you can't fail, just perform the operation. Anything the caller wants to know, they can extract from the pointers they already held before calling your function.

Edit: If your function only creates a one-way relationship (i.e. makes person A a buddy of person B, but not person B a buddy of person A) then the first three points in my list above could make sense. But even here, the caller could just extract the same information from the tree_node struct after performing the call.

nielsm fucked around with this message at 06:38 on Apr 6, 2011

Adbot
ADBOT LOVES YOU

nielsm
Jun 1, 2009



Johnson posted:

Noob question here:
I'm trying to learn C++. I downloaded Dev-C++ and wrote the "hello world" program, but when I run it, the command promp opens and closes immediately.
I googled about this, and people mentioned writing "cin.gate()" at the end, but that hasn't helped me at all.
How do I stop it from closing my files when I run them?

You're creating a console mode application, so Windows creates a console window your program's output is displayed in, but that window closes as soon as your program ends.

A bunch of things you can do if you want the window to stay up:
- Make the program wait, either just for a period of time, or until you do something like press a key.
- Run the program from an already existing console window, i.e. start cmd and run your compiled program from there.
- A kind of combination of the two, write a batch file that runs your program and then waits afterwards.

I'd strongly recommend one of the two latter, although the first also has its uses.
Mainly, if you aren't comfortable with using a command line, it's a good idea to become so. This looks like a decent guide. (Also it's worth noting that Windows' command line is not DOS. DOS is a 16 bit operating system and last time you ran DOS was with Windows 98.)
When you have a working understanding of the command line, you can also write simple batch files, just files with extension .cmd or .bat that contain a list of commands. That could be e.g. be the name of your compiled program, followed by the pause command on the next line.

If you want to make your program itself wait instead, read on.
First, why it's a bad idea: If you're writing a non-interactive program, i.e. one that just does a prescribed job without taking user input, it's silly to add a delay: You're just making the program take longer to complete without any gain. If you wanted to time to read its output you could be calling it from a batch file and pause after its execution, or you could redirect the output to a file, or several other things.
Now, what you'd do to make the program wait: The simplest is to just read something, anything, from standard input, i.e. std::cin when using C++'s iostreams. You could do that like this:
char dummy; std::cin >> dummy;
In the context of iostreams, the >> operator is used as "take from", the same way as << is used as "put to". (The general meaning of those operators is something entirely different, they're the bit-shifting operators in C. Important to remember!)
What this will do is read a single character from standard input, but you'll notice it only actually continues after you press Enter to finish a line, that's because of line buffering: The input system by default tries to read an entire line before passing anything to the program. There's also ways to do unbuffered input, but I can't remember them right now and can't bother looking it up.

Lastly, you could of course begin writing GUI programs ;)

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