【问题标题】:c - void pointer array with random printc - 带有随机打印的空指针数组
【发布时间】:2018-10-29 11:18:46
【问题描述】:

我尝试了很多不同的方法,也看过很多不同的文章来做到这一点,但我无法让它发挥作用。我试过 malloc 方法。我正在尝试将各种数据类型分配到一个 void 指针数组中并打印一个随机选择的值。

#include <stdio.h>
#define LENGTH 4
void main()
{
    int a = 3;
    float b = 2.5;
    char c = 'H';
    int d = 421;
    char e = 'a';
    void *array;
    array[LENGTH];
    array[0] = &a;
    array[1] = &b;
    array[2] = &c;
    array[3] = &d;
    array[4] = &e;
    printf("%p \n", array[rand() % LENGTH]);
}

【问题讨论】:

  • 如果您使用的是 GCC,请将-pedantic-errors 添加到您的命令行中。
  • 你需要指针数组void *array[LENGTH ];#define LENGTH 4应该是#define LENGTH 5
  • array 此处未分配。您刚刚将它定义为堆栈上的指针,它将指向任何地方(因为堆栈变量不会自动初始化,除非您指定它)。 array[LENGTH]; 行根本不做任何事情。以下行现在只写入数组点指向的任何位置。最后一行看起来是正确的,但是在此之前您可能已经损坏了一些内存或导致内存写入冲突。

标签: c arrays pointers printing


【解决方案1】:

为了打印任何类型的通用数据,您需要将类型信息与数据一起存储。这通常在 C 中通过创建枚举来完成。例如:

typedef enum
{
  TYPE_INT,
  TYPE_FLOAT,
  TYPE_CHAR,
  TYPE_STR,
} type_t;

然后您可以将其与数据一起存储:

typedef struct
{
  type_t type;
  void*  data;
} generic_t;

所以数组必须是结构数组:

generic_t array [LENGTH] = { ... };

完整示例:

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

typedef enum
{
  TYPE_INT,
  TYPE_FLOAT,
  TYPE_CHAR,
  TYPE_STR,
} type_t;

typedef struct
{
  type_t type;
  void*  data;
} generic_t;


void print_int   (int   x) { printf("%d", x); }
void print_float (float x) { printf("%f", x); }
void print_char  (char  x) { printf("%c", x); }
void print_str   (const char* x) { printf("%s", x); }

void print (const generic_t* gen)
{
  switch(gen->type)
  {
    case TYPE_INT:   print_int(*(int*)gen->data);       break;
    case TYPE_FLOAT: print_float(*(float*)gen->data);   break;
    case TYPE_CHAR:  print_char(*(char*)gen->data);     break;
    case TYPE_STR:   print_str((const char*)gen->data); break;
  }
}

#define LENGTH 5

int main (void)
{
  srand(time(NULL));

  int a = 3;
  float b = 2.5;
  char c = 'H';
  int d = 421;
  char e[] = "hello";

  generic_t array [LENGTH] =
  {
    { TYPE_INT,   &a },
    { TYPE_FLOAT, &b },
    { TYPE_CHAR,  &c },
    { TYPE_INT,   &d },
    { TYPE_STR,   &e },
  };

  for(size_t i=0; i<10; i++) // print 10 random indices of the array
  {
    print( &array[rand()%LENGTH] );
    printf("\n");
  }
}

这可以通过使用 C11 _Generic 等变得更漂亮、更安全,但以上是通用 C 编程的“老派”、向后兼容的方式。

【讨论】:

  • 出于好奇,您的意思是_Generic 可以应用于print 本身吗?
  • @StoryTeller 仅当传递的参数是原始intfloat 等而不是本示例中的结构时。要使用_Generic 重写它,上面的函数将被删除以支持宏。
  • 我想的也差不多。虽然这带来了另一个问题,'H' 和公司是整数。所以print(1); print(2.5); 工作正常,但print('H'); 会出乎意料。虽然这当然不是您的解决方案的错,只是语言缺陷。
  • @StoryTeller 确实如此。所以它必须是print( (char)'H' );
  • @StoryTeller 这是一种方法:stackoverflow.com/a/42245994/584518
【解决方案2】:

假设你想随机打印变量的地址:

#include <stdio.h>
#define LENGTH 5 //There are five variables
void main()
{
    int a = 3;
    float b = 2.5;
    char c = 'H';
    int d = 421;
    char e = 'a';
    void *array[LENGTH] = {&a, &b, &c, &d, &e};
    printf("%p \n", array[rand() % LENGTH]);
}

要打印这些地址的值,您必须对程序进行一些更改。
- 为数据类型声明一个Enum
- 在structure 中使用匿名union 来保存数据及其类型
- 基于适当类型打印的打印函数

程序将如下所示:

#include <stdio.h>
#define LENGTH 5

enum Type {CHAR = 0, INT, DOUBLE};

struct Variant {
    int type;
    union { 
        char c;   
        int i;    
        double d; 
    };
};

void Print(struct Variant v) {
    switch (v.type) {
        default: 
            printf("None"); 
            break;
        case CHAR: 
            printf(" %c", v.c); 
            break;
        case INT: 
            printf(" %d", v.i); 
            break;
        case DOUBLE: 
            printf(" %f", v.d); 
            break;
    }   
}

int main(void) {
    int a = 3;
    float b = 2.5;
    char c = 'H';
    int d = 421;
    char e = 'a';
    struct Variant array[5] = {0};
    array[0].type = INT; 
    array[0].i = a;

    array[1].type = DOUBLE; 
    array[1].d = b;

    array[2].type = CHAR; 
    array[2].c = c;

    array[3].type = INT; 
    array[3].i = d;

    array[4].type = CHAR; 
    array[4].c = e;

    Print(array[rand() % LENGTH]);  
    printf("\n");
}

【讨论】:

  • 我已经进行了编辑,分配没有问题,但打印为“0x7ffe322b436c”
  • @Redsam121:您想打印地址处的值吗?
  • @Redsam121:更新了答案。看看吧。
【解决方案3】:

在调用 printf 之前需要区分类型。这是一种方法。这种方法允许您正常使用 printf:printf("Random entry: %s\n", FMT_TYPE(array[rand() % LENGTH]))

记得调整 MAX_FORMATTED_LEN。

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

#define LENGTH 5

enum Types {
    CHAR,
    INT,
    FLOAT
};

typedef struct {
    void *data;
    int type;
} Type;

#define FMT_CHAR "%c"
#define FMT_INT "%d"
#define FMT_FLOAT "%f"

#define MAX_FORMATTED_LEN 100 // TODO: adjust this: put the maximum length of a printed float or int

char *fmt_type(char *buffer, Type *t);

#define FMT_TYPE(t) fmt_type((char [MAX_FORMATTED_LEN+1]){""}, t)


char *fmt_type(char *buffer, Type *t) {
    switch(t->type) {
        case CHAR:
            sprintf(buffer, FMT_CHAR, *((char *)t->data));
            break;
        case INT:
            sprintf(buffer, FMT_INT, *((int *)t->data));
            break;
        case FLOAT:
            sprintf(buffer, FMT_FLOAT, *((float *)t->data));
            break;
        default:
            printf("Wrong type: %d. Panicking.", t->type);
            exit(-1);
    }
    return buffer;
}



int main()
{
    int i0 = 3, i1 = 421;
    float f0 = 2.5;
    char c0 = 'H', c1 = 'a';

    Type a = { &i0, INT };

    Type b = { &f0, FLOAT };

    Type c = { &c0, CHAR };

    Type d = { &i1, INT };

    Type e = { &c1, CHAR };

    Type *array[LENGTH] = { &a, &b, &c, &d, &e }; 

    //printf("Random entry: %s\n", FMT_TYPE(array[rand() % LENGTH]));

    // the following is just for testing:
    int i = 0;
    for (i = 0; i < LENGTH; i++) {
        printf("entry: %s\n", FMT_TYPE(array[i]));
    }
}

【讨论】:

    猜你喜欢
    • 2015-02-13
    • 1970-01-01
    • 1970-01-01
    • 2019-04-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-14
    • 1970-01-01
    相关资源
    最近更新 更多