tut on void pointers

I'm having a real hard time understanding this. What I think I do understand is that the program is passing the address of "a" and "1" to the function "increase." I know that the value "x" is changed to "y" when the program reaches this "++(*pchar). I think I understand that since this is a void function it doesn't return anything, also there is no return statement. If this is true then the function is changing the value of "a", but how? Anyone have a flashlight?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#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 = 'x';
  int b = 1602;
  increase (&a,sizeof(a));
  increase (&b,sizeof(b));
  cout << a << ", " << b << endl;
  return 0;
}
there is two ways to call a function ....
(1) : call by value
(2) : call by reference

you here call by reference . you should read how a function call is working passing parameters left to right to the stack ,and inside the function call they are poping right to left. If you see actual assembly code for this , you can
make it crystal clear.
Increase is being given a pointer to a memory location which happens to be where "a" is stored. Its purpose is to increment the value stored in that memory location. That is what ++(*pint) does.
Thanks for replies, both help. I'll go back and read about functions again. One thing about this I do not understand is what (char*)data and (int*)data means. I think I understand what everything else is doing including that ++(*pchar) and ++(*pint) is incrementing the addresses by 1.

I see in both cases where it is pointing to the address, I just don't see where it changes the value.

EDIT: How do you know this is a call by reference? I would think this "data&" would mean it was passed by reference.
Last edited on
what (char*)data and (int*)data means


That means typecasting. you can read
http://www.cplusplus.com/doc/tutorial/typecasting.html

anyway let me explain that statement for you:
1
2
3
4
5
6
7
void increase (void* data, int psize)                                  // line 1 
{
  if ( psize == sizeof(char) ) 
  { 
     char* pchar;                                                                 // line 2  
     pchar=(char*)data;                                                      // line 3
     ++(*pchar); }                                                               // line 4  

oky , you agree that , inside this function's scope , data is type of
void *
void * is a void pointer. you can see it it definition in the line 1 .
in the line 2 you can see another definition of the pchar which is type
char *
so . In the C++ , strongly typed language , the "void *" and the
"char *" is different. It's like int and long. So that's why we need
some typecasting. so we write ,
pchar=(char*)data;
That means you convert a void pointer to a char pointer. and then you can use it like a char pointer . In the line number 3 you have use it as a
char pointer.
++(*pchar);

Now got clear ?

well for the next question :
I just don't see where it changes the value.

well nothing is hiding by the compiler. Nothing magic is going behind the screen. If you are using the visual studio IDE , then you can just debug
your program and trace how line by line executing the program. Using the
watch window you can inspect each variables. And everything will be crystal
clear after that.

--
I am just yet a newbie , please tell me if I suggesting bad , I will be quite and listen.
EDIT: How do you know this is a call by reference? I would think this "data&" would mean it was passed by reference.


call by reference is like this ,
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
 
#include <iostream.h>
  
void function1 ( int &a )
{ 
     a++;
}

int main ()
{
   int a = 10 ;
   cout << " Before calling ,  a = " << a << endl ;
   function1 ( a ) ;
   cout << " After calling     , a = " << a << endl ;
   return 0;
}


you can see the things are changed after calling the function1 . But for this ...

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <iostream.h>
  
void function1 ( int a )
{ 
     a++;
}

int main ()
{
   int a = 10 ;
   cout << " Before calling ,  a = " << a << endl ;
   function1 ( a ) ;
   cout << " After calling     , a = " << a << endl ;
   return 0;
}


you can see same values before and after calling. So that is the difference between the calling by reference and calling by value.

you can call by reference by using the pointers also. like this

1
2
3
4
void function1 ( int * p) 
{
    (*p)++ ;
}



and call like this
 
 function1 ( &a ) ;


--
I am just yet a newbie , please tell me if I suggesting bad , I will be quite and listen.
Last edited on
sanzilla you are no newbie to me. I'm trying to absorb all this but understanding a lot more. Thank you!

EDIT: I'm thinking now that in the original program, the first parameter "&a" is passed by reference, the second "sizeof(a)" is passed by value and both are void pointers. Then both of these have to be converted, the first to type "char" and the second to type "int." Is this correct?
Last edited on
first of all sizeof is a keyword. sizeof(a) is not a function call.
typically sizeof(a) returns the value , 1 and sizeof( b) returns the value 4. you
can inspect them , just write a simple program and see
1
2
3
4
5
6
7
8
9
10
11
#include <iostream.h>
#include <iostream.h>

int main() 
{
    char a = 'x';
    int b = 10 ;
    cout << sizeof ( a) << endl ;
    cout << sizeof ( b) << endl;
    return 0;
}

that means the value passing using sizeof(a) is not pass by reference , it is just pass by value.


anyway &a means , & operator output's the address of the a . For a example
you can write like this.
1
2
 int a  = 10 ;
 int * pointer_to_a = &a ;



Last edited on
the second "sizeof(a)" is passed by value and both are void pointers


sizeof(a) is passed by the value, yes. But not by a void pointer. pass by value
is happen by pushing that value to the stack. That value is stored on the stack .
for the second parameter it takes int as value . you can see that.

1
2
     void increase (void* data, int psize)
                                               ^

because int is 4 bytes long it will grow down the stack into 4 bytes.

but for the second parameter the address of integer 'a' is pushed to the stack. and it's type is void * , a pointer is a 32-bit means 4 bytes long , and
it also allocates 4 bytes from the stack, and it points to the variable 'a'.

if you like to see how the assembly machine code is generating for this , you will get crystal clear on this.
Last edited on
Then both of these have to be converted, the first to type "char" and the second to type "int." Is this correct?


No , you can convert a int to a char like this
1
2
3
4
5
char c = 'A' ;
int i =10 ;

i = (int) c ; // here typecast char to int .... 
cout << i << endl ;


Then you can convert a integer pointer to a char pointer like this .
1
2
3
4
5
char c = 'A';
int i = 10;

int * ip = &i ; // &i returns a int * type
char * cp = (char * ) ip ; // we convert int * to a char *  


like this (int *) is not type (int) , and (char *) is not the type (char) .
clear ?
Last edited on
Yes sanzilla, thanks to you I think I finally understand. The program is passing the address of "a". The function accepts this address as a void pointer and then uses "pchar=(char*)data" to convert it to a char pointer. When pchar is incremented it changes the value from "x" to "y." Maybe I didn't say this technically correct but I see what is happening. Thank you very, very much for taking so much time to explain this.
Last edited on
makes perfect sense to people who have written memory management systems ;)

see the added 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
26
27
28
29
30
31
32
33
#include <iostream>
using namespace std;

void increase (
    void* data,   // this is a random address to memory
    int psize     // this is the number of bytes at the memory location that matter
    )
{
  if ( psize == sizeof(char) )   // if we're being told that 1 byte matters (assume this is a char)
  {
    char* pchar;
    pchar=(char*)data;  // turn the random address into an address of a character variable
    ++(*pchar);  // grab the data at the address of this character variable, and increment.
  }
  else if (psize == sizeof(int) )  // same as above, bit with integer instead of character
  {
    int* pint;
    pint=(int*)data;
    ++(*pint);
   }
}

int main ()
{
  char a = 'x';  // declare a char, 1 byte of memory
  int b = 1602;   // declare an int, 4 bytes of memory
  // call the function with each address to memory, 
  // and the size of the variable at that memory space.
  increase (&a, sizeof(a));
  increase (&b, sizeof(b));
  cout << a << ", " << b << endl;
  return 0;
}
Years ago I worked extensively with DBase, FoxPro and some Oracle. I started the tuts thinking I had a leg up because of that experience. Maybe I did as far as control structures and operators. But it was a real disadvantage in understanding everything else. I pretty much skimmed over data types and constants thinking I understood that. I did not. It was not until you fellas took the time to dissect this little program that I really began to understand the difference between 'x' and "x".

Until I understood that I could make no sense of 'x'+1 being 'y' and this concept is still pretty incredible. cheif, thanks for posting exactly what this program is doing.
Topic archived. No new replies allowed.