#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.