简体   繁体   中英

C program printing garbage values

I am trying to create an array and assign values to it. While I am able to assign values correctly, I am unable to retrieve those values and I have no idea why.

Here is a part of the code snippet.

  void *arr = (void *)(malloc(sizeof(void *) * 5));
  int i = 0;
  for(i = 0; i < 5; i++) {
    *(int *)(arr+i) = initial[i];
    printf("Value of array: %d\n", *(int *)(arr+i));
  }
  for(i = 0; i < 5; i++) {
    printf("Pushing: %d\n", *(int *)(arr+i));
    DArray_push(result, (arr+i));
  }

The output of the program is

Value of array: 4
Value of array: 1
Value of array: 3
Value of array: 2
Value of array: 0
Pushing: 33751300
Pushing: 131841
Pushing: 515
Pushing: 2
Pushing: 0

Why is my program able to accept values correctly, but is printing out garbage values when I try to retrieve them later?

Turn warnings on. (arr+i) is not defined (you cannot add to a void pointer and you do the cast only after this addition). You see undefined behavior.

You further allocate things the size of a pointer but treat it as int (more undefined behavior).

Why not write:

  int *arr = malloc(sizeof(int) * 5);
  int i = 0;
  for(i = 0; i < 5; i++) {
    arr[i] = initial[i];
    printf("Value of array: %d\n", arr[i]);
  }
  for(i = 0; i < 5; i++) {
    printf("Pushing: %d\n", arr[i]);
  }
Pushing: 33751300 = 4 + 1 * 256 + 3 * 256 * 256 + 2 * 256 * 256 * 256
Pushing: 131841 = 1 + 3 * 256 + 2 * 256 * 256
Pushing: 515 = 3 + 2 * 256
Pushing: 2
Pushing: 0

That part is already wrong, but would on most 32 or 64 bit compilers still work: sizeof(void *) . Only because this this at least the size of an int on these platforms though.

*(int *)(arr+i)

This is the actual problem. This did not access the next integer, it accessed the next address addressable by a void pointer, which is typically a single byte. Accessing the next integer would had been equivalent to this:

*(int *)(arr + i*sizeof(int))

Or easier to read:

*( ((int *)arr) + i)

Remember, incrementing a pointer by an offset doesn't add to the raw memory address, but it depends on the pointer type.

The point here is the arithmetic of pointers. When we're adding a value by 1, it wouldn't be the same for different type pointers. So let's check an example:

(int  *)p + 1 // it's moving 4 bytes
(void *)p + 1 // it's moving 1 byte in my compiler, void * is a generic type

In your example we know we're working with integers, so we need to tell the compiler to convert the generic pointer to the appropriate type before we do any operations with.

Try to execute the following code to understand what I'm gonna talking about:

#include <stdio.h>
#include <stdlib.h>

void main() {
    int initial[] = {100, 101, 102, 103, 104};
    void *arr = (void *)(malloc(sizeof(void *) * 5));
    int i = 0;

    for (i = 0; i < 5; i++) {
        printf("%p\t%p\n", arr + i, ((int *)arr) + i);
    }

    for(i = 0; i < 5; i++) {
        *(((int *)arr)+i) = initial[i];
        printf("Value of array: %d\n", *(((int *)arr)+i));
    }

    for(i = 0; i < 5; i++) {
        printf("Pushing: %d\n", *(((int *)arr)+i));
    }
}

I found some resources to help:

https://www.cs.umd.edu/class/sum2003/cmsc311/Notes/BitOp/pointer.html

https://www.viva64.com/en/t/0005/

The thing is that you don't reset your arr pointer. Thus in your second loop you actually print the values after the initial array.

You need to create a variable to traverse your array.

void *p = arr;

And then use it to traverse the array. And again before the second loop.

Moreover, do not cast the return value of a malloc function call (even when you are casting it to a void pointer which is the actual return type of malloc).

EDIT: you actually don't change the value of arr. My bad.

First of all, the thing with casting malloc to void and using sizeof void is totally pointeless.

Assuming initial[] is another array, the fix would be:

#include <stdio.h>
#include <stdlib.h>

int initial[] = {10, 20, 30, 40, 50};

int main()
{
    //allocate memory for 5 integers
    int* arr = malloc(sizeof(int) * 5);

    //loop over and copy from inital to arr
    int i = 0;
    for(i = 0; i < 5; i++) {
        arr[i] = initial[i];
        printf("Value of array: %d\n", arr[i]);
    }

  //pointer to first element of arr
  int* arrPointer = arr;

  for(i = 0; i < 5; i++) {
    printf("Pushing: %d\n", *arrPointer);
    //DArray_push(result, (*arrPointer));
    //increment the arrPointer
    arrPointer++;
  }

  //reset pointer if needed later...
  arrPointer = arr;

    return 0;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM