more pointer help please :/

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// increaser
#include <iostream>
using namespace std; 
void increase (void* data, int psize) 
{ 
  if ( psize == sizeof(char) ) 
   { char* pchar; pchar=(char*)data; ++(*pchar); }      
  else if (psize == sizeof(int) ) 
  { int* pint; pint=(int*)data; ++(*pint); } 
} 
int main () 
{ 
  char a = 'a'; 
  int b = 1602; 
  increase (&a,sizeof(a)); 
  increase (&b,sizeof(b)); 
  cout << a << ", " << b << endl; 
  system ("Pause");
  return 0; 
}

could someone please explain this code sequence to me. the first half. ive sat here for an hour looking at the tutorial trying to understand it. :(
Essentially, the increase function takes a void* (I read this as "pointer to something"), converts the pointer to the appropriate type based on the parameter psize, and increments whatever the pointer is pointing to.

The important thing to note is with a void* you will need some knowledge of what that pointer points to in order to work with it. In this "tutorial", they chose to pass the size of the data type so that increase can make sense of the void*.

Here is an equivalent piece of code without the use of potentially dangerous pointer casting:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <iostream>
#include <limits>

template <typename T>
void increase(T& t)
{
   ++t;
}

int main()
{
   char a = 'a';
   int b = 1602;

   increase<char>(a);
   increase<int>(b);

   std::cout << a << ", " << b << std::endl;

   std::cout << "Press ENTER to continue..." << std::endl;
   std::cin.ignore( std::numeric_limits<std::streamsize>::max(), '\n' );

   return 0;
}
Last edited on
that didnt really help. im following the manual on this site dont know anything about <limits> or templates... i need it really broken down ;/ and how are the pointers potentially dangerous?
A void* is just like any other pointer, except it has no type. For increase() to know what type of data it is, "psize" is set along with it.

So:
increase(&a, sizeof(a)); // pass the location of a with it's size

if (psize == sizeof(char)) // which it does, since we gave it sizeof(a), a being a char.

1
2
3
4
char* pchar;  // declare another char*
pchar=(char*)data; // set it's value (the address) to the void* passed (which is being cast as a char*)
// the value of pchar  is now the same as &a in main()
++(*pchar); // increment the value in the de-referenced pchar. 


I had functions passing void* once, but in the end decided a simple overload/template was the way to go.

High (maybe low) level APIs might return a void*, in this case it would be your job to immediately cast it to the proper type.
Last edited on
I assume the part that's giving you trouble is the increase function. I have provided explanations in comments:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
//increase is a function that takes in data, a pointer to something, as well as the size of the
//data type pointed to by data (psize). Based on psize, this function converts
//data to the appropriate pointer type and increments the value pointed to by one.
//Currently this function assumes that data points either to a char or an int
void increase (void* data, int psize) 
{ 
   if ( psize == sizeof(char) ) 
   {
      //here we know that data points to a char, because the size of
      //the datatype matches that of char

      char* pchar; //instantiate a pointer to a char
      pchar=(char*)data; //convert data to be a pointer to a char, store the pointer in pchar
      ++(*pchar); //increment what pchar points to by one
   }      
   else if (psize == sizeof(int) ) 
   {
      //here we know that data points to an int, because the size of
      //the datatype matches that of int

      int* pint; //instantiate a pointer to an int
      pint=(int*)data; //convert data to be a pointer to an int, store the pointer in pint
      ++(*pint); //increment what pint points to by one
   } 
}


im following the manual on this site dont know anything about <limits> or templates...

The code that uses <limits> is the last line:

std::cin.ignore( std::numeric_limits<std::streamsize>::max(), '\n' );

which is a replacement to system("Pause");

http://cplusplus.com/forum/beginner/1988/

how are the pointers potentially dangerous?

Converting between pointer types is potentially dangerous because if the converted pointer type is wrong, you could end up doing undefined behaviour such as writing over memory you don't own.

Observe the following:

1
2
3
4
5
6
7
8
9
int main()
{
   char aCharacter = 'a';
   int pint = (int*) &aCharacter; //pint points to an int (say 4 bytes) but the char is only one byte

   *pint = 1000000; //we have now just played with memory we potentially don't own (the extra three bytes beside where aCharacter is in memory

   return 0;
}
Last edited on
if psize is defined as an integer in the void increase than how can it be a character too?
I think I can explain this more simply.

You pass in a pointer, and the size of the data type that the pointer is pointing to.

If the data size is that of a char, assume the pointer is pointing to a char, and increment that char, and finish.

If the data size is that of an int, assume the pointer is pointing to an int, and increment that int, and finish.

Otherwise, do nothing.

That's it.


Be aware that it's awful code and that there are much better ways to do this.
Last edited on
oh ok so does that mean since void is pointing to data, that data has no value at its memory address?
oh ok so does that mean since void is pointing to data, that data has no value at its memory address?


No. That's impossible. Every piece of memory holds some value. I think you need to go back to the basics of what a pointer is:
http://www.cplusplus.com/articles/EN3hAqkS/
OHHH I UNDERSTAND A LITTLE BIT MORE Maybe.
pchar=(char*)data;
so char points to data because its not defined as an integer or a character. so you can use it in both situations like this too
pchar=(int*) data;
right?
pchar=(char*)data;
This means: take the object named data, and pretend it is a char* (i.e. pretend it is a pointer to a char). Make pchar equal to that pointer (i.e. pchar is a char*, pointing at whatever data is pointing at).

pchar=(int*) data;
This means: take the object named data, and pretend it is a int* (i.e. pretend it is a pointer to a int). Make pchar equal to that pointer (i.e. pchar is a int*, pointing at whatever data is pointing at).


This kind of casting, using void*, is bad. Do not do it unless you really have no choice. There are far better ways to do this.
Last edited on
how would you go about doing it than?
1
2
3
4
5
6
7
8
9
10
11
void increase (void* data, int psize) /*increases takes a type of data and a size. void* data is the
data type because the pointer changes the meaning of data stored at its memory address? */ 
{ 
  if ( psize == sizeof(char) ) // if psize is equal to the size of the character entered
   { char* pchar; pchar=(char*)data; ++(*pchar); }// pchar is the value pointed by char.
   // pchar = the value of what char is pointing to.
   // increase the value of what pchar is pointing to by one.
  else if (psize == sizeof(int) ) // if psieze is equal to the size of the number entered
  { int* pint; pint=(int*)data; ++(*pint); } // pint is the value pointed by the number
// pint is the value of what int is pointing to
// increase the value of what pint is pointing to by one. 
is that right than?
how would you go about doing it than?

With a template function, for instance:

1
2
3
4
5
6
7
8
9
10
11
template <typename T>
void increase(T& t)
{
   ++t;
}

char a = 'a';
int b = 1602;

increase<char>(a);
increase<int>(b);


http://cplusplus.com/doc/tutorial/templates/

I think the tutorial should have a little blurb about how you should use void pointers only when necessary.
Last edited on
Topic archived. No new replies allowed.