如何使用具有相同名称的不同类型的指针?

时间:2019-01-21 12:20:15

标签: c pointers

我在减少for循环的数量上有问题。它们针对不同类型执行相同的操作。

我应该使用void指针还是其他指针。

是否可以减少代码数量?

  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 :(得分:2)

如果您使用以下方式分配内存

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

您可以将指针a用作float数组。编译器知道float有多大,用于计算数组元素a[i]的地址。

如果将指针强制转换为其他类型,则数组元素的大小可能会有所不同,从而导致地址不同。使用i != 0,您将在使用a[i]((double*)a)[i]时将数据存储在不同的地址。

要将不同类型存储在数组中,建议使用union。建议不要使用iform的枚举类型来代替#define的幻数。要减少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;

但我不建议这样做。

答案 1 :(得分:0)

由于C不知道模板,人们可能会回退使用预处理器和某些(在?)合理的宏:

#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;
  }

  ...

}