Open main menu

CDOT Wiki β

C/C++ FAQ

Revision as of 15:03, 25 November 2012 by Peter.liu (talk | contribs)

C/C++ FAQ

Q: Why is the postfix increment/decrement operator (e.g. a++ and a--) evaluated
   differently on different compilers?
Q: When we define a function-like macro, does the compiler ignore or take into
   consideration the spaces in between the parentheses?
Q: When using square-bracket pointer arithmetic, does ptr[-k] decrement the pointer?
Q: Is this syntax for pointer casting and dereferencing *(int*)p for void* p equivalent
   to (*(int*)p)?
Q: Why can't void* variables be dereferenced?
Q: Can a functional pointer be used to point to an overloaded function? If so, which
   function will it call when the pointer is dereferenced and why?
Q: How to redirect  cerr to  a file (instead of a console window)?
Q: How to visualize a multi-dimensional array?
Q: What is the correct way to pass a 2D array (called array) into a function? Which of the following is right: array[][],
   array[][COLS] or **array?
Q: When creating the header file for a template class and putting the implementation
   in the header as well there are no errors. However when splitting the deceleration
   (header) and implementation (making a cpp file) for that class template there are
   numerous compile errors. What do all these errors mean?
Q: Can Stacks, Queues or Lists be referenced using indexes?
Q: How to get size of an array without storing the size anywhere? 
Q: How do you get the length of a file / read the entire file without explicitly knowing its length,
   and how do you use that data afterwards?

Q: Why is the postfix increment/decrement operator (e.g. a++ and a--) evaluated differently on different compilers?
A: The evaluation of expressions, especially arithmetic expressions are based on sequence points which are undefined by the language. Arithmetic expressions containing complex postfix calculations are evaluated differently across different compilers because each compiler is unequally efficient. That is to say, these expressions are not portable as each compiler uses a different way to evaluate the expression based on its efficiency implementation. This can be noted by observing the process time of an expression across different platforms, which will be different for the same expression, due to different methods of evaluation.

  • Q: Where is the source of your information regarding sequence points and implementations used by different compilers? (pliu)
  • A: I learnt it in high school, not sure if there is a source.

For example, consider the following snippet:

   #include <iostream>
   using namespace std;

   #define PI 3.14

   int main()
   {
        double a = 2.35;
        cout << PI * ((a++) * (a++))<< endl;                              
        return 0;
   }

The GNU compiler prints 17.3407 as the output whereas the Borland compiler prints 24.7197 as the output.


Submitted by: Gideon Thomas and Marie Karimizadeh



Q: When we define a function-like macro, does the compiler ignore or take into consideration the spaces in between the parentheses?
For example:

#define F( x ) ((x) + (x))
int main()
{
   int a = 5;
   cout << F( a );
   return 0;
}

Which one of the following will the cout statement change to and why:

  1. cout << ((a) + (a));
  2. cout << x ) ((x) + (x)) a);

Note: in the second case, F( is considered the symbolic constant and is replaces by the rest of the string i.e. x ) ((x) + (x)) wherever it occurs.

A: cout << ((a) + (a)) will be executed. Although the compiler differentiates the symbolic constant from its value based on the position of the whitespace, ( tells it that it is a functional definition. #define follow the same identifier naming rules as variables do. Hence, ( cannot be included in the symbolic constant name and so the symbolic constant cannot be F(. Therefore, the compiler interprets this as a functional directive.


Submitted by: Gideon Thomas and Marie Karimizadeh



Q: When using square-bracket pointer arithmetic, does ptr[-k] decrement the pointer?
A: Yes. 'ptr' is the address of an element of the array; the array's element size is multiplied by the value of 'k', negated by '-', and then added to the address stored in 'ptr'. ptr[-k] moves to the element 'k' elements earlier than the element pointed to by ptr.


Submitted by: Kevin Kofler and Lucas Passarella, Team 9



Q: Is this syntax for pointer casting and dereferencing *(int*)p for void* p equivalent to (*(int*)p)?
A: Yes, however the latter is generally more accepted due to readability.
Submitted by: Team 6


Q: Why can't void* variables be dereferenced?
A: The pointer can't be dereferenced, because the compiler will not know how much of the memory is devoted to that particular value. For example if one has 8 bytes in memory with values in it, they are interpreted differently as int (2x 4 byte ints) and double (1x 8byte double). Without a data type the value cannot be determined therefore casting must be done first.
Submitted by: Team 6 (BTP300B)



Q: Can a functional pointer be used to point to an overloaded function? If so, which function will it call when the pointer is dereferenced and why?
Question Submitted by: Gideon Thomas and Marie Karimizadeh

A:Function Pointer can be used to point to any function with the same signature as its own.
"Signature is the information about a function that participates in overload resolution: its parameter-type-list... Function signatures do not include return type, because that does not participate in overload resolution." (Working Draft, Standard for Programming Language C++ 2005-10-19, p3, 1.3.11 signature)
In the case of overloaded functions the only thing they have in common is the name. Signatures are different, hence the same pointer to function can't be used for both of them.

Back to your question. Call to Function Pointer will call an overloaded function with the same signature as the Function Pointer.
Answer Submitted by: Team42

Q: How to redirect cerr to a file (instead of a console window)?
A:Use the rdbuf( ) method. [1]


Q: How to visualize a multi-dimensional array?
A: The simplest way to do so for a 2 dimensional array is a table

0123
4567
7890

It gets slightly more complex when it comes to 3 dimensional arrays

  • First what comes to minds of majority of people is a cube
            __________	
           /\444444444\
	  /\3\444444444\
	 /\2\3\444444444\
	/\1\2\3\444444444\
	\0\1\2\/33333333\/
	 \0\1\/22222222\/
	  \0\/11111111\/
	   \/00000000\/

(There are many disadvantages to using this form besides awkwardness!)


  • Another way is to display each of the layers as separate 2 dimensional arrays
111
111
111

222
222
222

333
333
333

To be Continued (Feel free to add your ideas! :D)

Submitted by Team42

Q: What is the correct way to pass a 2D array (called array) into a function? Which of the following is right: array[][], array[][COLS] or **array?
A: Any of the stated syntaxes are acceptable for passing a 2D array into a function. Generally the 2nd syntax (array[][COLS]) is used if the array is static and the number of cols is known. This is in order to reveal the preferred structure to the compiler, since the compiler stores a 2D array as one really long array with arrays as its elements. For example an array[3][3] would looks something like this in memory | |||| | |||| | |||| | where as we perceive the structure as a table. The other 2 syntaxes are equivalent and are generally used to pass a 2D array into a function if the structure is not know, hence for dynamic created arrays.

  • Comment (pliu): Excellent question and explanation. We need to make a distinction between a STATIC 2-d array and a 2-d array that is created by DYNAMAC MEMORY ALLOCATION.

Submitted by: Team 6




Q: When creating the header file for a template class and putting the implementation in the header as well there are no errors. However when splitting the deceleration (header) and implementation (making a cpp file) for that class template there are numerous compile errors. What do all these errors mean?

Possible errors:

arrayWrong.cpp:6:1: error: invalid use of template-name 'Array' without an argument list

arrayWrong.cpp:12:1: error: invalid use of template-name 'Array' without an argument list

arrayWrong.cpp:24:1: error: invalid use of template-name 'Array' without an argument list

arrayWrong.cpp:30:1: error: invalid use of template-name 'Array' without an argument list

arrayWrong.cpp:46:14: error: 'template<class T> class Array' used without template parameters



  • comment (pliu): Could you please post up the source code and the listing of compiler error messages please?

A: When splitting the deceleration of a template class additional code must be added onto every method of that class. If one has a class called Stack and a function called add(int x) for example, then in the implementation file the display function would be defined in the scope of the Stack class by writing int Stack::add(int x). Since templates are being used the compiler must also be told that this implementation is being defined with a template. This is done by writing something like template<class T> before every function. For the example stated it would look like this:

template<class T>

int Stack<T>::add(T x)
Submitted by: Team 6




Q: Can Stacks, Queues or Lists be referenced using indexes?
A: The answer is no. Linear data structures are used when the programmer does not know how many elements of an array there are going to be overall(assuming arrays are used over linear data structures)by the end of the programs termination. The problem that arises with using arrays when the number of elements is unknown is that dynamic allocation, copying and deletion need to be preformed every time a new element is added, altered or deleted in a sequence of data. In order to keep an index of the Nodes (in a linear data structure) a dynamic array would have to be made with a number to signify the artificial index of the linear data structure Node. The programmer could then refer to an index of the array that will automatically loop through the linear data structure (via a code block) to give a result. This would defeat the purpose of a linear data structure because the array holding the indexes would have to be deleted and reallocated every time the linear data structure changes.

Example explanation: A stack has numbers 15 10 5 on it and an array allocated to 3 indexes (with values 0, 1, 2) to match the number of Nodes. If a person adds 1 more data to the Stack (push(20))then the array would have to be deleted and reallocated, defeating the purpose of the stack in the first place.
Submitted by: Team 6

Q: How to get size of an array without storing the size anywhere?
A: There are several ways to get the length of an array without explicitly knowing its length. The C method is as follows

#define SIZEOF_ARRAY( a ) (sizeof( a ) / sizeof( a[ 0 ] ))

The above define macro can be called to find the size of an array in a C manner. This function exists in the std namespace.
One could also use the below code for a more effective (but c++ only) solution.

#include <iostream> using namespace std;  
template <typename T, size_t N> 

inline 

size_t SizeOfArray( const T(&)[ N ] ) {

	return N; 

}


int main() {  

	const char s[] = "Hello world!";
	cout << "s[] is " << SizeOfArray( s );
}

The good thing about the above method is not only its improved efficiency (most compilers will optimize the template function out of existance upon compilation) but the fact that it will not work with a pointer to an array, such as

const char* s = "Hello world!";  cout << "s is " << SizeOfArray( s )

Lastly, with C++11 there is an even better method of doing this: std::extent. More info on this trait class can be found here.
Submitted by Team42.

Q: How do you get the length of a file / read the entire file without explicitly knowing its length, and how do you use that data afterwards?

A: There are several ways to read the contents of a file without knowing it's length and then split the result into usable parts. First, you could use a string class and load the contents of the entire file into the string object. At this point you can manipulate it as any other string object (not to be confused with a char array) by using methods such as find, substr, erase, etc as outlined here

std::ifstream in("myfile", ios::binary);
std::stringstream buffer;
buffer << in.rdbuf();
std::string contents(buffer.str());

You could also use

inMyStream.seekg(0,std::ios_base::end);
    std::ios_base::streampos end_pos = inMyStream.tellg();
    return end_pos;

to get the length of the file without actually reading it, and then if needed read / append / modify it as required using a char array.. This method of getting a file's length can be used with char arrays / strings / vectors without problems. Lastly, you could also load the file into a vector and manipulate it as a vector object from that point onwards (more advanced topic) like so

std::ifstream ifs("foobar.txt", ios::binary);
ifs.seekg(0, std::ios::end);
std::ifstream::pos_type filesize = ifs.tellg();
ifs.seekg(0, std::ios::beg);
std::vector<char> bytes(filesize);
ifs.read(&bytes[0], filesize);

For any of these methods, to be able to work with the data afterwords simply use a common delimiter when originally generating the file, and then you can use methods like strtok (for char array), .find combined with .substr (string class) or use it as a vector (if that's required).
Submitted by Team42.