Перенос значений из указателя void

#c #pointers #char #void #memcpy

#c #указатели #символ #пустота #memcpy

Вопрос:

Может кто-нибудь сказать мне, что не так с этим кодом?

base является указателем void на набор floats
i является значением >1
size , является размером типа (в данном случае float 4 )

 char *a = (char *)base;
char *temp = (char *)a   size * (i/2);
printf("%d: %d = ", i, temp);
memcpy(a   size * i , temp , size);
printf("%dn", a   size * i);
  

Это вывод:

2: 136724 = 136728
3: 136724 = 136732
4: 136728 = 136736
6: 136732 = 136744
7: 136732 = 136748
8: 136736 = 136752

Комментарии:

1. Я не верю, что этот код имеет такой результат. Если a это действительно void* , то a size * i недопустимо, потому что вы не можете выполнить арифметику с указателем void.

2. Что заставляет вас думать, что с этим что-то не так? Какой результат вы ожидали вместо этого? Может быть, вы имели в виду разыменование некоторых из этих указателей, чтобы напечатать значения, на которые они указывают? Вы просто печатаете адреса, которые они хранят, что не очень интересно.

3. Упс. Base — это указатель void, а a — указатель char. Код обновлен. Как я могу распечатать значения?

4. @Kamran224: О каких «значениях» ты говоришь?

5. a[i]=a[i/2]; Как я могу добиться этого, используя указатели? Я родом из c / java

Ответ №1:

Если бы a было void* , компилятор не позволил бы вам писать a size*i (вы не можете выполнять арифметику указателей с неполными типами). Вероятно, тип не такой, как вы думаете.

Но почему вы думаете, что есть проблема? Левый столбец продвигается вдвое быстрее, чем правый, и это ожидаемо, потому что вы делите на 2.

Вы же понимаете, что печатаете адреса, а не копируемые значения, верно?

Ответ №2:

 char *a = (char *)base;
char *temp = (char *)a   size * (i/2);
printf("%d: %f = ", i, *(float *)temp);
memcpy(a   size * i , temp , size);
printf("%fn", *(float *)(a   size * i));
  

Изменения, которые я внес, заключаются в правильном разыменовании указателей (и приведении их к правильному типу) и изменении %d на %f, поскольку вы указали, что base представляет собой массив с плавающими значениями. %d — для целых чисел, а %f — для чисел с плавающей запятой.

Причина, по которой ваш код не работал, заключается в том, что вы печатали адреса, а не значения.

Ответ №3:

Не могли бы вы, пожалуйста, рассказать нам, чего вы пытаетесь достичь? Похоже на домашнюю задачу, верно?

Язык C позволяет вам привести любой указатель к void*, а затем привести его обратно к исходному типу указателя без потери какой-либо информации. Все остальное, что вы делаете с указателем void, является плохой идеей, хотя некоторые библиотечные функции (такие как memcpy) по историческим причинам все еще имеют void * . Вот почему вам также не нужно явное приведение, чтобы перейти от любого типа указателя к void *.

Вы не можете посмотреть, на что указывает void *, пока не приведете его обратно к правильному типу указателя. И будьте осторожны при этом!

 #include <stdio.h>
#include <memory.h>

/* It's a bad idea to pass Base as a void pointer,
   but that's what you said you have. */
void silly_function(void*base, int i, int size) {
    /* Using a char* that points to float, is an even worse idea!
        char *a = (char *)base;
        char *temp = (char *)a   size * (i/2);
        printf("%d: %d = ", i, temp);
        memcpy(a   size * i , temp , size);
        printf("%dn", a   size * i); 
    **/

    /** Probably ought to have a big SWITCH statement here, based
        on the data type. sizeof() isn't a good way to do this...
        On many computers, sizeof(float)==sizeof(long), but that
        doesn't mean that a float* is the same as a long* !!!
        For now, I'm going to assume (as you did) that base points
        to an array of float. */

    /* I think you're trying to copy the first half of the array
       into the second half of the array! But that's easy. */
    float*firsthalf = (float*)base; 
    float*secondhalf = firsthalf   (i/2);

    /* Show some starting values. */
    printf("Before: %x --> %f, %x --> %fn",
        firsthalf, *firsthalf, secondhalf, *secondhalf);

    /* Now do the copy */
    memcpy(secondhalf, firsthalf, (i/2)*(sizeof(float)));

    /* Now prove that it's been copied? */
    printf("After:  %x --> %f, %x --> %fn",
        firsthalf, *firsthalf, secondhalf, *secondhalf);
}

int main() {
    /* This drives the test */
    float ary[10] = {
        1.1f, 2.2f, 3.3f, 4.4f, 5.5f,
        0.0f, 0.0f, 0.0f, 0.0f, 0.0f };
    silly_function(ary, 10, sizeof(ary[0]));
    return 0;
}
  

В моей системе вывод является

 Before: 12ff38 --> 1.100000, 12ff4c --> 0.000000
After:  12ff38 --> 1.100000, 12ff4c --> 1.100000
  

Я надеюсь, что это поможет.

Комментарии:

1. В стандарте C нет такого понятия, как memory.h.