我知道如何创建一个结构数组但具有预定义的大小。但是有没有办法创建一个动态的结构数组,以便数组可以变得更大?
例如:
typedef struct
{
char *str;
} words;
main()
{
words x[100]; // I do not want to use this, I want to dynamic increase the size of the array as data comes in.
}
这可能吗?
我研究了这个:words* array = (words*)malloc(sizeof(words) * 100);
我想摆脱100并存储数据。因此,如果76个数据字段进来,我想存储76而不是100.我假设我不知道多少数据进入我的程序。在我上面定义的结构中,我可以创建第一个“索引”:
words* array = (words*)malloc(sizeof(words));
但是我想在之后动态地向数组中添加元素。我希望我能够清楚地描述问题区域。主要的挑战是动态添加第二个字段,至少这是目前的挑战。
但是我取得了一些进展:
typedef struct {
char *str;
} words;
// Allocate first string.
words x = (words) malloc(sizeof(words));
x[0].str = "john";
// Allocate second string.
x=(words*) realloc(x, sizeof(words));
x[1].FirstName = "bob";
// printf second string.
printf("%s", x[1].str); --> This is working, it's printing out bob.
free(x); // Free up memory.
printf("%s", x[1].str); --> Not working since its still printing out BOB even though I freed up memory. What is wrong?
我做了一些错误检查,这是我发现的。如果在我释放内存x后,我添加以下内容:
x=NULL;
然后,如果我尝试打印x,我得到一个错误,这就是我想要的。那么免费功能是不起作用的,至少在我的编译器上呢?我正在使用DevC ??
谢谢,我现在明白了:
FirstName是一个指向char数组的指针,它没有被malloc分配,只有指针被分配,在你调用free之后,它不会擦除内存,它只是将它标记为堆上可用以后写完了。 - 马特史密斯
我正在尝试模块化并将我的结构数组的创建放在一个函数中,但似乎没有任何效果。我正在尝试一些非常简单的事情,我不知道还能做些什么。它和以前一样,只是另一个函数,loaddata正在加载数据,而在我需要进行打印的方法之外。我怎样才能使它工作?我的代码如下:
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include <ctype.h>
typedef struct
{
char *str1;
char *str2;
} words;
void LoadData(words *, int *);
main()
{
words *x;
int num;
LoadData(&x, &num);
printf("%s %s", x[0].str1, x[0].str2);
printf("%s %s", x[1].str1, x[1].str2);
getch();
}//
void LoadData(words *x, int * num)
{
x = (words*) malloc(sizeof(words));
x[0].str1 = "johnnie\0";
x[0].str2 = "krapson\0";
x = (words*) realloc(x, sizeof(words)*2);
x[1].str1 = "bob\0";
x[1].str2 = "marley\0";
*num=*num+1;
}//
这个简单的测试代码崩溃,我不明白为什么。错误在哪里?
答案 0 :(得分:35)
您已将其标记为C ++和C。
如果你正在使用C ++,那么事情就容易多了。标准模板库有一个名为vector的模板,允许您动态构建对象列表。
#include <stdio.h>
#include <vector>
typedef std::vector<char*> words;
int main(int argc, char** argv) {
words myWords;
myWords.push_back("Hello");
myWords.push_back("World");
words::iterator iter;
for (iter = myWords.begin(); iter != myWords.end(); ++iter) {
printf("%s ", *iter);
}
return 0;
}
如果您正在使用C,那么事情就更难了,是的malloc,realloc和free是帮助您的工具。您可能需要考虑使用链接列表数据结构。这些通常更容易增长,但不便于随机访问。
#include <stdio.h>
#include <stdlib.h>
typedef struct s_words {
char* str;
struct s_words* next;
} words;
words* create_words(char* word) {
words* newWords = malloc(sizeof(words));
if (NULL != newWords){
newWords->str = word;
newWords->next = NULL;
}
return newWords;
}
void delete_words(words* oldWords) {
if (NULL != oldWords->next) {
delete_words(oldWords->next);
}
free(oldWords);
}
words* add_word(words* wordList, char* word) {
words* newWords = create_words(word);
if (NULL != newWords) {
newWords->next = wordList;
}
return newWords;
}
int main(int argc, char** argv) {
words* myWords = create_words("Hello");
myWords = add_word(myWords, "World");
words* iter;
for (iter = myWords; NULL != iter; iter = iter->next) {
printf("%s ", iter->str);
}
delete_words(myWords);
return 0;
}
Yikes,对不起世界上最长的答案。所以WRT到“不想使用链表评论”:
#include <stdio.h>
#include <stdlib.h>
typedef struct {
char** words;
size_t nWords;
size_t size;
size_t block_size;
} word_list;
word_list* create_word_list(size_t block_size) {
word_list* pWordList = malloc(sizeof(word_list));
if (NULL != pWordList) {
pWordList->nWords = 0;
pWordList->size = block_size;
pWordList->block_size = block_size;
pWordList->words = malloc(sizeof(char*)*block_size);
if (NULL == pWordList->words) {
free(pWordList);
return NULL;
}
}
return pWordList;
}
void delete_word_list(word_list* pWordList) {
free(pWordList->words);
free(pWordList);
}
int add_word_to_word_list(word_list* pWordList, char* word) {
size_t nWords = pWordList->nWords;
if (nWords >= pWordList->size) {
size_t newSize = pWordList->size + pWordList->block_size;
void* newWords = realloc(pWordList->words, sizeof(char*)*newSize);
if (NULL == newWords) {
return 0;
} else {
pWordList->size = newSize;
pWordList->words = (char**)newWords;
}
}
pWordList->words[nWords] = word;
++pWordList->nWords;
return 1;
}
char** word_list_start(word_list* pWordList) {
return pWordList->words;
}
char** word_list_end(word_list* pWordList) {
return &pWordList->words[pWordList->nWords];
}
int main(int argc, char** argv) {
word_list* myWords = create_word_list(2);
add_word_to_word_list(myWords, "Hello");
add_word_to_word_list(myWords, "World");
add_word_to_word_list(myWords, "Goodbye");
char** iter;
for (iter = word_list_start(myWords); iter != word_list_end(myWords); ++iter) {
printf("%s ", *iter);
}
delete_word_list(myWords);
return 0;
}
答案 1 :(得分:11)
如果您想动态分配数组,可以使用stdlib.h
中的malloc
。
如果要使用words
结构分配包含100个元素的数组,请尝试以下操作:
words* array = (words*)malloc(sizeof(words) * 100);
要分配的内存大小将传递到malloc
,然后它将返回类型为void
(void*
)的指针。在大多数情况下,您可能希望将其强制转换为所需的指针类型,在本例中为words*
。
此处使用sizeof
关键字来查找words
结构的大小,然后将该大小乘以您要分配的元素数。
完成后,请务必使用free()
释放您使用的堆内存,以防止memory leaks:
free(array);
如果您想更改已分配数组的大小,可以尝试使用其他人提到的realloc
,但请记住,如果您执行了很多realloc
,那么您可能会{ {3}}。如果要动态调整阵列大小以便为程序保留较低的内存占用,最好不要做太多realloc
。
答案 2 :(得分:5)
这看起来像是一次学术练习,不幸的是因为你不能使用C ++而变得更难。基本上,您必须管理分配的一些开销,并在需要稍后调整大小时跟踪已分配的内存量。这就是C ++标准库的亮点。
对于您的示例,以下代码分配内存,稍后调整大小:
// initial size
int count = 100;
words *testWords = (words*) malloc(count * sizeof(words));
// resize the array
count = 76;
testWords = (words*) realloc(testWords, count* sizeof(words));
请记住,在您的示例中,您只是分配一个指向char的指针,您仍然需要分配字符串本身,更重要的是在最后释放它。所以这段代码分配了100个指向char的指针,然后将其调整为76,但不会自己分配字符串。
我怀疑你实际上想要在一个与上面非常类似的字符串中分配字符数,但是将单词改为char。
编辑:还要记住,使很有意义来创建执行常见任务的功能并强制执行一致性,这样就不会在任何地方复制代码。例如,您可能有a)分配结构,b)为结构赋值,c)释放结构。所以你可能有:
// Allocate a words struct
words* CreateWords(int size);
// Assign a value
void AssignWord(word* dest, char* str);
// Clear a words structs (and possibly internal storage)
void FreeWords(words* w);
编辑:就调整结构大小而言,它与调整char数组的大小完全相同。但是,区别在于如果使struct数组更大,则应该将新数组项初始化为NULL。同样,如果使struct数组变小,则需要在删除项之前进行清理 - 这是在调整struct数组大小之前已分配的空闲项(以及仅分配的项)。这是我建议创建帮助函数来帮助管理它的主要原因。
// Resize words (must know original and new size if shrinking
// if you need to free internal storage first)
void ResizeWords(words* w, size_t oldsize, size_t newsize);
答案 3 :(得分:3)
在C ++中,使用vector。它就像一个数组,但您可以轻松添加和删除元素,它将负责为您分配和释放内存。
我知道问题的标题是C,但你用C和C ++标记了你的问题......
答案 4 :(得分:3)
另一个选项是linked list。您需要分析程序将如何使用数据结构,如果您不需要随机访问,它可能比重新分配更快。
答案 5 :(得分:3)
以下是我在C ++中的表现
size_t size = 500;
char* dynamicAllocatedString = new char[ size ];
对任何struct或c ++类使用相同的主体。
答案 6 :(得分:1)
上次更新中的代码不应该编译,更不用说运行了。你正在传递&amp; x到LoadData。 &amp; x具有**字的类型,但LoadData需要单词*。当然,当你在指向堆栈的指针上调用realloc时,它会崩溃。
修复它的方法是将LoadData更改为接受单词**。你可以实际修改main()中的指针。例如,realloc调用看起来像
*x = (words*) realloc(*x, sizeof(words)*2);
与“num”中的原则相同的是int *而不是int。
除此之外,你需要真正弄清楚单词中的字符串是如何存储的。允许将const字符串分配给char *(如在str2 =“marley \ 0”中),但它很少是正确的解决方案,即使在C中也是如此。
另一点:不需要“marley \ 0”,除非你真的需要在字符串末尾有两个0。编译器在每个字符串文字的末尾添加0。
答案 7 :(得分:1)
对于测试代码:如果要修改函数中的指针,则应将“指针指针”传递给函数。更正后的代码如下:
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
typedef struct
{
char *str1;
char *str2;
} words;
void LoadData(words**, int*);
main()
{
words **x;
int num;
LoadData(x, &num);
printf("%s %s\n", (*x[0]).str1, (*x[0]).str2);
printf("%s %s\n", (*x[1]).str1, (*x[1]).str2);
}
void LoadData(words **x, int *num)
{
*x = (words*) malloc(sizeof(words));
(*x[0]).str1 = "johnnie\0";
(*x[0]).str2 = "krapson\0";
*x = (words*) realloc(*x, sizeof(words) * 2);
(*x[1]).str1 = "bob\0";
(*x[1]).str2 = "marley\0";
*num = *num + 1;
}
答案 8 :(得分:0)
如果你想动态增长数组,你应该使用malloc()动态分配一些固定数量的内存,然后在你用完时使用realloc()。一种常见的技术是使用指数增长函数,以便您分配一些小的固定数量,然后通过复制分配的数量使数组增长。
一些示例代码是:
size = 64; i = 0;
x = malloc(sizeof(words)*size); /* enough space for 64 words */
while (read_words()) {
if (++i > size) {
size *= 2;
x = realloc(sizeof(words) * size);
}
}
/* done with x */
free(x);
答案 9 :(得分:0)
每个编码人员都需要简化他们的代码以使其易于理解....即使对于初学者也是如此。
如果您了解概念,那么使用动态的结构数组很容易。
// Dynamically sized array of structures
#include <stdio.h>
#include <stdlib.h>
struct book
{
char name[20];
int p;
}; //Declaring book structure
int main ()
{
int n, i;
struct book *b; // Initializing pointer to a structure
scanf ("%d\n", &n);
b = (struct book *) calloc (n, sizeof (struct book)); //Creating memory for array of structures dynamically
for (i = 0; i < n; i++)
{
scanf ("%s %d\n", (b + i)->name, &(b + i)->p); //Getting values for array of structures (no error check)
}
for (i = 0; i < n; i++)
{
printf ("%s %d\t", (b + i)->name, (b + i)->p); //Printing values in array of structures
}
scanf ("%d\n", &n); //Get array size to re-allocate
b = (struct book *) realloc (b, n * sizeof (struct book)); //change the size of an array using realloc function
printf ("\n");
for (i = 0; i < n; i++)
{
printf ("%s %d\t", (b + i)->name, (b + i)->p); //Printing values in array of structures
}
return 0;
}