Как использовать другой тип указателя с тем же именем? - PullRequest
0 голосов
/ 21 января 2019

У меня проблема с уменьшением количества for -циклов. Они делают то же самое для разных типов.

Должен ли я использовать пустые указатели или что-то еще.

Можно ли уменьшить количество кода?

  void smt(int nb, int iform, void *ptr)//example function
  {
      int *ipt;// pointers definitions
      float *fpt;
      double *dpt;
      if( iform == 1 )
      {
          ipt = (int *) ptr;
          for( int i = 0; i < nb; i++ )
              ipt[i]=i;
      }
      else if( iform == 2)
      {
          fpt  = (float *)ptr;
          for( int i = 0; i < nb; i++)
              fpt[i] = 2.71;
      }
      else
      {
          dpt = (double *)ptr;
          for( int i = 0; i < nb; i++)
              dpt[i] = i*3.14159;
      }
   } 
   int main(void)
   {
       int nb = 5;
       float iform = 2;
       float *a = malloc(nb*sizeof(float)); //allocate memory 
       float *fpt;
       //there should be double *dpt and so on  
       smt(nb, iform, a );
       if( iform == 1)
       {
           for( int i = 0; i < nb; i++)
               printf("a = %d\n", a[i]);
       }
       else if( iform  == 2)
       {
           for( int i = 0; i < nb; i++)
               printf("a = %f\n", a[i]);
       }
       else
       {
           for( int i = 0; i < nb; i++)
               printf("a = %f\n", a[i]);
       }            
            return 0;
   }

Ответы [ 2 ]

0 голосов
/ 21 января 2019

Поскольку C не знает шаблонов, можно использовать препроцессор и некоторые (in?) Вменяемые макросы:

#include <stdlib.h>
#include <stdio.h>
#include <math.h> /* for M_PI */

#ifndef M_PI
#  define M_PI (3.14159265359)
#endif 

#define SMT_INIT(T, p, nb) do { \
  (p) = malloc(nb * sizeof (T)); \
} while (0)

#define SMT(T, p, nb, stmt) do { \
  for (size_t i = 0; i < (nb); ++i) \
  { \
    ((T*)(p))[i] = (T)(stmt); \
  } \
} while (0)

#define SMT_PRINT(T, p, nb, fmt) do { \
  for (size_t i = 0; i < (nb); ++i) \
  { \
    printf("%" fmt "\n", ((T*)(p))[i]); \
  } \
} while (0)

int main(void)
{
  void * p = NULL;
  int iform = ...;
  size_t nb = ...;

  int result = 0;

  switch (iform)
  {
    case 1:
      SMT_INIT(int, p, nb);
      SMT(int, p, nb, i);
      SMT_PRINT(int, p, nb, "d");

      break;

    case 2:
      SMT_INIT(float, p, nb);
      SMT(float, p, nb, 2.71);
      SMT_PRINT(float, p, nb, "f");

      break;

    case 3:
      SMT_INIT(double, p, nb);
      SMT(double, p, nb, i * M_PI);
      SMT_PRINT(double, p, nb, "f");

      break;

    case 4:
      result = -1;
      break;
  }

  free(p);

  return 0 == result ?EXIT_SUCCESS :EXIT_FAILURE;
}

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

#define SMT_ALL(T, p, nb, stmt, fmt) do { \
  SMT_INIT(T, p, nb); \
  SMT(T, p, nb, stmt); \
  SMT_PRINT(T, p, nb, fmt); \
} while (0)

int main(void)
{
  ...

  switch (iform)
  {
    case 1:
      SMT_ALL(int, p, nb, i, "d");

      break;

    case 2:
      SMT_ALL(float, p, nb, 2.71, "f");

      break;

    case 3:
      SMT_ALL(double, p, nb,  i * M_PI, "f");

      break;

    case 4:
      result = -1;
      break;
  }

  ...

}
0 голосов
/ 21 января 2019

Если вы выделяете память с помощью

float *a = malloc(nb*sizeof(float));

, вы можете использовать указатель a в качестве массива с плавающей запятой.Компилятор знает, насколько велика float для вычисления адреса элемента массива a[i].

Если вы приведете указатель к другому типу, размер элемента массива может отличаться, в результатепо другому адресу.С i != 0 вы будете хранить ваши данные по разным адресам, когда используете a[i] или ((double*)a)[i].

Для хранения разных типов в массиве, я предлагаю использовать union.Вместо магических чисел для iform я предлагаю использовать тип enum (или #define s).Чтобы уменьшить количество циклов for, вы можете переместить сравнение iform в тело цикла.

union data {
    int intVal;
    float floatVal;
    double doubleVal;
};

enum dataType {
    INT_DATA = 1,
    FLOAT_DATA = 2,
    DOUBLE_DATA = 3
}

void smt(int nb, enum dataType iform, union data *ptr)//example function
{
    for( int i = 0; i < nb; i++ )
    {
        switch( iform )
        {
        case INT_DATA:
            ptr[i].intVal = i;
            break
        case FLOAT_DATA:
            ptr[i].floatVal = 2.71;
            break;
        case DOUBLE_DATA:
        default:
            ptr[i].doubleVal = i*3.14159;
            break;
        }
    }
} 

int main(void)
{
    int nb = 5;
    enum dataType iform = FLOAT_DATA;
    union data *a = malloc(nb*sizeof(union data )); //allocate memory 

    smt(nb, iform, a );
    for( int i = 0; i < nb; i++)
    {
        switch( iform )
        {
        case INT_DATA:
            printf("a = %d\n", a[i].intVal);
            break
        case FLOAT_DATA:
            printf("a = %f\n", (double)a[i].floatVal);
            break;
        case DOUBLE_DATA:
        default:
            printf("a = %f\n", a[i].doubleVal);
            break;
        }
   }            
   return 0;
}

Можно было бы использовать указатель void и для приведения, но вы должны будете использовать указательдля самого большого типа данных и вместо приведения указателя на начало массива a yopu должен был бы привести адрес элемента массива.Предполагая, что double является самым большим типом данных, вы можете сделать что-то вроде этого.

double *a = malloc(nb*sizeof(*a)); //allocate memory 

int *ipt = (int*)&(a[i]);
*ipt = i;

, но я не рекомендую это.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...