【问题标题】:C pointer to a const and non-const types pointers指向 const 和非 const 类型指针的 C 指针
【发布时间】:2020-06-18 21:51:47
【问题描述】:

我想声明一个指向指针的指针,其中一些指针将是const,而其他指针将是非常量指针。

下面是一个玩具示例。我有一组columns。每列都是指向intdouble 类型数据的指针。到目前为止,这工作正常。我也想使用const 指针。

#include<stdlib.h>
#include<stdio.h>
#define TYPE_INT 0
#define TYPE_DOUBLE 1

int main(void) {
  int ncol = 2;
  int nrow = 3;
  void **columns = malloc(ncol*sizeof(void*));
  int *types = malloc(ncol*sizeof(int));
  columns[0] = malloc(nrow*sizeof(int));
  types[0] = TYPE_INT;
  columns[1] = malloc(nrow*sizeof(double));
  types[1] = TYPE_DOUBLE;
  for (int i=0; i<ncol; ++i) {
    for (int j=0; j<nrow; ++j) {
      printf("value of column %d and row %d is: ", i+1, j+1);
      types[i]==TYPE_INT ?
        printf("%d", ((int*)columns[i])[j]) :
        printf("%.3f", ((double*)columns[i])[j]);
      printf("\n");
    }
  }
  return 0;
}
value of column 1 and row 1 is: 0
value of column 1 and row 2 is: 0
value of column 1 and row 3 is: 0
value of column 2 and row 1 is: 0.000
value of column 2 and row 2 is: 0.000
value of column 2 and row 3 is: 0.000

如果我尝试将double * 更改为const double*

int main(void) {
  int ncol = 2;
  int nrow = 3;
  void **columns = malloc(ncol*sizeof(void*));
  int *types = malloc(ncol*sizeof(int));
  columns[0] = malloc(nrow*sizeof(int));
  types[0] = TYPE_INT;
  columns[1] = (const double*)malloc(nrow*sizeof(double));
  types[1] = TYPE_DOUBLE;
  for (int i=0; i<ncol; ++i) {
    for (int j=0; j<nrow; ++j) {
      printf("value of column %d and row %d is: ", i+1, j+1);
      types[i]==TYPE_INT ?
        printf("%d", ((int*)columns[i])[j]) :
        printf("%.3f", ((const double*)columns[i])[j]);
      printf("\n");
    }
  }
  return 0;
}

然后gcc 发出警告

ptrs.c: In function ‘main’:
ptrs.c:13:14: warning: assignment discards ‘const’ qualifier from pointer target type [-Wdiscarded-qualifiers]
   columns[1] = (const double*)malloc(nrow*sizeof(double));

如何将我的列指针保持在一起,无论它们是const 还是正常的?

【问题讨论】:

  • 去掉来自malloc的返回值的强制转换。如果你真的想保留它,那么正确的类型是void *,而不是const double *。无论如何,它都被转换为void *,因为columns 被声明为void **。如果您想进行类型检查,请去掉 void 并改用 union,显式处理每个需要的指针类型。
  • 问题是指针来自另一个软件,所以我不能选择不进行类型检查。 union 方法似乎很有希望,@TomKarzes 你介意提供一个工作示例作为答案吗?

标签: c pointers constants


【解决方案1】:

根据您的数组(columnstypes)被相同的 [column] 索引索引,我推断给定的行必须是相同的类型?

你[本质上]有一个动态二维“稀疏”数组。

我不会使用双星指针(例如void **),而是创建一些用于扩展的结构。

这可能有点过度设计,但这是我的看法:

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

typedef enum {
    TYPE_INT,
    TYPE_DOUBLE,
    TYPE_CONST_INT,
    TYPE_CONST_DOUBLE,
} type_t;

typedef union {
    void *vp;
    const void *vpc;

    int *ip;
    const int *ipc;

    double *dp;
    const double *dpc;
} rowptr_t;

typedef struct {
    int type;
    rowptr_t *rowptr;
} column_t;

typedef struct {
    int mat_ncol;
    int mat_nrow;
    column_t *mat_base;
} matrix_t;

size_t
typesize(type_t type)
{
    size_t siz;

    siz = 0;

    switch (type) {
    case TYPE_INT:
    case TYPE_CONST_INT:
        siz = 4;
        break;

    case TYPE_DOUBLE:
    case TYPE_CONST_DOUBLE:
        siz = 8;
        break;
    }

    return siz;
}

const char *
typefmt(type_t type)
{
    const char *fmt;

    fmt = NULL;

    switch (type) {
    case TYPE_INT:
    case TYPE_CONST_INT:
        fmt = "%d";
        break;

    case TYPE_DOUBLE:
    case TYPE_CONST_DOUBLE:
        fmt = "%Lf";
        break;
    }

    return fmt;
}

void
typeprt(matrix_t *mat,int colidx,int rowidx)
{
    column_t *col;
    rowptr_t *row;
    const void *vpc;

    col = &mat->mat_base[colidx];
    row = &col->rowptr[rowidx];

    vpc = row->vpc;

    switch (col->type) {
    case TYPE_INT:
    case TYPE_CONST_INT:
        printf("%d",*(const int *) vpc);
        break;

    case TYPE_DOUBLE:
    case TYPE_CONST_DOUBLE:
        printf("%.3f",*(const double *) vpc);
        break;
    }
}

void
matinit(matrix_t *mat,int ncol,int nrow)
{

    mat->mat_nrow = nrow;
    mat->mat_ncol = ncol;

    mat->mat_base = calloc(ncol,sizeof(*mat->mat_base));
}

void
allocrow(matrix_t *mat,int colidx,type_t type)
{
    column_t *col;
    size_t siz;

    siz = typesize(type);

    col = &mat->mat_base[colidx];
    col->rowptr = malloc(mat->mat_nrow * siz);
    col->type = type;
}

int
main(void)
{
    matrix_t mat;

    matinit(&mat,2,3);
    allocrow(&mat,0,TYPE_INT);
    allocrow(&mat,1,TYPE_DOUBLE);

    for (int i = 0; i < mat.mat_ncol; ++i) {
        for (int j = 0; j < mat.mat_nrow; ++j) {
            printf("value of column %d and row %d is: ", i + 1, j + 1);
            typeprt(&mat,i,j);
            printf("\n");
        }
    }

    return 0;
}

【讨论】:

    【解决方案2】:

    您可以这样做,但在赋值期间,您需要将const 指针显式转换为非常量指针。还为const 类型添加额外的#defines,以便您知道特定列中存储的内容:

    #define TYPE_CONST_DOUBLE 2;
    
    //...
    
    //a const pointer storing an address of some buffer
    const double *ptr = (const double*)malloc(nrow*sizeof(double));
    
    //now we cast the const pointer to a non-const one and put it into the columns array
    columns[1] = (void*)ptr;
    types[1] = TYPE_CONST_DOUBLE;
    

    当您从columns[n] 读取值时,如果类型为TYPE_CONST_DOUBLE,则只需转换回const double *

    【讨论】:

    • 你不应该从malloc转换返回值。
    • @jwdonahue 是的 - 只是复制粘贴。但是为了这个例子,它并不重要——重要的部分是下一个演员:(void*)ptr。这真的不是“你不应该malloc中转换retun值”而是“你不必”,因为转换是隐含在这个特殊情况。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-09-10
    • 1970-01-01
    • 2020-02-04
    • 2021-12-08
    相关资源
    最近更新 更多