Некоторое недопонимание о приведении в обобщенной функции

У меня есть некоторое недопонимание учебника из моего класса. Есть функция называется print_Arr(), это универсальная функция, которая получает указатель на массивы двойных или целых чисел и печатает его.

Вот код:

int  main() {
    int  a[] = { 2,7,6,4,1 };
    double b[] = { 12.5,2.7,3.0,5.5,5.9,1.0 };

    print_Arr(a, sizeof(a)/sizeof(a[0]), sizeof(int), print_int);
    print_Arr(b, sizeof(b)/sizeof(b[0]), sizeof(double), print_double);
}

void print_Arr(void* a, int size, int m, void (*print_func)(void* )) {

    for (int i = 0; i <= size-1; i++)
    {
        print_func((char*)a + m*i);
    }
}

void print_int(int* p) {

    printf("%d\n", *p);
}

void print_double(double* num) {

    printf("%f\n", *num);
}

Почему я должен сделать бросок a в (char*) в этом ряду:

print_func((char*)a + m*i);

Я отправил print_Arr() универсальная функция двух типов массивов целых или двойных, таким образом, это логически привести a в int * или double*,

Но почему это приведено к char*? Что мне не хватает?

4 ответа

Сначала слово о том, зачем нужен актерский состав:

Арифметика указателя использует размер типа, на который указывает. void является вечно неполным типом, который не может быть завершен, поэтому арифметика указателя невозможна для указателя на void тип.

Чтобы добавить, для аддитивных операторов, цитирование из C11глава §6.5.6, ограничения:

Кроме того, либо оба операнда должны иметь арифметический тип, либо один операнд должен быть указателем на полный тип объекта, а другой должен иметь целочисленный тип.

и из главы §6.2.5,

void тип содержит пустой набор значений; это неполный тип объекта, который не может быть завершен.


Тем не менее, почему актеры должны char*:

Арифметика указателя использует тип, на который указывает. Цитирую спецификацию еще раз

[...] если выражение P указывает на iэлемент массива, выражения (P)+N (То же самое, N+(P)) а также (P)-N (где N имеет значение n) указывают, соответственно, на i+nи i−n-ые элементы объекта массива, если они существуют.

Вот, посмотрите на вашу конструкцию:

      ((char*)a + m*i);

где m это размер фактического типа объекта, на который указывает фактический аргумент. Таким образом, если вы приведете указатель к фактическому типу, вычисление будет неверным. Чтобы представить сравнение, скажите:

  • sizeof (char) 1, обязательный стандарт.
  • sizeof (int) == 4, скажем, в вашей платформе.

Итак, для массива int arr[ ] = {1, 2, 3, 4}Выражения

  • (char*)a + (sizeof(int)*1)а также
  • (int*) a + 1

эквивалентны.

Наконец, касаясь темы преобразования другого типа указателя в char* и доступ к нему:

[...] Когда указатель на объект преобразуется в указатель на тип символа, результат указывает на младший адресуемый байт объекта. Последовательные приращения результата, вплоть до размера объекта, дают указатели на оставшиеся байты объекта. [....]

Вам нужно char * приведение, потому что вы делаете арифметику указателя на указателе, чтобы получить смещение в байтах с начала, но вы не можете сделать это на void *,

Пустой указатель не имеет размера шрифта, поэтому вы не можете рассчитать с ним.

    public:

       int num=0;

       int c;
    int doubleToChar(double a){
       while ((a-1)>=0){
        num++;

       }
       c=a;
       return a*10;

    }/*    int doubleToCharhundred(double a){
       while ((a-1)>=0){
        num++;

       }

       return a*100-c;

    }*/
    double a=12.12345;
    char *tenDivide ;
    char *intPart;
    //u can add hundred or thousand by another char;
    tenDivide =doubleToChar(a);
    if(num<128)
      intPart=num; 
    else{
      while(num-1){
           //same  doubleToChar
       }
    }
Другие вопросы по тегам