所以我有這段代碼,目標是有一個void *data指標,它有時用于存盤一個簡單的陣列int,有時是單個char陣列,有時我需要存盤一個字符陣列陣列。我確保我始終知道我存盤在 void 指標中的資料型別。
代碼在在線決議器中執行良好,這是它的輸出:
sizeof 2 x char*: 8 str0: string1 addr: 2995278544 str1: bla2 addr: 2995278576 checking strings: str0: string1 addr: 2995278544 str1: bla2 addr: 2995278576
計劃是為 n 個 char* 指標分配空間并保存該指標 do void *data。然后將型別更改為“char **ptr”(指向指標的指標),這樣我就可以保存 strdup 回傳到該陣列的地址并稍后訪問它們。checkItems(uint8_t) 正是這樣做的,它通過再次將“void *data”指標更改為“char **ptr”來重新訪問“void *data”指標,以便能夠訪問保存實際 C 字串的記憶體地址。
這一切都正確嗎?一個人會這樣做嗎?我應該對 void *data 指標使用某種型別的轉換,而不是簡單地說“char **ptr = data;”?
謝謝!
#include<stdio.h>
#include<stdint.h>
#include<string.h>
#include<stdlib.h>
#include<stdarg.h>
void copyItems(uint8_t num, ...);
void checkItems(uint8_t num);
void *data;
int main()
{
copyItems(2, "string1", "bla2");
checkItems(2);
}
void copyItems(uint8_t num, ...)
{
printf("sizeof %u x char*: %u\r\n", num, sizeof(char*), sizeof(char*)*num);
data = malloc(sizeof(char*)*num);
char **ptr = data;
va_list ap;
va_start(ap, num);
for (uint8_t n = 0; n < num; n )
{
ptr[n] = strdup(va_arg(ap, char*));
printf("str%u: %s addr: %u\r\n", n, ptr[n], ptr[n]);
}
va_end(ap);
}
void checkItems(uint8_t num)
{
char **ptr = data;
printf("checking strings:\r\n");
for (uint8_t n = 0; n < num; n )
{
printf("str%u: %s addr: %u\r\n", n, ptr[n], ptr[n]);
}
}
uj5u.com熱心網友回復:
我會在結構中存盤大小和型別資訊
typedef enum
{
INT,
CHAR,
CHARPTR,
}DATA_TYPE;
typedef struct
{
DATA_TYPE dtype;
size_t size;
void *data;
}DATA;
DATA *copyItems(size_t num, DATA_TYPE type, ...);
void PrintItems(const DATA *data);
size_t datasize(const DATA *data)
{
size_t result;
switch(data -> dtype)
{
case INT:
result = sizeof(int);
break;
case CHAR:
result = 1;
break;
case CHARPTR:
result = sizeof(char *);
break;
default:
result = 0;
break;
}
return result;
}
int main()
{
DATA *data = copyItems(2, CHARPTR, "string1", "bla2");
PrintItems(data);
}
DATA *copyItems(size_t num, DATA_TYPE type, ...)
{
DATA *data = malloc(sizeof(*data));
va_list ap;
va_start(ap, type);
if(data)
{
data -> size = 0;
data -> data = malloc(datasize(data) * num);
data -> dtype = type;
if(data -> data)
{
for (size_t n = 0; n < num; n , data -> size )
{
switch(data -> dtype)
{
case INT:
((int *)data -> data)[n] = va_arg(ap, int);
break;
case CHARPTR:
((char **)data -> data)[n] = strdup(va_arg(ap, char *));
break;
default:
break;
}
}
}
else
{ /* error handler */}
}
va_end(ap);
return data;
}
void PrintItems(const DATA *data)
{
if(data && data -> size && data -> data)
{
for(size_t i = 0; i < data -> size; i )
{
switch(data -> dtype)
{
case INT:
printf("[%zu] = %d\n", i, ((int *)data -> data)[i]);
break;
case CHARPTR:
printf("[%zu] = %s\n", i, ((char **)data -> data)[i]);
break;
default:
break;
}
}
}
}
https://godbolt.org/z/PjWhrGvvP
uj5u.com熱心網友回復:
這是一種變體 record,存在于 C 和許多語言(如 Pascal)中,也許您可??以堅持通常的做法。
在C我們可以使用匿名工會這種效果。
我將向您展示一個簡短的示例。
請注意,我不會在這里實作將字串復制到新向量的邏輯,這對于安全很重要。如果您認為需要示例,請發表評論。
資料結構示例
typedef struct
{
unsigned char id; // 1,2,3
union
{
unsigned char the_char;
unsigned char size; // up to 255 strings
};
union
{
int the_int;
const char** argv;
};
} Data;
第一個聯合的原因如下所述,但它也有助于保持Data偶數的大小,有時它對于對齊目的很有用。
第二個聯合是可選的,存在于非字符情況下,因此最小大小Data為 2 個位元組。
這里我們使用idas 1for char、2forint和3for 字串向量。
當持有單個
char它遵循id所以我們只使用 2 個位元組當持有
int它時,它跟在這 2 個位元組之后使用字串時,代碼有兩個選項:
- 對于最多 255 個字串,計數放在
size組件上,為Data. - 向量何時
size被0假定為以空字符結尾,這在可能有大量會溢位大小的字串時很有用
- 對于最多 255 個字串,計數放在
輸出
char: '?'
int: Value is 42
array of strings: [4 in total]
#1 an
#2 array
#3 of
#4 strings
array of strings [null-terminated]:
#1 an
#2 array
#3 of
#4 strings
#5 ends here
5 strings were found...
代碼
#include <iso646.h>
#include <stdio.h>
typedef struct
{
unsigned char id; // 1,2,3
union
{
unsigned char the_char;
unsigned char size; // up to 255 strings
};
union
{
int the_int;
const char** argv;
};
} Data;
int check_one(Data*);
int valid_id(Data*);
int main(void)
{
const char* words[] = {"an", "array", "of",
"strings", "ends here", NULL};
Data data[4];
data[0].id = 1;
data[0].the_char = '?';
data[1].id = 2;
data[1].the_int = 42;
data[2].id = 3;
data[2].size = 4;
data[2].argv = words;
data[3].id = 3;
data[3].size = 0; // signals the array as null-terminated
data[3].argv = words;
for (int i = 0; i < 4; i = 1) check_one(&data[i]);
return 0;
}
int check_one(Data* d)
{
const char* what[] = {NULL, "char", "int", "array of strings"};
if (d == NULL) return -1;
if (not valid_id(d)) return -2;
switch (d->id)
{
case 1:
printf("\n%s: '%c'\n", what[d->id], d->the_char);
break;
case 2:
printf("\n%s: Value is %d\n", what[d->id], d->the_int);
break;
case 3:
if (d->size != 0)
{ // known size
printf("\n%s: [%d in total]\n\n", what[d->id], d->size);
for (int i = 0; i < d->size; i = 1)
printf("\t#%d\t%s\n", 1 i, d->argv[i]);
printf("\n");
return 0;
};
// ok: the array is NULL-terminated
printf("\n%s [null-terminated]:\n\n", what[d->id]);
int sz = 0;
for (; d->argv[sz] != NULL; sz = 1)
printf("\t#%d\t%s\n", 1 sz, d->argv[sz]);
printf("\n%d strings were found...\n\n", sz);
break;
default:
break;
}
return 0;
}
int valid_id(Data* d) { return ((d->id > 0) && (d->id < 4)); };
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/383272.html
標籤:C
