Dogtree 23 Posting Whiz in Training

Think recursively. Operands return the value, binary operators perform themselves on the left and right value:

if (is_operand())
  return value;

T a = recurse(left);
T b = recurse(right);

switch (operator()) {
case '+': return a + b;
case '-': return a - b;
case '*': return a * b;
case '/': return a / b;
}

It's also easy to turn the four function calculator into something more powerful. You can easily modify the algorithm to handle unary operators and add error checking to verify that the syntax of the expression is correct.

Dogtree 23 Posting Whiz in Training

Another option if MSDN scares you is to download the Boost::filesystem library. If you can figure out how to build it and link with it then writing your program would be a breeze. :) But I still recommend using the Win32 API, and my link is a great start.

Dogtree 23 Posting Whiz in Training

C++ only natively supports file access through iostreams. You create an object of the *fstream family of classes and open them using a file name and orientation. To open a file for reading you would probably do this:

#include <iostream>
#include <fstream>
#include <string>

int main()
{
  std::ifstream file("file");

  if (file.is_open()) {
    std::string s;

    while (getline(file, s))
      std::cout << s << '\n';
  }
}

To write to a file, you use ofstream instead of ifstream, and the corresponding operators:

#include <iostream>
#include <fstream>
#include <string>

int main()
{
  std::ifstream file("file");
  std::ofstream log("log");

  if (file.is_open()) {
    std::string s;

    while (getline(file, s)) {
      std::cout << s << '\n';
      log << s << '\n';
    }
  }
}

Along with unidirectional streams, you can also have a bidirectional stream that allows input and output with intervening flushes or seeks:

#include <iostream>
#include <fstream>
#include <string>

int main()
{
  std::fstream file("file", std::ios::in | std::ios::out);

  if (file.is_open()) {
    file << "First line\nSecond line" << '\n';
    file << "Third line" << '\n';

    file.seekg(0, std::ios::beg);

    std::string s;

    while (getline(file, s))
      std::cout << s << '\n';
  }
}

Once opened, file streams are used just like cin and cout unless they're bidirectional. In that case you also have to consider the flush or seek when you change direction so that the stream buffer is synchronized. Otherwise, even the bidirectional file streams are used just like cin and cout.

Timers are tricky. If you need good precision, ie. REALLY every N seconds rather than just an …

Dogtree 23 Posting Whiz in Training

Uh, that's not C++, it's Java.

Dogtree 23 Posting Whiz in Training
int NoLinesIgnored, NoCharsIgnored, NoCharsWanted;
std::string s;

// ...

while (--NoLinesIgnored >= 0) {
  // Read and discard a line
  file.ignore(std::numeric_limits<streamsize>::max(), '\n');
}

// Read and discard N characters
file.ignore(NoCharsIgnored);

// Read and save N characters
file >> std::setw(NoCharsWanted) >> s;

How you do this will vary depending on your whitespace needs, but the above should suffice. Concerning integers, can you be more specific about what you want to do? What does the file look like, how do you want to process it, and what should the output be?

Dogtree 23 Posting Whiz in Training

Wow, leave it to Slashdot to use the most biased description possible. ;)

Dogtree 23 Posting Whiz in Training

How does that function not work? There are a few iffy parts, like not checking fopen for success and not considering that fread can return a non-zero failure code, but there are no obvious errors that I can see this early in the morning. ;)

Dogtree 23 Posting Whiz in Training

Your biggest problem is trying to use stream.read() and stream.write() with a non-POD type. Because the string class is not a trivial class, and your PersonInfo struct has at least one of them, read and write are only guaranteed to cause undefined behavior. You would be better off defining a function that extracts and inserts fields from/to the database manually. Using unformatted binary I/O is tricky to get right and has a lot of restrictions in C++.

Dogtree 23 Posting Whiz in Training

You have to do everything that MFC does for you manually. That's a pretty broad topic because "dialog-based application" covers a LOT of stuff. You should consider picking up Charles Petzold's Programming Windows.

Dogtree 23 Posting Whiz in Training

No offense, but if you're so pressed for time on something this simple, you probably deserve a failing grade. That said, enumerations are easy to define:

enum Suit { Hearts, Diamonds, Clubs, Spades };

And an integral face value is as simple as declaring an int:

int value;
Dogtree 23 Posting Whiz in Training

It depends on the implementation; it could go either way. If no formatting information is included then there'll probably be a method to print the number and add formatting. If that's the case then the only purpose of a null character is to act as a sentinel. But if the size is always 7, there's no reason to use a sentinel such as with the name where it could be any amount up to 40 characters. As for area code, yea, I'd probably include space for that or have a separate member[*], but cspikes made it clear that the phone number was 7 characters.


[*] Actually, I'd be a lot more lenient in how phone numbers are set up for internationalization purposes. Most likely I'd write a facet to handle phone numbers and set up the data accordingly. But that's way beyond the scope of this thread, so I didn't mention it. ;)

Dogtree 23 Posting Whiz in Training

You're sorting by name, and name only. Just because a name goes in one spot doesn't mean the corresponding data goes in the same spot if you sort it too. This is basically what you're doing:

#include <algorithm>
#include <iostream>
#include <iterator>

template <typename T>
void bubble(T list[], int sz)
{
  for (int i = 0; i < sz; i++) {
    for (int j = i; j < sz; j++) {
      if (list[j] < list[i])
        std::swap(list[i], list[j]);
    }
  }
}

int main()
{
  int a[] = {9,8,7,6,5,4,3,2,1,0};
  int b[] = {6,7,5,8,9,0,4,3,2,1};

  copy(a, a + 10, std::ostream_iterator<int>(std::cout, " "));
  std::cout << '\n';
  copy(b, b + 10, std::ostream_iterator<int>(std::cout, " "));
  std::cout << '\n';

  bubble(a, 10);

  copy(a, a + 10, std::ostream_iterator<int>(std::cout, " "));
  std::cout << '\n';
  copy(b, b + 10, std::ostream_iterator<int>(std::cout, " "));
  std::cout << '\n';
}

To get it to work, you need to pass the other arrays and swap them too, but only use name in the test:

#include <algorithm>
#include <iostream>
#include <iterator>

template <typename T>
void bubble(T list1[], T list2[], int sz)
{
  for (int i = 0; i < sz; i++) {
    for (int j = i; j < sz; j++) {
      if (list1[j] < list1[i]) {
        std::swap(list1[i], list1[j]);
        std::swap(list2[i], list2[j]);
      }
    }
  }
}

int main()
{
  int a[] = {9,8,7,6,5,4,3,2,1,0};
  int b[] = {6,7,5,8,9,0,4,3,2,1};

  copy(a, a + 10, std::ostream_iterator<int>(std::cout, " "));
  std::cout << '\n';
  copy(b, b + 10, std::ostream_iterator<int>(std::cout, " "));
  std::cout << '\n';

  bubble(a, b, 10);

  copy(a, a + 10, std::ostream_iterator<int>(std::cout, " ")); …
Dogtree 23 Posting Whiz in Training

Koenig Lookup

There are three ways to use a name nested in a namespace. Making the namespace open to the current scope with a using directive:

using namespace std;

cout << "Hello world!" << endl;

Making only select names open to the current scope with a using declaration:

// Make cout and endl available, but nothing else
using std::cout;
using std::endl;

cout << "Hello world!" << endl;

And explicit qualification of every name for every use:

std::cout << "Hello world!" << std::endl;

It's best to never use the using directive unless you know for a fact that you won't have name clashes. That's usually not easily possible, and most people will suggest that you use explicit qualification all the time. The problem with that is explicit qualification is so verbose! Koenig lookup is a trick to shorten some of those names.

Here's a common example:

vector<int> c;

// ...

std::copy(c.begin(), c.end(), std::ostream_iterator<int>(std::cout, "\n"));

Koenig lookup says that if a function in a namespace takes an argument from the same namespace, the function need not be qualified because the compiler will look in that namespace for matching functions. So the following is legal C++:

copy(c.begin(), c.end(), std::ostream_iterator<int>(std::cout, "\n"));

copy takes an ostream_iterator object as an argument. Because both ostream_iterator and copy are members of namespace std, Koenig lookup finds copy via ostream_iterator. A third of the namespace qualification has been removed from this line, and that is a big timesaver when it all adds …

JoBe commented: Very friendly, Ace in C++ in my eyes, doesn't have a problem in explaining something what you didn't understand the first time! +1
Dogtree 23 Posting Whiz in Training

Fill in the blanks:

class Entry {
  char _name[41];  // +1 for '\0'
  char _number[7]; // Not including format characters
public:
  Entry(const char *name, const char *number);

  void reset(const char *name, const char *number);

  const char *name() const { /* ... */ }
  const char *number() const { /* ... */ }
};

Entry::Entry(const char *name, const char *number)
{
  // ...
}

void Entry::reset(const char *name, const char *number)
{
  // ...
}
Dogtree 23 Posting Whiz in Training

Accelerated C++ by Andrew Koenig and Barbara Moo. The Design and Evolution of C++ and The C++ Programming Language by Bjarne Stroustrup are also books you'll want to have on your shelf if you plan to really learn C++ and not just get through a few classes. :) Note that these are just starters. There are other books a serious C++ite will want to have and study regularly such as The C++ Standard Library by Nicolai Josuttis, C++ Templates by Nicolai Josuttis and David Vandevoorde, Generic Programming and the STL by Matthew Austern, Effective C++, More Effective C++, and Effective STL by Scott Meyers, anything by Herb Sutter, C++ IOstreams and Locales by Anjelika Langer and Klaus Kreft, the C++ standard itself, and about a dozen other texts that are interesting, but not must-have's.

Dogtree 23 Posting Whiz in Training

As much as I want to help you, it looks like you want someone else to do your work for you. The code you've provided doesn't even come close to an attempt to solve the problem. It's asking you to write a Dice class that supports rolling the dice and giving the result. If you're having trouble with C++ at the fundamental level as your code suggests, you really need personal, face to face help instead of the clipped "this is your problem, here's how to fix it" help that you'd get here.

And no, nobody is going to write this for you.

Dogtree 23 Posting Whiz in Training

What have you tried so far, and why is everyone posting C++ questions in the Community Introductions forum? There's a separate C++ forum for such problems.

Dogtree 23 Posting Whiz in Training

When you don't understand an algorithm, the best way to figure it out is to run it through a debugger step by step, or write down the execution on paper. Of course, if the algorithm is wrong, or the right way to call the function is misunderstood, naturally it will be confusing. :) How is this Merge supposed to be called? Because if left is the first element in the array and right is the last, the algorithm is wrong because it accesses both temp and array out of bounds.

Dogtree 23 Posting Whiz in Training

In that case the Win32 API would probably be your easiest solution. You can start browsing from here.

Dogtree 23 Posting Whiz in Training

It sounds like the stream isn't getting flushed. That's not correct behavior because calling exit() will flush all output streams with unwritten data. Just for grins, try changing cout to cerr and see what happens. cerr has the unitbuf flag set by default, so it should flush the stream after every operation. If that works then the compiler isn't predictable enough to be useful and you should get a newer version. Visual C++ 2005 Express Beta 2 is free for download, and conforms to the C++ standard very well. Dev-C++ is also a good conforming compiler, but the IDE is lacking in my opinion.

Dogtree 23 Posting Whiz in Training

A good starter distro is Knoppix on Live CD or Mandrake Move. If you want to actually install Linux on your system then Mandrake is probably the easiest to do. Concerning development tools, that's not really an issue. Just look for a distro that makes it easy to add new software and you can have tools coming out your ears by downloading them from GNU or other open source repositories. But most distros let you choose from a wide range of development tools during installation.

Dogtree 23 Posting Whiz in Training

pid_t is integral, so you need to actually convert it to a string. Type casting doesn't cut it, but sprintf is a good easy fix:

sprintf(msg1.message, "%lu", (unsigned long)pid);

This is assuming that message is an array or pointer with memory allocated to it and sized enough to hold the value. If it's just a pointer, you need to allocate some memory:

msg1.message = malloc(ENOUGH_FOR_AN_INT + 1);

if (msg1.message == NULL)
  error("malloc failure");

sprintf(msg1.message, "%lu", (unsigned long)pid);

The same goes with your alternate solution:

sprintf(msgbuf, "systemcall%lu", (unsigned long)pid);
/* strcat(msgbuf, (char*)pid); */
Dogtree 23 Posting Whiz in Training

Can you get a string from one file? If so then can you get a string from more than one file in the same directory? Do you have to search for the files according to some pattern, or do you have a list of filenames? I see this question a lot, and nobody gives enough detail. I need to know what you already know how to do. If you don't know how to open and read a file then my answering the question assuming your problem is with reading from multiple directories wouldn't help much. If you don't know how to open and read from different directories then I need to know what operating system and compiler you use because there's no portable solution for that problem.

Dogtree 23 Posting Whiz in Training

Your comments are pretty useless for understanding the algorithm. Sure, you may understand the mechanics of each line taken out of context, but do you understand the purpose of each line when taken as a whole for the algorithm? Comments are better for documenting the reasons for doing something, not for repeating the code in english.

void QuickSort( long array[], long left, long right)
{
  if( right <= left ) return; // Return if there's nothing to partition

  long i = Partition( array, left, right );

  QuickSort( array, left, i - 1);  // Sort the left subarray [left, pivot)
  QuickSort( array, i + 1, right ); // Sort the right subarray [pivot+1, right)
}
long Partition( long array[], long left, long right )
{
  long i = left - 1, r = right;
  long y = array[right]; // Pivot value, (poor choice)

  while( 1 )
  {
    while( array[++i] < y ); // Locate the pivot value index with i
    while( y < array[--r] ) // Locate the pivot value index with r
      if( r == 1 ) break;

    if( i >= r ) break; // Finished if the indexes cross

    Swap( array[i], array[r] ); // Place values less than the pivot at lower
                      // indices and values greater or equal at higher indices
  }

  Swap( array[i], array[right] ); // Place the pivot in its final location

  return i; // Return the pivot index
}
Dogtree 23 Posting Whiz in Training

>>strcat(msgbuf, (char*)pid);
If you have to cast to char * then chances are good you're doing something wrong. ;) What type is pid? I'm guessing it's an int, and that would be a problem because typecasting doesn't make an integer into a string.

Dogtree 23 Posting Whiz in Training

Here's a trick for fixing problems like this one. Cut out all of the fluff from your program so that it's absolute bare-bones, but still has the problem. Errors are easier to see when you don't have a lot of code all around them diverting your attention. There are three rules to follow:

1) Use a single source file. No headers except the required standard ones.
2) Output is irrelevant unless the problem is with formatting. Remove all pretty-print functionality.
3) Hardcode everything. User input is nice, but it bulks up a program.

Dogtree 23 Posting Whiz in Training

1) Yep, the default access for a class is private, so unless you specify otherwise, it's private. It's the opposite for a struct though, where the default is public.

2) I use it to differentiate between data members and parameters or local variables.

3) Yes, but it's good practice to initialize objects when you create them. Otherwise you would create an empty iterator, then assign it a value as opposed to simply creating an initialized iterator, which can be more efficient.

4) That sounds like an autocomplete feature for your environment. How it works depends on which environment you use, and what version of the environment you're at.

4a) That's a list of the names in the std namespace. Basically every available name in the namespace should be included if the list is complete.

4b) That's up to your implementation. For example, while your autocomplete doesn't show cout, mine does.

Dogtree 23 Posting Whiz in Training

Dude, you're gonna have to give us something complete. A full program that doesn't work, and a chunk of the file that you're using so that we can actually test this and answer your question completely without all the back and forth.

Dogtree 23 Posting Whiz in Training

I haven't actually written code for fingerprint matching, but I've studied the methods and algorithms and it's pretty complicated. There are a bunch of ways to do it, and I doubt that even if anyone has code not under a non-disclosure agreement, they won't just give it to you. If you search google for "fingerprint algorithms" then you'll get a few good hits.

Dogtree 23 Posting Whiz in Training

Viva la std::string!

Dogtree 23 Posting Whiz in Training

It's just that easy. Of course, if you want to get some really cool features going, it takes more work. But for the most part the simple stuff is enough.

Dogtree 23 Posting Whiz in Training

Here's the mathematical way to do it. But if this is homework, your teacher is probably looking for the brute force way of doing it. I won't show you that one because half the fun is figuring things out for yourself. The other half is writing the code to do it. :)

#include <iostream>

double factorial(double n)
{
  return (n > 1) ? n * factorial(n - 1) : 1;
}

double ncr(int n, int r)
{
  return factorial(n) / (factorial(r) * factorial(n - r));
}

int main()
{
  std::cout.setf(std::ios::fixed, std::ios::floatfield);
  std::cout.precision(0);

  for (int i = 0; i < 15; i++) {
    for (int j = 0; j <= i; j++)
      std::cout << std::right << ncr(i, j) << ' ';
    std::cout << std::endl;
  }
}
Dogtree 23 Posting Whiz in Training

You've pretty much checked off everything on the "don't do" list of basic C. Maybe you should start using the standard C++ classes instead of fumbling around with the low level arrays and pointers of the C subset of C++. It's easier to get right if you don't have years of experience with the low level stuff:

#include <algorithm>
#include <iostream>
#include <string>

bool is_vowel(std::string::size_type c)
{
	std::string vocales("aeiou");
	return vocales.find(c) != std::string::npos;
}

void cuenta_vocales(std::string palabra)
{
	int count = count_if(palabra.begin(), palabra.end(), is_vowel);
	std::cout<<"Cantidad de vocales en "<<palabra<<": "<<count<<std::endl;
}

int main()
{
	std::string palabra;
	std::cout<<"Entre la palabra que desea evaluar: ";
	std::cin>>palabra;
	cuenta_vocales(palabra);
}
Dogtree 23 Posting Whiz in Training

If you defined your operator<< correctly, which seems to be the case, then you don't need to do anything special. That's the nice thing about extending iostreams, you can use them just like you would the standard library stuff:

cout << xVal << ' ' << yVal << '\n';
Dogtree 23 Posting Whiz in Training

It depends on the compiler. Generally the files will be compiled in the order that they're listed when the compiler is run.

>>And what's the one declaration rule?
One "definition" rule. It means that you can declare an object as much as you want because a declaration only says "Hey, I exist", but you can only define it once because a definition actually makes the object exist by allocating memory and calling constructors. If there are multiple definitions then you'll get an error.

Dogtree 23 Posting Whiz in Training

When you swap the name array, you'll have to swap all of the other arrays along with it, since each array is a unique object. A good alternative is to stuff everything in an structure and then sort an array of structs:

struct record {
  string name;
  // ...
} rec[N];

That would save you a lot of work because you can treat a record as a single unit rather than an index in a bunch of arrays.

Dogtree 23 Posting Whiz in Training

One good reason would be to hide the implementation. If any changes need to be made to the implementation then it makes sense to separate it into a single file so that any code that uses the header doesn't need to be recompiled. If you place declarations in a header file you can more easily break the one definition rule, so separating declarations and definitions will make writing correct code easier. If you place the entire class in your headers then compilation can also take longer.

Dogtree 23 Posting Whiz in Training

You have the same problem with testScore. You define it, don't initialize it, but still use it in your tests. Technically, the program is allowed to crash noisily because you're accessing uninitialized memory, but undefined behavior in your case is getting to the else clause and setting grade to 'F' in every case.

Finding the highest score is a cakewalk if you use the standard library:

bool gradeLess(const studentType& a, const studentType& b)
{
  return a.grade < b.grade;
}

int highestScore (const studentType sList[], int listSize)
{
  return max_element(sList, sList + listSize, gradeLess)->grade;
}

Otherwise you'll be stuck doing it manually:

int highestScore (const studentType sList[], int listSize)
{
  int max = sList[0].grade;

  for (int i = 0; i < listSize; i++) {
    if (sList[i].grade > max)
      max = sList[i].grade;
  }

  return max;
}
Dogtree 23 Posting Whiz in Training

This might give you a start for how to define them:

#include <iostream>
#include <utility>

class Integer {
  int _val;
public:
  Integer(): _val(0) {}
  Integer(int val): _val(val) {}
  int get() const { return _val; }

  Integer operator+=(const Integer& rhs) { return _val += rhs._val; }
  Integer operator-=(const Integer& rhs) { return _val -= rhs._val; }
  Integer operator*=(const Integer& rhs) { return _val *= rhs._val; }
  Integer operator/=(const Integer& rhs) { return _val /= rhs._val; }
  Integer operator%=(const Integer& rhs) { return _val %= rhs._val; }

  Integer operator+(const Integer& rhs) { return _val + rhs._val; }
  Integer operator-(const Integer& rhs) { return _val - rhs._val; }
  Integer operator*(const Integer& rhs) { return _val * rhs._val; }
  Integer operator/(const Integer& rhs) { return _val / rhs._val; }
  Integer operator%(const Integer& rhs) { return _val % rhs._val; }

  Integer operator++() { return *this += 1; }
  Integer operator++(int) { Integer temp(*this); ++*this; return temp; }
  Integer operator--() { return *this -= 1; }
  Integer operator--(int) { Integer temp(*this); --*this; return temp; }

  friend bool operator==(const Integer& lhs, const Integer& rhs)
  { return lhs._val == rhs._val; }
  friend bool operator<(const Integer& lhs, const Integer& rhs)
  { return lhs._val < rhs._val; }
};

int main()
{
  using namespace std::rel_ops; // Sneaky sneaky ;-)

  Integer a(20);

  // Op-assign operators
  std::cout << a.get() <<'\n';
  a += 2;
  std::cout << a.get() <<'\n';
  a -= 2;
  std::cout << a.get() <<'\n';
  a *= 2;
  std::cout << a.get() <<'\n';
  a /= 2;
  std::cout << a.get() <<'\n';
  a %= 2;
  std::cout …
Dogtree 23 Posting Whiz in Training

Either n is bigger than 50, which is the last accessible index in your array, or you aren't allocating memory to each Activity pointer in the array. You probably want to allocate the initial memory like this:

Activity **p = new Activity*[51];

for (int i = 0; i < 51; i++)
  p[i] = new Activity;

Then you release the memory like this:

for (int i = 0; i < 51; i++)
  delete [] p[i];
delete p;

Unless you do this, you'll have to initialize each pointer to an existing object before you try to dereference it.

Dogtree 23 Posting Whiz in Training

Yes, it would help. Quite a bit. :)

Dogtree 23 Posting Whiz in Training

You never initialize grade to anything. In calculateGrade you assign to grade, but don't do anything else with it, so when the function terminates, all of the work is lost. Then in printResult, you redefine grade, but don't give it a value, so you'll get garbage.

Dogtree 23 Posting Whiz in Training

It's not about bells and whistles. If you want that stuff, take a look at the std::string class. Narue's list is actually very sparse, it just seems complicated because of the nested Node and Iterator helper classes. The only operations that the list class itself supports are:

  • Create an empty list
  • Create a list from a range
  • Add a value to the front of the list
  • Add a value to the end of the list
  • Get the size of the list
  • Define a [first, last) range

It doesn't handle insertion anywhere except the front and back, it doesn't handle deletion of any values, it lacks a copy constructor, assignment operator, destructor, and a good number of fundamental operations for a linked list. The standard std::list class is pretty generic, and it sports 12 types, four constructors, a destructor, 43 member functions, and 7 non-member functions. That isn't including the functionality required of the bidirectional iterators that the std::list class requires. With that in mind, especially after seeing and/or writing the standard std::list, Narue's class is practically trivial. ;)

I don't see how vector would be a part of the exercise. It isn't, and can't be, implemented as a linked list, so unless you want to use a vector for something other than the implementation of your linked list class, it wouldn't fit in the exercise.

Dogtree 23 Posting Whiz in Training

If you want to make the class look something like a standard C++ container then Narue's code is about as simple as it gets. You define a data structure that holds items and then define an iterator that controls safe traversal of those items. A simpler, but less safe, linked list class would just dole out node pointers as iterators:

#include <iostream>

template <typename T>
struct Node {
  T _item;
  Node *_next;

  Node(const T& item, Node *next)
    : _item(item), _next(next)
  {}
};

template <typename T>
class LinkedList {
  Node<T> *_head;
public:
  typedef Node<T> *iterator;

  LinkedList(): _head(0) {}

  void add(const T& val)
  {
    _head = new Node<T>(val, _head);
  }

  iterator begin() { return _head; }
  iterator end() { return 0; }
};

int main()
{
  LinkedList<int> list;

  list.add(1);
  list.add(2);
  list.add(3);
  list.add(4);

  LinkedList<int>::iterator it = list.begin();

  while (it != list.end()) {
    std::cout << it->_item << '\n';
    it = it->_next;
  }
}

That's not as useful because it involves knowing about the Node class. A good linked list class should hide all of that away so that users only know, or care, about values and iterators.

Dogtree 23 Posting Whiz in Training

If you want to have multiple "worlds" then yea, that's probably the best way to go about it.

>>LOCATION *grid[MAX_GRID_X - 1][MAX_GRID_Y - 1];
Why are you taking 1 away from each of the sizes? It would be safer in the long run to just change MAX_GRID_X and MAX_GRID_Y to 99 rather than figure out what kind of integer arithmetic to do to avoid out of bounds accesses.

Dogtree 23 Posting Whiz in Training

Can you shrink down your code to something small enough to post? I don't think anyone wants to download your attachment, unzip it, create a collection of source files to match their environment's needs, compile and run your program, then debug it to find the problem. If your program is large, that makes it even harder and most people, like me, don't have the time to go through all that mess.

Dogtree 23 Posting Whiz in Training

>>if ( !isdigit( a ) || !isdigit( b ) )
isdigit takes a single int as its argument, and the int must be in the range of an unsigned char. Both a and b are being passed as pointers to char. Now, since the is* functions from ctype.h are typically implemented as a jump table without any bounds checking, passing a memory address would very likely cause an out of bounds access and result in an access violation crashing your program. If you're lucky of course, undefined behavior can do anything.

atoi is troublesome when it comes to error handling anyway, so you would be better off using strtol:

int safe_atoi(const char *s, int *result)
{
  char *end;

  *result = (int)strtol(s, &end, 0);

  if ((*result == 0 && end == s) || *end != '\0')
    return 0;

  return 1;
}
if (!safe_atoi(a, vA) || !safe_atoi(b, vB))
  return EXIT_FAILURE;

But that's really a lot more work than strcmp.

Dogtree 23 Posting Whiz in Training

You're basically just describing the "area of rooms" concept with different terminology. Both can be easily written using multidimensional arrays, or sparse matrices. In the file you could have the x/y/x coordinates that relate to the array indexes followed by location information:

0 0 0 Information about the location
0 0 1 Information about the location
0 0 2 Information about the location
0 0 3 Nothing there

Then in your program you can have an array of structures that represent location information:

struct Location {
  /* Location information */
} loc[Z][X][Y];

And in your program, you can load the file into the array easily assuming you have a way to parse the location information into a Location object:

int inrange(int x, int low, int high)
{
  return x >= low && x < high;
}

void LoadFile(struct Location loc[Z][X][Y], FILE *fp)
{
  int x, y, z;

  while (fscanf("%d%d%d", &z, &x, &y) == 3) {
    assert(inrange(z, 0, Z) && inrange(x, 0, X) && inrange(y, 0, Y));
    LoadLocation(loc[z][x][y], fp);
  }

  if (!feof(fp)) {
    fprintf(stderr, "An error occurred while reading the file\n");
    cleanup(); /* Do any application-specific cleanup */
    exit(EXIT_FAILURE);
  }
}
Dogtree 23 Posting Whiz in Training

I wasn't trying to solve your problem for you, sorry if I gave you that impression. I'm glad you figured it out without my help anyway.

Dogtree 23 Posting Whiz in Training

Was this what you were trying to do?

Activity **p = new Activity*[51];

for ( int i = 1; i <= n; ++i ) {
  // Read the activity records.
  pert >> (*(p+i))->i >> (*(p+i))->j >> (*(p+i))->pt 
    >> (*(p+i))->prt >> (*(p+i))->ot;
  pert.getline((*(p+i))->desc,21);
}