-2

In order to understand how void pointer works, I wrote a piece of code to test it. However I got the segmentation fault during the runtime and had not clue how to deal with it. The key point here is that, the data are generated inside that function call. You don't know the datatype and how large is that void pointer should be allocated.

#include <iostream>
#include <vector>

int valueAssignment(void *ptr1, void *ptr2){
  std::vector<int> vi;
  std::vector<double> vb;
  int num = 10;

  for (size_t i = 0; i < num; i++) {
    vi.push_back((int)rand());
    vb.push_back((double)rand());
    std::cerr <<i<<": "<< vi[i] <<'\t'<<vb[i]<<'\n';
  }

  for (size_t i = 0; i < num; i++) ((int*)ptr1)[i] = vi[i];

  for (size_t i = 0; i < num; i++) ((double*) ptr2)[i] = vb[i];

  return num;
}

int main(int argc, char const *argv[]) {

  void * intPtr, *doublePtr;
  int size;

  size = valueAssignment(intPtr,doublePtr);

  std::cerr << "/* ------------------- */" << '\n';

  for (size_t i = 0; i < size; i++) {
    std::cout <<i<<": "<< ((int*)intPtr)[i]<<"," <<((double *)doublePtr)[i]<<std::endl;
  }

  return 0;
}
ccm
  • 25
  • 4
  • 7
    You need to make those pointers point to valid memory locations. – 001 Jul 30 '19 at 00:25
  • 3
    `size = valueAssignment(intPtr,doublePtr);` -- The `intPtr` and `doublePtr` are uninitialized, thus this could never work. – PaulMcKenzie Jul 30 '19 at 00:28
  • 2
    Before you try to find out about void pointers, practice with typed pointers, e.g. `int*` if you cannot use the straight forward pointers, your chances of getting void pointers right are small. They mostly are for "I actually know better" situations. – Yunnosch Jul 30 '19 at 00:28
  • If I comment for (size_t i = 0; i < num; i++) ((double*) ptr2)[i] = vb[i]; and corresponding ((double *)doublePtr)[i] at std::cout. It does work. – ccm Jul 30 '19 at 00:32
  • @chengcheng *It does work.* -- C++ has something called *undefined behavior*, and you have fallen victim to it. There is no guarantee as to what will happen when you dereference and access an uninitialized pointer. – PaulMcKenzie Jul 30 '19 at 00:34
  • @chengcheng It doesn't work but it also might fail to cause an obvious crash. Both pointers are **uninitialized** and dereferencing those pointers is a terrible bug that you must fix. – Blastfurnace Jul 30 '19 at 00:35
  • @PaulMcKenzie I've tried to put ptr1 = malloc(num*sizeof(int)); and ptr2 = malloc(num*sizeof(double)); before the for loop assignment. I still got segmentation fault. – ccm Jul 30 '19 at 00:36
  • @chengcheng Where is the segmentation fault? Outside of the `valueAssignment` function? If so, I already mentioned that those pointers are uninitialized before you called that function, and remain uninitialized after you left that function. It doesn't matter what you did *inside* that function -- it has no effect on the caller whatsoever. Also, don't put code in the comment section, as it becomes unreadable. – PaulMcKenzie Jul 30 '19 at 00:39
  • @PaulMcKenzie Yes, the segmentation fault is outside of that function call. You are saying, we have the allocate corresponding size before the function call? But question is, the data is generated inside the function, you don't the datatype and size until that function is been called. – ccm Jul 30 '19 at 00:43
  • A function that takes a pointer value **must** have those pointers initialized if that function is going to do anything with them that the caller will later on use. That's the bottom line. The only thing a function can do with those uninitialized pointers is testing them for `nullptr` -- and that's it -- nothing else. If you really wanted to change the pointer values and have the changes reflect back to the caller, then the function signature needs to change to pass a *reference* to the pointers, not just pointers, i.e `valueAssignment(void *& ptr1, void *& ptr2);` – PaulMcKenzie Jul 30 '19 at 00:47
  • 1
    [Possible duplicate](https://stackoverflow.com/questions/22374524/what-is-a-reference-to-pointer) – PaulMcKenzie Jul 30 '19 at 00:51
  • @PaulMcKenzie I see, the pass by reference is the way to go. Thank you very much. – ccm Jul 30 '19 at 00:51
  • 1
    "In order to understand how void pointer works..." You probably should read a [good book](https://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list). – Eljay Jul 30 '19 at 01:17

1 Answers1

0

We should simply follow the many many recommendations given by experts.

  1. Do not use raw pointers in C++
  2. Do not use raw pointers in C++
  3. Do not use raw pointers in C++

WIth that we woulld already make a huge progress. But then, you want to learn about a void* pointer. The void pointer is a somehow generic pointer that can point to anything. You can also assign other pointer types to a void pointer. Vice versa this is not possible and you need an explicit type cast.

With classes and espcially derived classes you may even lose information by doing such casts.

Legacy C codes often uses void pointers, but that is basically no problem.

In modern C++, void pointers are rarely needed. Maybe mainly to interface with legacy code.

So, now to your special case:

The problem has been mentioned already in many comments. And this has nothing to do with void pointers, but pointers in general. Your pointers are not initialized. They point to somewhere, randomly at some point in memory. And in your subfunction, you are assigning values to those none initalized pointers, writing values to somewhere randomly in memory. Your program will chrash.

So, a pointer needs to point to somewhere defined. To a defined memory region.

You could have written:

    int intArray10[10];        // You should not use C-Style plain arrays
    double doubleArray10[10];  // You should not use C-Style plain arrays

    void* intPtr = intArray10;
    void* doublePtr = doubleArray10;

Then your pointer would point to a defined region. And you program would work.

But then you want to define or use somehow the pointer within your function. If the size is known, then you can allocate data with new and assign it to the pointer. The pointer must then be passed as "reference to pointer" or "pointer to pointer". If the size is unknown, it will be more difficult, you need to inform the calling program on the size.

All this is very error prone and should be avoided.

So again: Do not use raw pointer. If you really need them for some ressource management, then use std::unique_ptr or std::shared_ptr.

Or better use STL container in the first place.

A M
  • 14,694
  • 5
  • 19
  • 44