Assign and dereference void * to an array pointer in C - c

I have a pointer to array of fixed size integer elements. After populating that array, I assigned it to void *pBuff. Later on, I need to access array elements through void pointer which I failed in doing so.
Here is the code using C:
void * pBuff = NULL;
int
set_data(void *pBuff)
{
int ptr = 10, i;
int phy_bn[8] = {0};
int (*pPB)[8];
for(i=0; i<8; i++){
phy_bn[i] = ptr;
}
pPB = &phy_bn;
pBuff = pPB;
return 0;
}
int main()
{
int i;
set_data(&pBuff);
for(i =0 ; i <8; i++){
printf("\ndata : %d\n", *(int *)pBuff[i]);
}
return 0;
}
It prompts an error cast of 'void' term to non-'void' against *(int *)pBuff[i].
Any help will be really appreciated.
Thanks,
-Sam

Apart from the fact that you need to use:
((int*)pBuff)[i]
What you have in your code is Undefined Behavior.
pBuff = pPB;
pBuff points to a array which is local to the function and its lifetime does not exist beyond the function scope. So you have a pointer pointing to something that does not need to exist but may seemingly exist sometimes.

You should probably dereference with * or [], not both at the same time :-)
If your intent is to get the integer at that i position of a void pointer which points to ints, use:
((int*)pBuff)[i]
The ((int*)pBuff) turns pBuff into a pointer to an integer and the [i] following that grabs the i'th integer at that location.
So your loop would be:
for (i = 0 ; i < 8; i++)
printf ("\ndata : %d\n", ((int*)pBuff)[i]);
Another thing you should probably watch out for is returning pointer to stack-based variables. Those variables disappear when the function exits at which point dereferencing pointers to them is undefined behaviour.

pBuff[i] is illegal, since pBuff is a void*. It's a matter of operator precedence:
((int *)pBuff)[i]
You don't need to dereference pBuff again with the first * because [i] already does that.

It should be
void * pBuff = NULL;
int
set_data(void *pBuff)
{
int ptr = 10, i;
int *phy_bn = (int*)malloc(sizeof(int)*8);
//this is needed so that it is valid for pBuff to point phy_bn even if it is getting out of scope
for(i=0; i<8; i++){
phy_bn[i] = ptr;
}
pBuff = phy_bn;
return 0;
}
int main()
{
int i;
set_data(&pBuff);
for(i =0 ; i <8; i++){
printf("\ndata : %d\n", ((int*)pBuff)[i]);
}
return 0;
}

Related

Understanding why it does not find duplicates in array

I wrote the following function in C:
int last(long arr[], int length) {
for (int i = 0; i < length-1; i++)
if (*(arr+i) == *(arr + length - 1))
return 1;
return 0;
}
it checks if the last value of the array was used more than once. In the main:
int *arr = malloc(length*sizeof(int));
for (int i = 0; i < length; i++)
scanf("%d", ++arr);
printf(last((long *) arr, length);
For some reason for the array [1,2,2,3] it returns that the last element was used multiple times and I'm not sure why. I think that is because of scanf("%d", ++arr); but I don't know how to fix it.
My goal is that it will return 1 for [1,3,2,3] and 0 for [1,2,2,3]. What could be the problem?
You should use scanf("%d", &arr[i]);. Using ++arr causes the array to be incremented before you pass it to last, and also reads into data beyond arr, which is undefined behavior.
Another one of the issues in this is the cast to long *.
You should use %ld in scanf and long *arr = malloc(length*sizeof(*arr));.
Also make sure to check for NULL. You never know when malloc is going to fail or someone's going to pass bad data.
Full example:
#include <stdio.h>
#include <stdlib.h>
int last(long arr[], int length) {
if(!arr) return -1;
for (int i = 0; i < length-1; i++)
{
if (arr[i] == arr[length-1])
return 1;
}
return 0;
}
int main(void)
{
long *arr = malloc(4*sizeof(*arr));
if(!arr) return 1;
for (int i = 0; i < 4; i++)
scanf("%ld", &arr[i]);
printf("%d\n", last(arr, 4));
}
Several problems in your code:
Look at this statement:
scanf("%d", ++arr);
^^^^^
In the last iteration of loop, the pointer arr will be pointing to one element past end of array arr (due to pre-increment) and it is is passed to scanf(). The scanf() will access the memory location pointed by the pointer which is an invalid memory because your program does not own it. This is undefined behavior. Note that a pointer may point to one element past the end of array, this is as per standard but dereferencing such pointer will lead to undefined behavior.
Once the main() function for loop finishes the arr pointer pointing to location past the end of memory allocated to arr and just after this you are passing arr to last() function. So, you are passing an invalid memory reference to last() function and then accessing that memory in last() function - one more undefined behavior in your program.
Probably you should take another pointer and point it to arr, so that arr keep pointing to allcoated memory reference returned by malloc().
Note that if you want to read the input the way you are doing then use the post-increment operator in scanf(), like this:
int *arr = malloc(length*sizeof(int));
if (arr == NULL)
exit(EXIT_FAILURE);
int *ptr = arr;
for (int i = 0; i < length; i++)
scanf("%d", ptr++);
but the more appropriate and readable way is - scanf("%d", &arr[i]).
Another big problem in your code is accessing the int values as long type.
The last() function parameter arr type is long and you are passing it int pointer typecasted to long *.
Note that the size of long and int may be different based on the platform. You cannot assume them to be of same size on all platforms.
Assume the case where int size is 4 bytes and long size is 8 bytes.
In this case, when accessing an int pointer using long type pointer then every object will be considered as 8 byte long and when you do arr+1 in last(), the pointer will be advance by 8 bytes and you will never get correct result.
Compiler must be throwing warning message on this statement:
printf(last((long *) arr, length);
because the printf() expects first argument as const char * and you are passing it int (return type of last()). You should give the first argument to printf() a string which contains appropriate format specifier('s).
Putting these altogether:
#include <stdio.h>
#include <stdlib.h>
int last(int arr[], int length) {
if (arr == NULL) {
return 1;
}
for (int i = 0; i < length - 1; i++) {
if (arr[i] == arr[length - 1]) {
return 1;
}
}
return 0;
}
int main(void) {
int length = 4;
int *arr = malloc (length * sizeof (*arr));
if (arr == NULL) {
exit(EXIT_FAILURE);
}
printf ("Enter %d numbers:\n", length);
for (int i = 0; i < length; i++) {
scanf ("%d", &arr[i]);
}
printf ("Duplicate found: %s\n", last (arr, length) == 1 ? "Yes" : "No");
return 0;
}

pointer arithmetic with pointer to array

I'm trying to do pointer arithmetic with a pointer to array, but I get a wrong value since I can't dereference the pointer properly.
Here is the code:
#include "stdlib.h"
#include "stdio.h"
int main()
{
int a[] = {10, 12, 34};
for (int i = 0; i < 3; ++i)
{
printf("%d", a[i]);
}
printf("\n");
int (*b)[3] = &a;
for (int i = 0; i < 3; ++i)
{
printf("%d", *(b++));
}
printf("\n");
return 0;
}
In the second for I can't get to print the correct value.
It doesn't work even if I write
printf("%d", *b[i]);
I'd like to see how to print correctly using the b++ and the b[i] syntax.
The following should work:
printf("%d\n", *( *b+i ));
// * b + i will give you each consecutive address starting at address of the first element a[0].
// The outer '*' will give you the value at that location.
instead of:
printf("%d", *(b++));
You have declared b to be a pointer to arrays of 3 integers and you have initialized it with address of a.
int (*b)[3] = &a;
In the first loop you will print the first element of a array but then you will move 3*sizeof(int) and trigger undefined behavior trying to print whatever there is.
To print it correctly:
int *b = a;
// int *b = &a[0]; // same thing
// int *b = (int*)&a; // same thing, &a[0] and &a both points to same address,
// though they are of different types: int* and int(*)[3]
// ...so incrementing they directly would be incorrect,
// but we take addresses as int*
for (int i = 0; i < 3; ++i)
{
printf("%d", (*b++));
}
gcc will complain about the formatting in the second for loop: it will tell you format specifies type 'int' but the argument has type 'int *
your assignment of a to b should look like this:
int *b = a

returning 2D array having error, need concept

I tried different methods but eventually got errors. Please give a solution and a brief explanation of the concept.
uint8_t **subBytes()
{
int i,j;
uint8_t r,c;
uint8_t t[4][4];
for(i=0;i<4;i++)
{
for (j=0;j<4;j++)
{
r = pt[p1][j] & 0xf0;
r = r >> 4;
c = pt[p1][j] & 0x0f;
t[i][j] = (uint8_t *) malloc(sizeof(uint8_t));
t[i][j] = sBox[r][c];
}
p1++;
}
return t;
}
int main()
{
uint8_t **temp;
temp = subBytes();
for(i=0;i<4;i++)
{
for(j=0;j<4;j++)
{
printf("%x ", temp[i][j]);
}
printf("\n");
}
}
This is my original code. Here, I used malloc, but then too it is not working.
the memory space alloced for your matrix is a LOCAL VARIABLE.
The scope of a LOCAL VARIABLE is only within that function.
When you returned it is discarded.
In your code it is uint8_t t[4][4].
t is discarded right after return t.
So you return nothing and may cause undefined behavior.
You should use malloc to alloc memory for your matrix not just declare it locally.
in code
uint8_t **t.
t = malloc(sizeof(uint8_t) * 16 ) //size of a 4x4 matrix
then use t as a two dimension array and return t.like
t[0][0] = 1;
don't forgot to free it after use it out side of the function.
free(t);
m is LOCAL VARIABLES. When add returns, m is DESTROYED!
You SHOULD NOT return the pointer or reference of local variables. Look the following code:
int foo() { return 1; }
int *bar() { int i = 1; return &i; }
When I call foo(), it returns 1.
When I call bar(), it try to return the local variables, i's address. But when bar() returns, the i variable is DESTROYED! So the return pointer become trash pointer. (Sorry, I don't know how to say that term in English;)
You should use like that:
void bar(int *ret) { *ret = 1; }
int i;
bar(&i); /* now i is 1 */
or
int *bar()
{
int *p = (int *)malloc(sizeof(int));
*p = 1;
return p;
}
int *pi = bar();
/* now *pi is 1 */
...
free(pi); /* You MUST free pi. If not, memory lack is coming~ */
(I recommend first one. the second one require free and it can be mistaken.)
When a variable is declared (statically allocated) within a function, it is placed on what is called the stack, which is only local to that function. When the program leaves that function's scope, the variable is no longer guaranteed to be preserved, and so the pointer you return to it is essentially useless.
You have three options to fix your error:
Don't do it
Simply declare the array in the same function as you use it, don't bother with trying to return a pointer from another function.
Pass a pointer to a variable local to main
A pointer to a variable local to main will be valid until main returns, so you could do this:
void subBytes(uint8_t t[4][4]){
//perform initialization of matrix on passed variable
}
int main(){
uint8_t temp[4][4];
subBytes(&temp);
//...
}
Dynamic Allocation
This will probably give you more errors than it will solve in this case, but if you are heartset on returning a pointer to a matrix, you could malloc() the memory for the array and then return it, but you would have to free() it afterwards.
In C, there are several ways to dynamically allocate a 2D array. The first is to create it as a single array, and operate on the indices to treat it as 2D.
//...
int *arr = (int *)malloc(rows*cols*sizeof(int));
for (int i = 0; i<rows; i++){
for (int j = 0; j<height; j++){
arr[i*height + j] = i*j; //whatever
}
}
return arr; // type is int *
//...
Note that in this method, you cannot use array[i][j] syntax, because the compiler doesn't know the width and height.
The second way is to treat it as an array of arrays, so store an array of pointers to other arrays.
//...
int **arr = (int **)malloc(rows*sizeof(int *));
for (int i = 0; i<rows; i++){
arr[i] = (int *)malloc(cols*sizeof(int));
}
arr[i][j] = 86; //whatever
return arr; //type is int **
//...
For further information, see: Pointer to Local Variable

Why Does This Kind of Pointer Arithmetic Work In A Function, But Not In Main?

Here is my code that works. The function initializes the array, a, to values 0 - 3
int main(void)
{
int a[4];
pointer(a);
return 0;
}
void pointer(int* a)
{
int *p, i;
p = a;
for(i = 0; i < 4; i++)
{
*a++ = i;
printf(" %d", p[i]);
}
}
But when I combine it all into main(), it no longer works.
int main(void)
{
int a[4], *p, i;
p = a;
for(i = 0; i < 4; i++)
{
*a++ = i;
printf("%d", p[i]);
}
return 0;
}
Instead, it prints out memory addresses or something. It works when I dynamically allocate a[], so I'm guessing it has something to do with the way a[] is managed in memory. Can someone tell me why the second main() doesn't work?
In the function pointer, the argument a is a pointer. But in main, a is an array, you can't modify an array name, so *a++ = i is invalid.
I can't even compile your code, and the error illustrates why:
$ gcc -o foo foo.c
./foo.c:9:11: error: cannot increment value of type 'int [4]'
*a++ = i;
~^
1 error generated.
You aren't actually using a pointer in your code at all. If you change it as follows, it works as you expect:
#include <stdio.h>
int main(void)
{
int a[4], i;
int* p = a;
for(i = 0; i < 4; i++)
{
*p++ = i;
printf("%d", a[i]);
}
return 0;
}
C arrays decay into pointers in some circunstances, but they aren't pointers. Use p instead of a.
It works when you dynamically allocate a because malloc() returns a pointer, not an array.
you should know the differences between array and pointer.I suggest .
In function,the array you put in will turn to pointer(point to first element of array),it's a variable of pointer,so you can do increasement,in main,a is a address of first element,it's constant,so you can't change.you should change pointer p.
In functions you'r passing the array address point to a pointer. and pointer is accessing each variable when u increment it. this is called a walking pointer.
but in case when u use it in main you'r assuming that array is a simple . Think of an array declared by compiler like
int *const array;
so when you try to increment it. it pops an error. so use one more Walking pointer inside
main so u traverse the array

Why am I getting segmentation fault for malloc() while using pointer to pointer?

I don't understand why this works:
void main() {
int * b;
b = (int *)malloc(sizeof(int));
*b = 1;
printf("*b = %d\n", *b);
}
while this does not (gets segmentation fault for the malloc()):
void main() {
int ** a;
int i;
for (i = 0; i<= 3; i++) {
a[i] = (int*)malloc(sizeof(int));
*(a[i]) = i;
printf("*a[%d] = %d\n", i, *(a[i]));
}
}
since I find a[i] is just like b in the first example.
BTW, a[i] is equal to *(a+i), right?
You need to allocate memory for a first, so that you can access its members as a[i].
So if you want to allocate for 4 int * do
a = malloc(sizeof(int *) * 4);
for (i = 0; i<= 3; i++) {
...
}
or define it as array of integer pointers as
int *a[4];
a is a 2 dimensional pointer, you have to allocate both dimension.
b is a 1 dimensional pointer, you have to allocate only one dimension and that's what you're doing with
b = (int *)malloc(sizeof(int));
So in order the second example to work you have to allocate the space for the pointer of pointer
void main() {
int ** a;
int i;
a = (int**)malloc(4*sizeof(int*));
for (i = 0; i<= 3; i++) {
a[i] = (int*)malloc(sizeof(int));
*(a[i]) = i;
printf("*a[%d] = %d\n", i, *(a[i]));
}
The allocated pointer is written to uninitialized memory (you never set a to anything), causing undefined behavior.
So no, it's not at all equivalent to the code in the first example.
You would need something like:
int **a;
a = malloc(3 * sizeof *a);
first, to make sure a holds something valid, then you can use indexing and assign to a[0].
Further, this:
a[i] = (int*)malloc(sizeof(int));
doesn't make any sense. It's assigning to a[i], an object of type int *, but allocating space for sizeof (int).
Finally, don't cast the return value of malloc() in C.
actually malloc it's not that trivial if you really want safe and portable, on linux for example malloc could return a positive response for a given request even if the actual memory it's not even really reserved for your program or the memory it's not writable.
For what I know both of your examples can potentially return a seg-fault or simply crash.
#ruppells-vulture I would argue that malloc is really portable and "safe" for this reasons.

Resources