Connect with us

Passing an address to a function

Discussion in 'Microcontrollers, Programming and IoT' started by Horn, Jun 18, 2012.

  1. Horn

    Horn

    42
    0
    Jun 4, 2012
    I am wanting to pass multiple addresses to a function in c I have tried the following form.

    deceleration
    void FUNCTION(char &Var1[], char &Var2[][], int &Var3);

    calling
    FUNCTION( &Var1[], &Var2[][], &Var3)

    Doing this allows me to modify the values in the function without having to return the values through the function. However I am getting syntax errors. I could use a few suggestions.
     
  2. Harald Kapp

    Harald Kapp Moderator Moderator

    9,396
    1,919
    Nov 17, 2011
    It looks like you are confusing poinmters (addresses) and values.

    In C, if you want to pass an adddress to a function, you declare e.g.:

    void FUNCTION (char* test); /* *test is a character, so test alone is the address of the character */

    Assuming the following declaratikon of the cvariable test within main:

    main()
    {
    char test[100]; /* delcare char array test with 100 elements */
    ...

    You can call


    FUNCTION (test); /* test is the address of test[0] */

    An example:

    Code:
    #define MAXCHAR 100
    
    void FUNCTION (char* test);
    
    int _tmain(int argc, _TCHAR* argv[])
    {
    	int i;
    
    	char test[MAXCHAR];
    
    
    
    	for (i=0;i<MAXCHAR;i++)
    		test[i] = ' ';
    	FUNCTION(test);
    	std::cout << test[0];
    
    
    
    	return 0;
    }
    void FUNCTION (char* test)
    {
    	int i;
    	for (i=0;i<MAXCHAR;i++)
    		*test++ = 'A';
    	*(--test)= 0x00; /* end of string */
    }
    Or if your variable within the calling routine (main) is not declared as pointer, you get its address using the "&":

    Code:
    char test; /* declare test as single character */
    
    FUNCTION (&test); /* call FUNCTION with the address of test as parameter */
    Harald
     
    Last edited: Jun 18, 2012
  3. Horn

    Horn

    42
    0
    Jun 4, 2012
    I am getting a lot of illegal pointer to integer warnings on almost any combination of * and & I can make up and have scoured the internet and see that their are 1001 different ways to do this but they all "freeze up" my PIC. When I run the following code it does not even make it into main before freezing.

    #include <pic.h>
    #include <string.h>
    #include <stdio.h>

    #include "define.h"
    //void CLEAR(uchar8 *Temp, uint8 STemp, uchar8 *Table, uint8 STable, uint8 *x, //uint8 *y, uint8 *v, uint8 *c, uint8 *ck)

    main()
    {
    int x, y, v, c, ck, STemp, STable;
    char Temp[30], Table[3][3];

    STemp=sizeof(Temp);
    STable=sizeof(Table);

    CLEAR(Temp, STemp, Table, STable x, y, v, c, ck);


    }

    void CLEAR(uchar8 *Temp, uint8 STemp, uchar8 *Table, uint8 STable, uint8 *x, uint8 *y, uint8 *v, uint8 *c, uint8 *ck)
    {
    memset(*Temp, 0x20, STemp);
    memset(*Table, 0x20, STable);
    *x=0;
    *y=1;
    *v=2;
    *c=0;
    *ck=0;
    }


    Are their any obvious problems or possibly wiring issues?
     
  4. Harald Kapp

    Harald Kapp Moderator Moderator

    9,396
    1,919
    Nov 17, 2011
    1) the declaration s (data types) of your variables should match those in the function header. You mix data types:

    declaration of variables:
    int x, y, v, c, ck, STemp, STable;
    char Temp[30], Table[3][3];

    use in function header:
    void CLEAR(uchar8 *Temp, uint8 STemp, uchar8 *Table, uint8 STable, uint8 *x, uint8 *y, uint8 *v, uint8 *c, uint8 *ck)

    You should stick to one data type, e.g. either int or uint, but do not mix them. This would lead to:

    void CLEAR(char *Temp, int STemp, char *Table, int STable, int *x, int *y, int *v, int *c, int *ck)

    Which still isn't correct.

    2) Let''s analyze this fragment:
    void CLEAR(char *Temp, int STemp, char *Table, int STable, int *x, int *y, int *v, int *c, int *ck)
    Since Temp is declared as
    char Temp[30]
    Temp (without * or &) is a pointer to the array. Therefore you can use Temp (without any qualifier) to submit the address of the array to the subroutine.
    The same is true for Table.

    x, y etc. are defined as:
    int x, y, v, c, ck;
    Therefore, in order to get the address of one of these variable you need to qualify the variable by the & sign:
    address of x = &x
    In the function header the syntax ... int *x... signifies that you will not handle the value of x, but its address. So this part of your code looks o.k.

    In all, the code should like something like this:

    main()
    {...
    CLEAR(Temp, STemp, Table, STable &x, &y, &v, &c, &ck);


    ...}
    void CLEAR(char *Temp, int STemp, char *Table, int STable, int *x, int *y, int *v, int *c, int *ck)
    {...}

    I have two tips:
    1) It may be easier to first get a grasp of the C syntax by using a C complier on the pC and get a feeling for the language. E.g. the free personal edition of Microsoft Visual Studio or GCC.
    2) Using pointer (addresses) in C is rather easy, once you have understood the concept. However, even professionals time and again stumble over runtime errors caused by pointers that contain wrong or even illegal values. This can happen, for example, if you assign a value to a pointer without completely checking the validity of the value or if you do pointer arithmetic (increment, decrement are good candidates).
    I therefore recommend that you deeply consider whether it is wise to use a pointer or if another, less critical method can do the job.

    In your example, you could have
    either:
    - placed the short piece of code for nulling the arrays and variables into the main code. Unless you need this subroutine more than once, this will save you runtime overhead since no subroutine call needs to be performed.
    or:
    - made the arrays and the variables global variables. You can then access them by the subroutine without the need to handle pointers.

    Every method has advantages and drawbacks. Which one prevails depends on the particular programming problem at hand.

    Oh, and one very general tip: When you are dealing with a new situation in programing (e.g. syntax elements, data structures etc that are new to you) I suggest starting with very basic examples to get a grasp of the problem and its solution in the programming language used. In the above example, it would have been a good idea to start with justa single variable to learn the concepts of the * and & operator.
    Here http://www.physics.drexel.edu/courses/Comp_Phys/General/C_basics/ is a tutorial on C programming (including pointers).

    Harald
     
  5. LordSputnik

    LordSputnik

    45
    0
    Aug 11, 2011
    Your original idea is fine. The problem is, that your using a strange combination of C++ and C.

    In C++, the & operator, when used in a function declaration, indicates to the compiler that the value should be passed by reference. References are similar to pointers, but they always point to a valid address.

    eg.
    Code:
    void a_function ( int & a )
    {
    a = 5;
    }
    
    int main()
    {
    int b = 0;
    a_function(b);
    /* Value of b is now 5, as we modified the value through a reference. */
    
    return 0;
    }
    In C, there are no references, so to achieve the above, you'd use:

    Code:
    void a_function ( int* a )
    {
    (*a) = 5;
    }
    
    int main()
    {
    int b = 0;
    a_function(&b);
    /* Value of b is now 5, as we passed a pointer to the integer to a function, then dereferenced the pointer to modify the value that it points to. */
    
    return 0;
    }
    You're trying to modify an array. An array is just a pointer to a block of memory. So, for example, an array of ints could be passed to a function taking a pointer to an int:

    Code:
    void a_function ( int* a )
    {
    (*a) = 5;
    }
    
    int main()
    {
    int b[10];
    a_function(b);
    /* Value of b[0] is now 5, as we passed a the array to a function, then dereferenced the pointer to modify the value that it points to. */
    
    return 0;
    }
    So the value "pointed to" by an array is the first element of the array.

    In your case, it looks like you want to pass an array, a 2D array and a variable to be modified in a function. To do this, you'd use this sort of code:

    Code:
    void a_function(char* a, char** b, int* c)
    {
    /* Do stuff here. For example: */
    a[5] = 2;
    b[1][3] = 6;
    (*c) = 2;
    }
    
    int main()
    {
    char x[10];
    char y[2][4];
    int z = 0;
    
    a_function(x, y, &z);
    //Modifies x, y and z.
    
    return 0;
    }
    I believe that this should work, although I haven't tested any of these samples, and it's been a few months since I last did any major C programming...

    EDIT: Whenever you pass an array to a function, it's also good to pass in the dimensions of the array, so that you don't accidentally access memory you shouldn't. Eg.

    Code:
    void a_func(int* a, size_t b)
    {
    //Do stuff.
    }
    
    int main()
    {
    int x[10];
    a_func(x, 10);
    }
     
    Last edited: Jun 18, 2012
  6. Horn

    Horn

    42
    0
    Jun 4, 2012
    Harald you are right I read over the link you sent and I need to back down and open my visual studio again. I have used matlab too much. Also in my code I switched variable types to simplify my program and seems I forgot some, sorry. I have also tried what you recommended and it still throws warnings with the 2D array but works.

    I tried your idea Lord Sputnik with the 2D array and it still throws the "illegal conversion between pointers" warning but it again works fine. As much as I hate to see warnings I may let this one slide for now and practice my knowledge of pointers on another project in visual studios and come back to tackle this at a later date.

    Thank you both for the very helpful information. I am sorry to continue to bother you Harald! :)
     
  7. LordSputnik

    LordSputnik

    45
    0
    Aug 11, 2011
    I read somewhere yesterday, you may need to explicitly state the number of columns:

    Small example program, which compiles fine in gcc with no additional parameters:
    Code:
    #include <stdio.h>
    
    void func( char (*p)[3] )
    {
      int x, y;
      for( x = 0; x != 5; ++x )
      {
        for( y = 0; y != 3; ++y )
            printf("%i ",p[x][y]);
        
        putchar('\n');
      }
    }
    
    int main()
    {
      char x[5][3] = {};
      func(x);
      
      return 0;
    }
     
  8. Harald Kapp

    Harald Kapp Moderator Moderator

    9,396
    1,919
    Nov 17, 2011
    Sounds logical for a multidimensional array. How else should the compiler know that the argument is the address of a multidimensional array and not just a linear array?

    Harald
     
  9. Horn

    Horn

    42
    0
    Jun 4, 2012
    and we have a winner! It is no longer throwing any warnings and is working properly. One question though, why? Do you happen to have that link or where you found it in a book?
     
  10. LordSputnik

    LordSputnik

    45
    0
    Aug 11, 2011
    It's here:

    http://www.xargs.com/pic/c-faq.html#twodarray

    In short, the compiler needs to know how many columns you're using, so that it can properly dereference the indices you provide. It's to do with the way the 2D array is laid out in memory.
     
  11. Horn

    Horn

    42
    0
    Jun 4, 2012
    That page contains a lot of information I need not just with the 2D array. Thank you very much Lord Sputnik!
     
Ask a Question
Want to reply to this thread or ask your own question?
You'll need to choose a username for the site, which only take a couple of moments (here). After that, you can post your question and our members will help you out.
Electronics Point Logo
Continue to site
Quote of the day

-