【问题标题】:Array values set in function only work properly for one data type函数中设置的数组值仅适用于一种数据类型
【发布时间】:2020-02-10 18:22:04
【问题描述】:

在这段代码中,我试图在指针算术和数组方面做得更好。我有一个函数,它根据用户输入的内容创建一个数组类型(因此我使用 void * 作为函数类型),然后在数组 [-1] 点中“隐藏”函数的大小,所以它总是可以被索引并在那里有大小。最后,我将其转换为 void 并返回数组。

它适用于整数,但没有其他数据类型。

#include <stdio.h>
#include <stdlib.h>

void * createArray(int size, int soa)
{
int *array;
array = malloc(sizeof(int)+size*soa);
array[0] = size; array++;
return (void*)array;
}

int main(void)
{
int *array;
array = createArray(10, sizeof(int));
double *array2;
array2 = createArray(5, sizeof(double));
printf("%d\n", *(array-1));
printf("%f", *(array2-1));
}

我的输出是: 10 0.000000

所以,它正确地为整数隐藏了它,但是对于所有其他数据类型都出了问题,我很难过。任何帮助将不胜感激!!!

【问题讨论】:

  • double 的大小可能与int 不同,因此它不会起作用。您在那里存储了一个int,并试图将其视为double。而且您也只为int 分配了足够的空间。即使大小相同,它也不是存储在那里的double 值。它们没有相同的表示。
  • ... 所以您不能将 int 值传递给 %f 格式并期望任何合理的结果。
  • 使用size_t 表示大小,而不是整数。另请参阅calloc
  • 也可能存在对齐问题。例如,如果double 需要在 8 字节边界上对齐,分配代码将(通常)返回一个 4 字节对齐的指针,而不是 8 字节对齐的指针,并且数组将不可用。跨度>

标签: c arrays pointers


【解决方案1】:

@Azoros,

您的代码适用于整数,因为您将指针类型定义为整数。当您将指针类型定义为双精度时,处理器将尝试将每个元素作为双精度数据类型处理。内部整数和双精度数使用不同的格式存储。这就是为什么当您尝试从双精度数据类型中检索整数值时它不起作用的原因。

所以,如果我正确理解了您的问题,您希望将一个数组的零元素定义为一个包含数组长度的整数。其余元素需要保存可能与第一个元素不同的数据类型的数据值。

我会通过将数组指针定义为字节数组 (void *) 来解决这个问题。然后在访问元素时,我会告诉处理器它正在处理什么数据类型。

这是在实践中的做法:

将指针定义改为字节指针。

void* array;

将数组分配到包含数组长度元素和数据元素的大小。

array = calloc(1, INT_SIZ + (noe * soe));

将大小值移动到数组的第一个位置。请注意,在 Windows x86 机器上,这将复制 4 个字节的数据。

memcpy(array, (void*)&noe, INT_SIZ);

返回第一个元素大小的内存地址偏移量。在 x86 机器上,这将偏移 4 个字节

return (void*)(((int*)(array)) + 1);

这里是使用修改后的 createArray 例程的完整代码。

# include <stdio.h>
# include <string.h>
# include <stdlib.h>

# define INT_SIZ sizeof(int)
# define GetSize( pt ) ((int *)pt)[-1]
# define GetElement( pt, etype, idx ) ((etype *)pt)[idx]
# define InsertElement( pt, etype, idx, val ) \
  { \
     etype temp = val; \
     memcpy ( (void *) &((etype *)pt)[idx], &temp, sizeof(etype) ); \
  }



void * createArray(int noe,  /* Number of elements */
                   int soe)  /* Size of element */
{
   void *array;

   /* Allocate the array */    
   array = calloc(1, INT_SIZ + (noe * soe));
   if ( array == NULL ) return NULL;

   /* Copy the integer value representing the number of elements to the first
      element in the array */
   memcpy ( array, (void *) &noe, INT_SIZ );


   /* Return the pointer value offset by the size of an int */
   return (void *) (((int *)(array))+1);
}


int main(void)
{
   void *array;
   int i=0;

   array = createArray(10, sizeof(int));
   InsertElement ( array, int, 0, 65534 );

   printf("%d\n",  *(int *)( ((int *)(array)) - 1) );  /* pointer syntax */
   printf("%d\n",  ((int *)array)[-1]  );              /* array syntax   */
   printf("%d\n",  GetSize(array)  );
   printf ( "Element #%d: %d\n", 0, GetElement ( array, int, 0 ) );

   puts ( "\nDemonstrating Array of Doubles --------------------------------");
   array = createArray(10, sizeof(double));
   InsertElement ( array, double, 0, 3.0 );
   InsertElement ( array, double, 1, 3.1 );
   InsertElement ( array, double, 2, 3.2 );

   printf("Array size: %d\n",  GetSize(array)  );
   for ( i=0; i<3; i++ )
      printf ( "Element #%d: %lf\n", i, GetElement ( array, double, i ) );

   free ( ((int *)(array))-1 );
}

这是输出:

10
10
10
Element #0: 65534

Demonstrating Array of Doubles --------------------------------
Array size: 10
Element #0: 3.000000
Element #1: 3.100000
Element #2: 3.200000

关于代码的注意事项

  1. 该数组被视为零基数组,就像任何其他 C 数组。
  2. 虽然在例程中,我添加了一个检查内存是否 已分配,则 createArray 的任何调用者都应进行类似的检查 例行公事。
  3. 添加了宏定义以使代码更具可读性。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-07-17
    • 2020-10-19
    • 1970-01-01
    • 1970-01-01
    • 2013-03-29
    • 2016-08-17
    • 2020-12-17
    • 1970-01-01
    相关资源
    最近更新 更多