LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Programming (https://www.linuxquestions.org/questions/programming-9/)
-   -   Unable to pass array as parameter, using void pointer, s.t. the contents too are accessed in the called function. (https://www.linuxquestions.org/questions/programming-9/unable-to-pass-array-as-parameter-using-void-pointer-s-t-the-contents-too-are-accessed-in-the-called-function-4175726056/)

ajiten 06-16-2023 01:21 AM

Unable to pass array as parameter, using void pointer, s.t. the contents too are accessed in the called function.
 
In the below program, there is one type of error, repeated twice, on execution in Cygwin.
Code:

#include <stdio.h>
     
void foo(void *p)
{
        while(* (int *)p) //Doubt #1: first typecast to integer, then deference it. Else (i.e., without typecast and just stating : while( *p)) get one additional error, as shown below in 'Errors2'.
        //Doubt #2: how to change the typecast to 'char' data-type, as have chosen fixed typecast to 'int'?
              print("%p \n", *p);
      //Doubt #3: How to access the contents of the array, and if use: **p, then do I need change from %p to %d, or %c; accordingly.
      //Currently, due to unable to compile, not able to see the difference, in output, between **p, and *p. Though, seems that to access the contents, need **p instead.
}

int main()
{
        int x[10] = {1,2,3,4,5,6,7,8,9,10};
        char c[5] = "ABCDE";
        void * p = x;
        *p = c;
        foo(&x);
        foo(&c);
        return (0);
}

Errors:
Code:

b.c: In function ‘foo’:
b.c:3:54: warning: dereferencing ‘void *’ pointer
    3 | void foo(void *p) { while(*(int *)p) printf("%p \n", *p); }
      |                                                      ^~
b.c:3:54: error: invalid use of void expression
b.c: In function ‘main’:
b.c:10:9: warning: dereferencing ‘void *’ pointer
  10 |        *p = c;
      |        ^~
b.c:10:12: error: invalid use of void expression
  10 |        *p = c;
      |            ^


Errors 2:
Code:

b.c:3:28: warning: dereferencing ‘void *’ pointer
    3 | void foo(void *p) { while (*p) printf("%p \n", **p); }
      |                            ^~
b.c:3:28: error: void value not ignored as it ought to be
    3 | void foo(void *p) { while (*p) printf("%p \n", **p); }
      |                            ^
b.c:3:49: warning: dereferencing ‘void *’ pointer
    3 | void foo(void *p) { while (*p) printf("%p \n", **p); }
      |                                                ^~
b.c:3:49: error: void value not ignored as it ought to be
b.c: In function ‘main’:
b.c:10:9: warning: dereferencing ‘void *’ pointer
  10 |        * p = c;
      |        ^~~
b.c:10:13: error: invalid use of void expression
  10 |        * p = c;
      |            ^


NevemTeve 06-16-2023 03:11 AM

What is the goal? What do you wish to accomplish with this code?

pan64 06-16-2023 03:13 AM

what do you want to print?
The pointer itself? printf("%p \n", p)
The integer? printf("%i \n", *(int *)p)
or ?

ajiten 06-16-2023 04:28 AM

As stated in my post's title ...
 
Quote:

Originally Posted by NevemTeve (Post 6436782)
What is the goal? What do you wish to accomplish with this code?

Want to not only pass two different arrays, using void pointer, but also want to access the contents of the two arrays, in the common function, to which these two arrays are
passed in successive invocations.

ajiten 06-16-2023 04:31 AM

Quote:

Originally Posted by pan64 (Post 6436783)
what do you want to print?
The pointer itself? printf("%p \n", p)
The integer? printf("%i \n", *(int *)p)
or ?

The contents of both the arrays, need be accessed, using a common function (here foo()), irrespective of the data type of the arrays passed; using just a void pointer.
If try to run with the simple modification, of having an integer specifier, for the output; still get the same error; apart from the usual issue of having another array (char), to be passed too, to the same function.

ajiten 06-16-2023 04:48 AM

Hope would get some help soon.

NevemTeve 06-16-2023 06:37 AM

There are not much of things you can do with a piece of data without knowing its type. Printing hexdump might be an option.
Code:

#include <stdio.h>

void hexdump(unsigned len, const void *p)
{
    const unsigned char *q= p;
    const unsigned char *qlim= q + len;

    for (q= p; q < qlim; ++q) {
        printf ("%02x", *q);
    }
    fputc('\n', stdout);
}

int main()
{
    int x[10] = {1,2,3,4,5,6,7,8,9,10};
    char c[5] = "ABCDE";

    hexdump(sizeof x, x);
    hexdump(sizeof c, c);

    return 0;
}


ajiten 06-16-2023 06:55 AM

Quote:

Originally Posted by NevemTeve (Post 6436804)
There are not much of things you can do with a piece of data without knowing its type. Printing hexdump might be an option.
Code:

#include <stdio.h>

void hexdump(unsigned len, const void *p)
{
    const unsigned char *q= p;
    const unsigned char *qlim= q + len;

    for (q= p; q < qlim; ++q) {
        printf ("%02x", *q);
    }
    fputc('\n', stdout);
}

int main()
{
    int x[10] = {1,2,3,4,5,6,7,8,9,10};
    char c[5] = "ABCDE";

    hexdump(sizeof x, x);
    hexdump(sizeof c, c);

    return 0;
}


Please state how to directly access the contents of the array, using the void pointer.

Though have understood that cannot use one function, to access two different types of arrays, as the output specifier would differ then; and the contents' data type can not be stated beforehand.

But, to get this information, am not clear how you intend to use hexdump().

On Cygwin, it prints:
Code:

0100000002000000030000000400000005000000060000000700000008000000090000000a000000
4142434445

The output is unclear to me, as what is being printed, and also how it helps.

Also, am not clear as to why fputc() prints a single character of newline to the stdout (default file descriptor), even if multiple characters are used instead of just: '\n'?

NevemTeve 06-16-2023 07:32 AM

Never mind, here is the fixed version of your original program:
Code:

#include <stdio.h>

void foo(int type, unsigned n, void *p)
{
    if (type=='C') {
        for (unsigned i=0; i<n; ++i) {
            printf("%d: '%c'\n", i, ((char *)p)[i]);
        }
    } else if (type=='I') {
        for (unsigned i=0; i<n; ++i) {
            printf("%d: %d\n", i, ((int *)p)[i]);
        }
    }
}

int main()
{
    int x[10] = {1,2,3,4,5,6,7,8,9,10};
    char c[5] = "ABCDE";

    foo('I', 10, &x);
    foo('C',  5, &c);
    return 0;
}


ajiten 06-16-2023 08:53 AM

Quote:

Originally Posted by NevemTeve (Post 6436809)
Never mind, here is the fixed version of your original program:
Code:

#include <stdio.h>

void foo(int type, unsigned n, void *p)
{
    if (type=='C') {
        for (unsigned i=0; i<n; ++i) {
            printf("%d: '%c'\n", i, ((char *)p)[i]);
        }
    } else if (type=='I') {
        for (unsigned i=0; i<n; ++i) {
            printf("%d: %d\n", i, ((int *)p)[i]);
        }
    }
}

int main()
{
    int x[10] = {1,2,3,4,5,6,7,8,9,10};
    char c[5] = "ABCDE";

    foo('I', 10, &x);
    foo('C',  5, &c);
    return 0;
}


Thanks for introducing to many new rules, in C; say the type of character variables is denoted by 'C', and that of integer variable is denoted by 'I'.
Seems never read this aspect of the C language before.

There were some inadverent typos, after the removal of which, the code is:

Code:

#include <stdio.h>

void foo(int type, unsigned n, void *p)
{
        if (type=='C'){
                for (unsigned i=0; i<n; ++i){
                        printf("%d: '%c'\n", i, *(char *)(p+i));
                }
        } else if (type=='I'){
                for (unsigned i=0; i<n; ++i){
                        printf("%d: %d\n", i, *(int *)(p+i));
                }
        }
}

int main()
{
        int x[10] = {1,2,34,5,6,7,8,9,10};
        char c[5]= "ABCDE";

        foo('I', 10, &x);
        foo('C', 5, &c);
        return 0;
}

-----

Though still can't understand why the output is like that, as shown below:
Code:


User@DESKTOP-OKV7A0Q ~
$ ./f1
0: 1
1: 33554432
2: 131072
3: 512
4: 2
5: 570425344
6: 2228224
7: 8704
8: 34
9: 83886080
0: 'A'
1: 'B'
2: 'C'
3: 'D'
4: 'E'

=============

The reason for choosing the expression of: *(char *)(p+i), or: *(int *)(p+i), was that the alternative forms of: *(char *)p[i], and *(int *)p[i], did not work; as gave error:
Code:

$ cc f1.c -o f1
f1.c: In function ‘foo’:
f1.c:7:59: warning: dereferencing ‘void *’ pointer
    7 |                        printf("%d: '%c'\n", i, *(char *)p[i]);
      |                                                          ^
f1.c:7:50: error: invalid use of void expression
    7 |                        printf("%d: '%c'\n", i, *(char *)p[i]);
      |                                                  ^
f1.c:11:56: warning: dereferencing ‘void *’ pointer
  11 |                        printf("%d: %d\n", i, *(int *)p[i]);
      |                                                        ^
f1.c:11:48: error: invalid use of void expression
  11 |                        printf("%d: %d\n", i, *(int *)p[i]);
      |                                                ^

===============================

Error #2: By your original code, after removing just the typos:
Code:

#include <stdio.h>

void foo(int type, unsigned n, void *p)
{
    if (type=='C') {
        for (unsigned i=0; i<n; ++i) {
            printf("%d: '%c'\n", i, ((char *)p)[i]);
        }
    } else if (type=='I') {
        for (unsigned i=0; i<n; ++i) {
            printf("%d: %d\n", i, ((int *)p)[i]);
        }
    }
}

int main()
{
    int x[10] = {1,2,3,4,5,6,7,8,9,10};
    char c[5] = "ABCDE";

    foo('I', 10, &x);
    foo('C',  5, &c);
    return 0;
}

Output:

Code:

$ cc f2.c -o f2
f2.c: In function ‘foo’:
f2.c:7:58: warning: dereferencing ‘void *’ pointer
    7 |                        printf("%d: '%c'\n", i, (char *)p[i]);
      |                                                          ^
f2.c:7:49: error: invalid use of void expression
    7 |                        printf("%d: '%c'\n", i, (char *)p[i]);
      |                                                ^
f2.c:11:55: warning: dereferencing ‘void *’ pointer
  11 |                        printf("%d: %d\n", i, (int *)p[i]);
      |                                                      ^
f2.c:11:47: error: invalid use of void expression
  11 |                        printf("%d: %d\n", i, (int *)p[i]);
      |                                              ^


astrogeek 06-16-2023 11:17 AM

Quote:

Originally Posted by ajiten (Post 6436834)
Thanks for introducing to many new rules, in C; say the type of character variables is denoted by 'C', and that of integer variable is denoted by 'I'.
Seems never read this aspect of the C language before.

That isn't an aspect of the language, it is simply passing additional arguments into the function to tell it the type and size of the array.
Quote:

Originally Posted by ajiten (Post 6436834)
There were some inadverent typos, after the removal of which, the code is:

Code:

#include <stdio.h>

void foo(int type, unsigned n, void *p)
{
        if (type=='C'){
                for (unsigned i=0; i<n; ++i){
                        printf("%d: '%c'\n", i, *(char *)(p+i));
                }
        } else if (type=='I'){
                for (unsigned i=0; i<n; ++i){
                        printf("%d: %d\n", i, *(int *)(p+i));
                }
        }
}

int main()
{
        int x[10] = {1,2,34,5,6,7,8,9,10};
        char c[5]= "ABCDE";

        foo('I', 10, &x);
        foo('C', 5, &c);
        return 0;
}


That does not produce the desired output because your pointer arithmetic is not correct.

Also, there is no need to pass the address of the array variables to make them a pointer as they are already simply pointers to the base of the arrays.

Try this:

Code:

#include <stdio.h>

void foo(int type, unsigned n, void *p)
{
    if (type=='C') {
        for (unsigned i=0; i<n; ++i) {
            printf("%d: '%c'\n", i, *((char *)(p)+i));
        }
    } else if (type=='I') {
        for (unsigned i=0; i<n; ++i) {
            printf("%d: %d\n", i, *((int *)(p)+i));
        }
    }
}

int main()
{
    int x[10] = {1,2,3,4,5,6,7,8,9,10};
    char c[5] = "ABCDE";

    foo('I', 10, x);
    foo('C',  5, c);
    return 0;
}

The difference in the pointer arithmetic is that your version:

Code:

printf("%d: %d\n", i, *(int *)(p+i));
...performs the addition before the pointer p has been cast to type, so the result is not an incremented pointer to type, but just a number.

This one:

Code:

printf("%d: %d\n", i, *((int *)(p)+i));
... first casts the pointer to its type, then performs the addition which produces a valid pointer to the type.

You could do it with less parenthesis, but I tend to use them when needed to make things clear to myself! This also works for the same reason given...

Code:

printf("%d: %d\n", i, *(int *)p+i);

NevemTeve 06-16-2023 11:19 AM

@OP Make sure to achieve warning-less compilation (use options -pedantic -W -Wall -Werror); you can access the array elements this way:
((int *)p)[i] or *((int *)p + i), ((char *)p)[i] or *((char *)p + i)

dugan 06-16-2023 06:57 PM

Quote:

Originally Posted by ajiten (Post 6436769)
Code:

char c[5] = "ABCDE";

This mistake leapt out at me. "ABCDE" actually 6 characters long, because there's a terminating null character. Also, string constants are read-only, and you don't want to point a non-const char to it. There are other problems, and I assume that the compiler warnings would have flagged them.

The usual idiom for a string constant is this. It will work for what you're doing.
Code:

const char* c = "ABCDE";
If you need to modify the string, then you need to do this.

Code:

char c[6];
strcpy(c, "ABCDE");


astrogeek 06-16-2023 07:28 PM

Quote:

Originally Posted by dugan (Post 6436934)
This mistake leapt out at me. "ABCDE" actually 6 characters long, because there's a terminating null character.

Indeed! I saw that then forgot about it before I posted. Short term memory is not what it used to be!

ajiten 06-16-2023 11:56 PM

Quote:

Originally Posted by NevemTeve (Post 6436869)
@OP Make sure to achieve warning-less compilation (use options -pedantic -W -Wall -Werror); you can access the array elements this way:
((int *)p)[i] or *((int *)p + i), ((char *)p)[i] or *((char *)p + i)

Kindly elaborate as giving on google: "-pedantic -W -Wall -Werror" fetched nothing at all. Also, not fetched anything relevant with the statement of: 'warning-less compilation C compiler -pedantic -W -Wall -Werror'. So, any literature search is not possible, not even with googlebooks.

Though compilation was done successfully, with the command:
Code:

$ cc -pedantic -W -Wall -Werror f2.c -o f2


All times are GMT -5. The time now is 11:45 PM.