943,892 Members | Top Members by Rank

Ad:
  • C++ Discussion Thread
  • Unsolved
  • Views: 89439
  • C++ RSS
You are currently viewing page 2 of this multi-page discussion thread; Jump to the first page
Mar 22nd, 2005
0

Re: C and C++ Timesaving Tips

Finding Array Size

Starting Out
When first starting out, we might write some code that initializes an array, perhaps does some manipulation, and then displays the results. It might look something like this (contrived example):
void foo(void)
{
   int array[10];
   int i;
   /* Initialize array. */
   for ( i = 0; i < 10; ++i )
   {
      array[i] = i;
   }
   /* Perform calculations. */
   for ( i = 0; i < 10; ++i )
   {
      array[i] *= 2;
   }
   /* Print array. */
   for ( i = 0; i < 10; ++i )
   {
      printf("%d,", array[i]);
   }
   putchar('\n');
}
We notice that if we want to change the array dimension, there are several lines of code to edit to make the change. Maintaining code like this is more difficult because in larger sets of code, finding all of the places that need to be changed becomes less trivial.

Using a Symbolic Constant
To avoid this, it is often recommended to use a symbolic constant instead.
#define SIZE 10

void bar(void)
{
   int array[SIZE];
   int i;
   /* Initialize array. */
   for ( i = 0; i < SIZE; ++i )
   {
      array[i] = i;
   }
   /* Perform calculations. */
   for ( i = 0; i < SIZE; ++i )
   {
      array[i] *= 2;
   }
   /* Print array. */
   for ( i = 0; i < SIZE; ++i )
   {
      printf("%d,", array[i]);
   }
   putchar('\n');
}
Now we can see we only need to change the #define to make a change to the array size. Unfortunately, purveyors of this wisdom often stop there.

The debugging hazard that this leads to often materializes itself in some header that is used to declare dozens of such constants. Some may like this, but I've found this to be a maintenance headache as well. For example, let's take a look at this code fragment.
C++ Syntax (Toggle Plain Text)
  1. for ( i = 0; i < ASIZE; ++i )
  2. {
  3. printf("%d,", array[i]);
  4. }
Is it correct? You can't tell from this alone. You have to find the declaration of the array and double check. That alone is probably not that big of a deal, except when you have data that may be declared far away from this section of code.

Another Way
A cure is such an old piece of code, it's hard to imagine more people aren't aware of it long before they've learned a struct. It works by dividing the total size of the array (in bytes) by the size of the first element of the array (in bytes); this gives the number of elements. This is calculated at compile time.
void baz(void)
{
   int array[10];
   size_t i;
   /* Initialize array. */
   for ( i = 0; i < sizeof array / sizeof *array; ++i )
   {
      array[i] = i;
   }
   /* Perform calculations. */
   for ( i = 0; i < sizeof array / sizeof *array; ++i )
   {
      array[i] *= 2;
   }
   /* Print array. */
   for ( i = 0; i < sizeof array / sizeof *array; ++i )
   {
      printf("%d,", array[i]);
   }
   putchar('\n');
}
Now if you want to change the size of the array, you do it in only one place, and that place happens to be right where you define the array. If we saw the following fragment, is it correct?
C++ Syntax (Toggle Plain Text)
  1. for ( i = 0; i < sizeof array / sizeof *array; ++i )
  2. {
  3. printf("%d,", array[i]);
  4. }
If array is an array in scope, yes.

Further Considerations
Some programmers may prefer to use a macro to make it easier to read; either of these are examples.
C++ Syntax (Toggle Plain Text)
  1. #define ARRAYSIZE(x) (sizeof(x)/sizeof(*(x)))
  2. #define NELEM(x) (sizeof(x)/sizeof(x[0]))
So another way to write this is as follows.
void qux(void)
{
   int array[10];
   size_t i;
   /* Initialize array. */
   for ( i = 0; i < ARRAYSIZE(array); ++i )
   {
      array[i] = i;
   }
   /* Perform calculations. */
   for ( i = 0; i < NELEM(array); ++i )
   {
      array[i] *= 2;
   }
   /* Print array. */
   for ( i = 0; i < ARRAYSIZE(array); ++i )
   {
      printf("%d,", array[i]);
   }
   putchar('\n');
}
Use With Functions
Finally, if you pass "the array" to a function, you are really only passing a pointer to the first element of the array. In such cases, you should also pass a size parameter to the function.
void fum(int *array, size_t size)
{
   size_t i;
   /* Initialize array. */
   for ( i = 0; i < size; ++i )
   {
      array[i] = i;
   }
   /* Perform calculations. */
   for ( i = 0; i < size; ++i )
   {
      array[i] *= 2;
   }
   /* Print array. */
   for ( i = 0; i < size; ++i )
   {
      printf("%d,", array[i]);
   }
   putchar('\n');
}

int main(void)
{
   int myarray[25];
   foo();
   bar();
   baz();
   qux();
   fum(myarray, ARRAYSIZE(myarray));
   return 0;
}
Team Colleague
Reputation Points: 2780
Solved Threads: 312
long time no c
Dave Sinkula is offline Offline
4,790 posts
since Apr 2004
Apr 7th, 2005
0

Re: C and C++ Timesaving Tips

This one is entertaining, and useful too. We all know ("we" being C++ programmers who came from C or still use C extensively) that scanf will eat up a format nice and pretty:
C++ Syntax (Toggle Plain Text)
  1. scanf ( "%d-%d-%d", &m, &d, &y );
If the input stream does not contain an integer followed by a '-' followed by an integer (shush Dave, and humor me), followed by a '-' followed by an integer, the call will fail. Sadly, this useful feature isn't available in C++ unless you use scanf. Using iostreams, you would be forced to do something painful like this (with suitable error handling, of course):
C++ Syntax (Toggle Plain Text)
  1. cin>> m;
  2. if ( cin.peek() == '-' )
  3. cin.ignore();
  4. cin>> d;
  5. if ( cin.peek() == '-' )
  6. cin.ignore();
  7. cin>> y;
Wouldn't it be nice if we could just do this and be done with it?
C++ Syntax (Toggle Plain Text)
  1. cin>> m >>"-">> d >>"-">> y;
Well, unfortunately it's not quite that easy. One could overload operator>> for a pointer to const char, but that kind of invades the implementation's personal space and therefore, is not portable.

To do it would be trivial though:
C++ Syntax (Toggle Plain Text)
  1. istream& operator>> ( istream& in, const char *s )
  2. {
  3. while ( *s != '\0' && in && in.peek() == *s ) {
  4. in.get();
  5. ++s;
  6. }
  7.  
  8. if ( *s != '\0' )
  9. in.setstate ( ios::failbit );
  10.  
  11. return in;
  12. }
This was my solution (more or less). I didn't need something portable, and the benefit of clarity was a decisive factor. Looking toward portability though, just as a mental exercise, I also considered the manipulator approach:
C++ Syntax (Toggle Plain Text)
  1. class scan {
  2. public:
  3. scan ( const char *init ): fmt ( init ) {}
  4. friend istream& operator>> ( istream& in, const scan& s )
  5. {
  6. while ( *s.fmt != '\0' && in && in.peek() == *s.fmt ) {
  7. in.get();
  8. ++s.fmt;
  9. }
  10.  
  11. if ( *s.fmt != '\0' )
  12. in.setstate ( ios::failbit );
  13.  
  14. return in;
  15. }
  16. private:
  17. mutable const char *fmt;
  18. };
It's almost as simple, but using it requires a bit more work:
C++ Syntax (Toggle Plain Text)
  1. cin>> m >> scan ( "-" ) >> d >> scan ( "-" ) >> y;
On a similar note, I also found a similar manipulator useful. The following manipulator will discard all characters in the stream up to (and including) a user defined character delimiter:
C++ Syntax (Toggle Plain Text)
  1. class moveto {
  2. public:
  3. moveto ( istream::int_type init ): ch ( init ) {}
  4. friend istream& operator>> ( istream& in, const moveto& d )
  5. {
  6. if ( in.rdbuf()->in_avail() > 0 )
  7. in.ignore ( numeric_limits<streamsize>::max(), d.ch );
  8.  
  9. return in;
  10. }
  11. private:
  12. istream::int_type ch;
  13. };
This is slightly more complicated than the usual "empty the buffer" call to ignore, designed to flush the stream of interactive input. That job could be performed with a simple moveto request:
C++ Syntax (Toggle Plain Text)
  1. cin>> moveto ( '\n' );
But, moveto is useful in parsing as well.

One can easily imagine how useful these manipulators can be. Not only does the scanf behavior of eating a format work with standard input and output, a clever programmer could easily pair them with stringstreams, fstreams, or even custom streams to solve a whole slew of formatted parsing problems without hacking together something big and ugly.

And with a little bit of extra work, the scan manipulator can be extended to more accurately mimic scanf's format processing.
Administrator
Reputation Points: 6442
Solved Threads: 1393
Bad Cop
Narue is offline Offline
11,807 posts
since Sep 2004
Apr 19th, 2005
0

Re: C and C++ Timesaving Tips

I know this may not seem like a super time saving technique, but the way you name your variables will help save time and reduce compile time errors.. Having a conventional variable naming format will help keep things organized and easy to read.

Styles

Typically, most variable names get the every other word capitalized. Functions get the first letter of each word capitalized and constants get all of the letters capitalized.

Example:

Variable: First letter of every other word capitalized.
  • char theName[20];
Functions: First letter of each word capitalized .
  • void GetTheName();
Constants: All capitals
  • #define THENAME 20
Of course, sometimes choosing a good variable name can take a long time!
Reputation Points: 28
Solved Threads: 9
Posting Whiz in Training
BountyX is offline Offline
222 posts
since Mar 2004
May 13th, 2005
0

Re: C and C++ Timesaving Tips

Reading an Integer

This is in many FAQs elsewhere, so this is just my repackaging of it here.

C Version
#include <stdio.h>
#include <stdlib.h>

int main(void)
{
   char response[32];
   /*
    * Prompt for input.
    */
   fputs ( "Enter your number: ", stdout );
   fflush ( stdout );
   /*
    * Read user response.
    */
   if ( fgets ( response, sizeof response, stdin ) != NULL )
   {
      /*
       * Attempt to convert user's response into an integer using strtol. The
       * second parameter to strtol allows for greater error checking if used.
       */
      int value = strtol ( response, NULL, 10/* radix or base */ );
      /*
       * No error checking was done, but attempt to display integer value.
       */
      printf ( "value = %d\n", value );
   }
   return 0;
}

/* my output
Enter your number: 12345
value = 12345
*/
C++ Version
#include <iostream>
#include <string>
#include <sstream>

int main(void)
{
   std::string response;
   /*
    * Prompt for input.
    */
   std::cout << "Enter your number: ";
   /*
    * Read user response.
    */
   std::cin >> response;
   /*
    * Attempt to convert user's response into an integer using a stringstream.
    */
   std::istringstream convert(response);
   int value;
   if ( convert >> value )
   {
      std::cout << "value = " << value << std::endl;
   }
   return 0;
}

/* my output
Enter your number: 456879
value = 456879
*/
Team Colleague
Reputation Points: 2780
Solved Threads: 312
long time no c
Dave Sinkula is offline Offline
4,790 posts
since Apr 2004
May 19th, 2005
1

Re: C and C++ Timesaving Tips

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:
C++ Syntax (Toggle Plain Text)
  1. using namespace std;
  2.  
  3. cout << "Hello world!" << endl;
Making only select names open to the current scope with a using declaration:
C++ Syntax (Toggle Plain Text)
  1. // Make cout and endl available, but nothing else
  2. using std::cout;
  3. using std::endl;
  4.  
  5. cout << "Hello world!" << endl;
And explicit qualification of every name for every use:
C++ Syntax (Toggle Plain Text)
  1. 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:
C++ Syntax (Toggle Plain Text)
  1. vector<int> c;
  2.  
  3. // ...
  4.  
  5. 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++:
C++ Syntax (Toggle Plain Text)
  1. 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 up.
Reputation Points: 35
Solved Threads: 3
Posting Whiz in Training
Dogtree is offline Offline
232 posts
since May 2005
Jun 23rd, 2005
0

time saving tip for C programmers

suppose you guys are writing a program which uses a number of loops,
use a single variable for all the loop counters and declare the variable to be of register storage class. what happens is that the variable gets stored in the cpu registers and the loops get executed a lot faster.
the syntax is:
register int i;
hope this was helpful.
Reputation Points: 9
Solved Threads: 1
Junior Poster in Training
indianscorpion2 is offline Offline
82 posts
since May 2005
Jun 23rd, 2005
0

Re: time saving tip for C programmers

Quote originally posted by indianscorpion2 ...
declare the variable to be of register storage class. what happens is that the variable gets stored in the cpu registers and the loops get executed a lot faster.
Rather ancient advice. Better advice is to improve the algorithm rather than micro-optimize.
http://www.eskimo.com/~scs/cclass/krnotes/sx7g.html
Team Colleague
Reputation Points: 2780
Solved Threads: 312
long time no c
Dave Sinkula is offline Offline
4,790 posts
since Apr 2004
Aug 23rd, 2005
0

Re: C and C++ Timesaving Tips

Avoid Loop Control Using eof()

All over the 'net C++ programmers are taught to "read until end of file". This leads to the following (incorrect) idiom for loop control.
#include <iostream>
#include <fstream>

int main()
{
  std::ifstream file("file.txt");
  if ( file )
  {
     int i;
     while ( !file.eof() ) // bad!!
     {
        file >> i;
        std::cout << i << ' ';
     }
     std::cout << std:: endl;
  }
  return 0;
}
Run the above code with the following text file, "file.txt".
Quote ...
1 2 3 4 5 6 7 8 9 10
Your output will be like this.
Quote ...
1 2 3 4 5 6 7 8 9 10 10
Note the repeated 10.

What To Use Instead

Change your thinking to "while successfully reading input from a file" and know that the state of the stream -- indicating successful input or a failure -- is available from the input operation.
#include <iostream>
#include <fstream>

int main()
{
  std::ifstream file("file.txt");
  if ( file )
  {
     int i;
     while ( file >> i )
     {
        std::cout << i << ' ';
     }
     std::cout << std:: endl;
  }
  return 0;
}
The output is now correct.
Quote ...
1 2 3 4 5 6 7 8 9 10
Then, for amusement, change "file.txt" to this.
Quote ...
1 2 3 4 5 6 7 8 9 1A
Then run each of the above programs.

Another Example

A similar thing can be done when reading text.
#include <iostream>
#include <fstream>

int main()
{
  std::ifstream file("file.txt");
  if ( file )
  {
     char line[80];
     while ( file.getline(line, sizeof line) )
     {
        std::cout << line << '\n';
     }
  }
  return 0;
}
Copy this source into "file.txt" and it will print out this code.

Further Reading:
http://www.parashift.com/c++-faq-lit....html#faq-15.2
http://www.parashift.com/c++-faq-lit....html#faq-15.3
http://www.parashift.com/c++-faq-lit....html#faq-15.4
http://www.parashift.com/c++-faq-lit....html#faq-15.5
Team Colleague
Reputation Points: 2780
Solved Threads: 312
long time no c
Dave Sinkula is offline Offline
4,790 posts
since Apr 2004
Aug 29th, 2005
0

Re: C and C++ Timesaving Tips

Dave,
in your first example with
C++ Syntax (Toggle Plain Text)
  1. while ( !file.eof() ) // bad!!
I could not get the extra 10
I am using Dev-C++ and Windows XP
Moderator
Reputation Points: 1333
Solved Threads: 1403
DaniWeb's Hypocrite
vegaseat is offline Offline
5,792 posts
since Oct 2004
Aug 29th, 2005
0

Re: C and C++ Timesaving Tips

>I could not get the extra 10
Put a newline at the end of the file.
Administrator
Reputation Points: 6442
Solved Threads: 1393
Bad Cop
Narue is offline Offline
11,807 posts
since Sep 2004

This thread is more than three months old

No one has posted to this discussion for at least three months. Please let old threads die and do not reply to them unless you feel you have something new and valuable to contribute that absolutely must be added to make the discussion complete. Otherwise, please start a new thread in this forum instead.
This thread is currently closed and is not accepting any new replies.
Previous Thread in C++ Forum Timeline: not sure why program crashes
Next Thread in C++ Forum Timeline: helpppppp me with this program





About Us | Contact Us | Advertise | Acceptable Use Policy
Forum Index | Build Custom RSS Feed


Follow us on Twitter


© 2011 DaniWeb® LLC