我正在嘗試找到一種方法來創建動態分配的 C 字串陣列。到目前為止,我已經有了以下代碼,它允許我初始化一個字串陣列并更改已經存在的索引的值。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void replace_index(char *array[], int index, char *value) {
array[index] = malloc(strlen(value) 1);
memmove(array[index], value, strlen(value) 1);
}
int main(int argc, const char * argv[]) {
char *strs[] = {"help", "me", "learn", "dynamic", "strings"};
replace_index(strs, 2, "new_value");
// The above code works fine, but I can not use it to add a value
// beyond index 4.
// The following line will not add the string to index 5.
replace_index(strs, 5, "second_value");
}
該函式replace_index將用于更改已包含在初始化程式中的字串的值,但無法在初始化程式中添加超出最大索引的字串。有沒有辦法分配更多記憶體并添加新索引?
uj5u.com熱心網友回復:
首先,如果你想做嚴肅的字串操作,那么使用幾乎任何其他語言或讓一個庫為你做這件事都會容易得多。
無論如何,進入答案。
原因replace_index(strs, 5, "second_value");在您的代碼中不起作用是因為 5 超出范圍 - 該函式將寫入與strs. 這不是你的問題,但如果你不知道,這很重要。相反,您似乎想附加一個字串。下面的代碼應該可以解決問題。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
char **content;
int len;
} string_array;
void free_string_array(string_array *s) {
for (int i = 0; i < s->len; i ) {
free(s->content[i]);
}
free(s->content);
free(s);
}
int append_string(string_array *s, char *value) {
value = strdup(value);
if (!value) {
return -1;
}
s->len ;
char **resized = realloc(s->content, sizeof(char *)*s->len);
if (!resized) {
s->len--;
free(value);
return -1;
}
resized[s->len-1] = value;
s->content = resized;
return 0;
}
string_array* new_string_array(char *init[]) {
string_array *s = calloc(1, sizeof(string_array));
if (!s || !init) {
return s;
}
while (*init) {
if (append_string(s, *init)) {
free_string_array(s);
return NULL;
}
init ;
}
return s;
}
// Note: It's up to the caller to free what was in s->content[index]
int replace_index(string_array *s, int index, char *value) {
value = strdup(value);
if (!value) {
return -1;
}
s->content[index] = value;
return 0;
}
int main() {
string_array *s = new_string_array((char *[]) {"help", "me", "learn", "dynamic", "strings", NULL});
if (!s) {
printf("out of memory\n");
exit(1);
}
free(s->content[2]);
// Note: No error checking for the following two calls
replace_index(s, 2, "new_value");
append_string(s, "second value");
for (int i = 0; i < s->len; i ) {
printf("%s\n", s->content[i]);
}
free_string_array(s);
return 0;
}
此外,您不必將char **and放在int一個結構中,但如果這樣做會更好。
如果您不想使用此代碼,關鍵是char **必須動態分配字串陣列(如果您愿意)。意思是,你需要使用malloc()或類似的東西來獲得你需要的記憶體,你會用它realloc()來獲得更多(或更少)。free()當你使用它時,不要忘記你得到的東西。
我的示例用于strdup()制作 s 的副本,char *以便您可以隨時更改它們。如果您不打算這樣做,可能會更容易移除strdup()ing 部分以及free()它們的 ing。
uj5u.com熱心網友回復:
靜態陣列
char *strs[] = {"help", "me", "learn", "dynamic", "strings"};
這宣告strs為一個指向 char 的指標陣列,并用 5 個元素對其進行初始化,因此隱含[]的是 is [5]。const char *strs[]如果不打算修改字串,則更嚴格的會更合適。
最大長度
char strs[][32] = {"help", "me", "learn", "dynamic", "strings"};
這宣告strs為char 陣列 32 的陣列,該陣列用 5 個元素初始化。5 個元素在字串之外被零填充。最多可以修改 32 個字符,但不能添加更多。
動態陣列
struct str_array { const char **data; size_t size, capacity; };
我認為您要求的是const char *. 動態陣列的語言級支持不在標準C運行時;必須自己寫。這是完全可能的,但涉及更多。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
/** A dynamic array of constant strings. */
struct str_array { const char **data; size_t size, capacity; };
/** Returns success allocating `min` elements of `a`. This is a dynamic array,
with the capacity going up exponentially, suitable for amortized analysis. On
resizing, any pointers in `a` may become stale. */
static int str_array_reserve(struct str_array *const a, const size_t min) {
size_t c0;
const char **data;
const size_t max_size = ~(size_t)0 / sizeof *a->data;
if(a->data) {
if(min <= a->capacity) return 1;
c0 = a->capacity < 5 ? 5 : a->capacity;
} else {
if(!min) return 1;
c0 = 5;
}
if(min > max_size) return errno = ERANGE, 0;
/* `c_n = a1.625^n`, approximation golden ratio `\phi ~ 1.618`. */
while(c0 < min) {
size_t c1 = c0 (c0 >> 1) (c0 >> 3);
if(c0 >= c1) { c0 = max_size; break; } /* Unlikely. */
c0 = c1;
}
if(!(data = realloc(a->data, sizeof *a->data * c0)))
{ if(!errno) errno = ERANGE; return 0; }
a->data = data, a->capacity = c0;
return 1;
}
/** Returns a pointer to the `n` buffered strings in `a`, that is,
`a [a.size, a.size n)`, or null on error, (`errno` will be set.) */
static const char **str_array_buffer(struct str_array *const a,
const size_t n) {
if(a->size > ~(size_t)0 - n) { errno = ERANGE; return 0; }
return str_array_reserve(a, a->size n)
&& a->data ? a->data a->size : 0;
}
/** Makes any buffered strings in `a` and beyond if `n` is greater then the
buffer, (containing uninitialized values) part of the size. A null on error
will only be possible if the buffer is exhausted. */
static const char **str_array_append(struct str_array *const a,
const size_t n) {
const char **b;
if(!(b = str_array_buffer(a, n))) return 0;
return a->size = n, b;
}
/** Returns a pointer to a string that has been buffered and created from `a`,
or null on error. */
static const char **str_array_new(struct str_array *const a) {
return str_array_append(a, 1);
}
/** Returns a string array that has been zeroed, with zero strings and idle,
not taking up any dynamic memory. */
static struct str_array str_array(void) {
struct str_array a;
a.data = 0, a.capacity = a.size = 0;
return a;
}
/** Erases `a`, if not null, and returns it to idle, not taking up dynamic
memory. */
static void str_array_(struct str_array *const a) {
if(a) free(a->data), *a = str_array();
}
int main(void) {
struct str_array strs = str_array();
const char **s;
size_t i;
int success = EXIT_FAILURE;
if(!(s = str_array_append(&strs, 5))) goto catch;
s[0] = "help";
s[1] = "me";
s[2] = "learn";
s[3] = "dynamic";
s[4] = "strings";
strs.data[2] = "new_value";
if(!(s = str_array_new(&strs))) goto catch;
s[0] = "second_value";
for(i = 0; i < strs.size; i ) printf("->%s\n", strs.data[i]);
{ success = EXIT_SUCCESS; goto finally; }
catch:
perror("strings");
finally:
str_array_(&strs);
return success;
}
uj5u.com熱心網友回復:
但無法在初始化程式中添加超出最大索引的字串
為此,您還需要指標陣列是動態的。創建字串的動態陣列是使用指標到指標來模擬 2D 陣列的極少數地方之一:
size_t n = 5;
char** str_array = malloc(5 * sizeof *str_array);
...
size_t size = strlen(some_string) 1;
str_array[i] = malloc(size);
memcpy(str_array[i], some_string, size);
n您必須手動跟蹤使用的尺寸,并在用完時留出realloc更多空間。保證保留以前的值。str_arrayrealloc
這是非常靈活的,但代價是碎片分配,這相對較慢。如果您使用固定大小的 2D 陣列,代碼會執行得更快,但您無法調整它們的大小。
請注意,我使用的是memcpy,而不是memmove- 前者是您通常應該使用的,因為它是最快的。memmove適用于您懷疑被復制的兩個陣列可能重疊的特殊場景。
作為旁注,strlen 可以替換為,這是目前的非標準功能(但被廣泛支持)malloc。在即將到來的 C23 版本的 C 中,這似乎很可能成為標準,因此使用它將成為推薦的做法。memcpystrdupstrdup
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/464191.html
