如何定义一个动态的数组

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何定义一个动态的数组相关的知识,希望对你有一定的参考价值。

例如,定义一个a[10],但是scanf()输入的时候不输入10个元素,输入小于10个的元素,要怎么做呢

如果楼主使用的是C++编程,那么不推荐你这么做。推荐你使用vector来做这件事情。


不过看起来使用的C来编程的,

这里你定义了a[10],但是没有输入足够的元素,这个不会出问题。

这个数组中只有前几个是你输入的值,没有得到输入的就是系统给的默认值。


定义动态数组,在C中使用的是malloc函数。

例如:

int *a = (int*)malloc(sizeof(int) * 10);

这个几乎和 int a[10]; 等价。


不过这里使用malloc是显示分配内存,所以需要使用free函数显示的进行销毁。(堆中分配)

但是,int a[10] 的形式,是在栈中分配,当程序运行超出了这个变量的生存范围,这个数组会自行销毁的。

追问

那如果用scanf的时候,输入数组元素的值的时候,回车会结束赋值么?

追答

如果scanf函数不在一个循环里面,只有单独的一句。

例如这个程序(program 1), 当你第一次按下回车后,就会结束赋值:

int main ()  // program 1
  int a[10];
  scanf("%d", &a[0]);

例如这个程序(program 2), 当你第一次按下回车后,不会结束赋值;而会进入到第二个赋值过程中...依次类推,只到第10次:

int main ()  // program 2
  int a[10], i;
  for ( i = 0; i < 10; i++) 
    scanf("%d", &a[i]);
  

如还有问题,请追问。

追问

program1中,是不是就输入一个元素的值啊?
program2中,不就是输入了10个数么?
但是如果运行的时候不一定输入几个数怎么办呢?例如:int a[10];怎么输入6个数?

追答

恩,对的。

你要输入6个数,这样做就可以了

int main ()  // program 3
  int a[10], i;
  for ( i = 0; i < 6; i++) 
    scanf("%d", &a[i]);
  

输入的每个数用回车或空格隔开

追问

那如果6那里是不确定的怎么办?

追答

如果不确定输入个数,需要再输入前确定。

例如:

#include <stdio.h>
int main ()  // program 4
  int a[10], i,n;
  printf("please enter the number of numbers:");
  scanf("%d", &n);
  
   if (n > 10)
    printf("Please check your number, the number should be less than 10!!");
    exit(-1);
  
  
  printf("\\nplease enter the numbers one by one:");
 
  for ( i = 0; i < n; i++) 
    scanf("%d", &a[i]);
  

如果不想让程序意外退出,可以使用动态数组:

#include <malloc.h>
#include <stdio.h>

int main ()  // program 5
  int *a, i,n;
  printf("please enter the number of numbers:");
  scanf("%d", &n);
  
  a = (int*)malloc(sizeof(int) * n);
  
  printf("\\nplease enter the numbers one by one:");
 
  for ( i = 0; i < n; i++) 
    scanf("%d", &a[i]);
  
  
  free(a);

参考技术A #include<iostream>
using namespace std;
int main()

int len;
cin>>len;
//用指针p指向new动态分配的长度为len*sizeof(int)的内存空间
int *p=new int[len];
...........
delete[] p;
return 0;

参考技术B 如果使用的是C语言的话, 用malloc函数, 定义动态数组。
例如:int *a = (int*)malloc(sizeof(int) * 10); // 分配10个int类型的数组, 同int a[10]

普通数组分配在栈(stack)里面, 由变压器统一分配和回收. 动态数组则定义在堆(heap)里面, 分配后要调用用free函数释放内存, 以免造成内存泄漏. 其它编程语言都可以查找相应的分配/释放函数, 但其本质都是分配在堆里面.
参考技术C a[5]数组中 5表示a数组中有5个元素,分别是a[0],a[1],a[2],a[3],a[4].

在sum=a[0]+a[1]+a[2]+a[3]+a[4]+a[5] 公式中严格的讲

将会出现‘下标越界’或‘上标越界’的错误(在不同的语言中数组的开始时不一样的!例如:c是 0开始;basic是1开始的!)!但是分在什么里面运行里!

而a[5]的值到底是多少呢?

就要知道,这个数组是如何在内存中存储的了!

数组如何在内存中存储,就要知道,数组是什么类型的?
不同的类型占用不同内存的大小!

例如: 地址:&1205 存储的 是a[4]的值,数组a是一个整形!

那a中的每一个元素占用的内存大小就是4字节,那么总共开辟的空间便是20字节的内存大小!

a[5]就是这20字节内存中,后面的4字节中得值。

a数组后面的4字节的值是多少呢?

谁也不知道?

只有内存知道!嘿嘿!

所以a[5]是一个不可预料的值!
参考技术D int(*a)[80];
a=new int[n] [80];追问

看不懂诶

如何创建动态大小的结构数组?

【中文标题】如何创建动态大小的结构数组?【英文标题】:How can I create a dynamically sized array of structs? 【发布时间】:2010-09-20 15:04:34 【问题描述】:

我知道如何创建具有预定义大小的结构数组。但是,有没有办法创建一个动态的结构数组,使数组变得更大?

例如:

    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;
    //

这个简单的测试代码崩溃了,我不知道为什么。错误在哪里?

【问题讨论】:

你到底是什么意思:“我想在数组之后动态添加元素”和“主要挑战是动态添加第二个字段”?您的意思是向结构内的项目添加第二个元素吗?也许你需要: typedef struct char **str words;指向字符串的指针。 永远不要 x = realloc(x, newsize);除非您有 x 值的副本。如果 realloc() 失败,那么你已经丢失了指针并且有泄漏。 我的问题的答案就在你的问题中:) 【参考方案1】:

如果要动态分配数组,可以使用malloc from stdlib.h

如果您想使用 words 结构分配一个包含 100 个元素的数组,请尝试以下操作:

words* array = (words*)malloc(sizeof(words) * 100);

您要分配的内存大小被传递到malloc,然后它将返回一个voidvoid*)类型的指针。在大多数情况下,您可能希望将其转换为所需的指针类型,在本例中为 words*

sizeof 关键字在这里用于找出words 结构的大小,然后将该大小乘以您要分配的元素数。

完成后,请务必使用free() 释放您使用的堆内存,以防止memory leaks:

free(array);

如果你想改变分配数组的大小,你可以尝试像其他人提到的那样使用realloc,但请记住,如果你做很多reallocs,你最终可能会使用fragmenting the memory。如果您想动态调整数组大小以保持程序的低内存占用,最好不要做太多reallocs。

【讨论】:

感谢您指出这一点,夜骑士!我已经修复了错误。 在 C 中,'void *'(由 malloc() 返回)不是强制转换为另一种指针类型 - 您可以省略转换。但是,C++ 确实需要强制转换。【参考方案2】:

如果你想动态增长数组,你应该使用 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);

【讨论】:

这不是 realloc 的正确用法。请进行适当的研究和编辑。【参考方案3】:

在 C++ 中,使用 vector。它就像一个数组,但您可以轻松添加和删除元素,它会为您分配和释放内存。

我知道问题的标题是 C,但您用 C 和 C++ 标记了您的问题...

【讨论】:

我投了反对票,因为它是最佳答案,但现在标签只有 c。对不起;)【参考方案4】:

您的另一个选择是linked list。您需要分析您的程序将如何使用数据结构,如果您不需要随机访问,它可能比重新分配更快。

【讨论】:

【参考方案5】:

您已将其标记为 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;

哎呀,对不起,世界上最长的答案。所以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;

【讨论】:

我别无选择,只能使用动态数组。如果它是一个链表,我不会有问题。我用链表编写了大量程序,这就是为什么这个程序对我来说如此复杂。 不要在 C 中强制转换返回 void * 的函数的返回值。它不会添加任何内容,并且可能会隐藏缺少原型的错误。 克里斯,您总是需要将返回值从 void* 转换为您分配的内容 - 这是 c 而不是 c++。 @thaggie:你搞错了; C 不需要强制转换,但 C++ 需要。 @thaggie:非常好,我喜欢。一个潜在的问题是静态字符串和 add_word_to_word_list。您的示例适用于静态字符串,但对于分配的字符串,它会导致内存泄漏。分配内存并复制字符串然后在 delete_word_list 中释放它可能会更好【参考方案6】:

这看起来像是一项学术练习,不幸的是,由于您不能使用 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,但不分配字符串本身。

我怀疑您实际上想分配与上述非常相似的字符串中的字符数,但将 word 更改为 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 数组的大小相同。然而不同的是,如果你使结构数组更大,你可能应该将新的数组项初始化为 NULL。同样,如果您使结构数组更小,则需要在删除项目之前进行清理——即在调整结构数组大小之前已分配的空闲项目(并且只有分配的项目)。这是我建议创建辅助函数来帮助管理此问题的主要原因。

// 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);

【讨论】:

是的,不幸的是,当您熟悉 java 等不错的程序时,您又回到了使用 c 的旧时代。是的,我想分配下面我回复中的字符串。实际上我知道如何动态分配字符串中的字符。问题在于使用结构数组。 你丢弃了 realloc 的返回值。这是错误的:(a)realloc 可能会失败(返回 NULL),(b)realolc 可能会返回一个新指针,因为它必须移动数据。 鉴于调整大小是一种缩小操作,realloc() 不太可能移动数据。然而,正如您所建议的,认为 realloc() 不会移动数据是一个坏主意,尤其是在您扩大数组的情况下。 @Chris Young - 同意,我在 realloc 的原型上看得太快了,并认为它返回的是 void 而不是 void*。使用内存的返回值。【参考方案7】:

您在上次更新中的代码不应该编译,更不用说运行了。您将 &x 传递给 LoadData。 &x 具有 **words 的类型,但 LoadData 需要 words* 。当然,当您在指向堆栈的指针上调用 realloc 时,它会崩溃。

修复它的方法是将 LoadData 更改为接受单词**。这样摇摆,你实际上可以修改 main() 中的指针。例如,realloc 调用看起来像

*x = (words*) realloc(*x, sizeof(words)*2);

与“num”中的原理相同,它是 int* 而不是 int。

除此之外,您还需要真正弄清楚单词中的字符串是如何存储的。允许将 const 字符串分配给 char *(如 str2 = "marley\0"),但它很少是正确的解决方案,即使在 C 中也是如此。

另外一点:除非你真的需要在字符串末尾有两个 0,否则不需要有 "marley\0"。编译器在每个字符串文字的末尾添加 0。

【讨论】:

"允许将 const 字符串分配给 char *(如 str2 = "marley\0"),但它很少是正确的解决方案,即使在 C 中也是如此。"这是我知道的唯一解决方案,有没有比分配字符串值更好的解决方案? 您正在分配一个字符串常量。例如,可以使用 strdup 分配字符串值:str2 = strdup("marley")。这样,单词结构的所有者负责内存释放。我真的认为使用更宽容的语言会更好,例如 Python 甚至 Java【参考方案8】:

这是我在 C++ 中的做法

size_t size = 500;
char* dynamicAllocatedString = new char[ size ];

对任何结构或 c++ 类使用相同的主体。

【讨论】:

问题是关于 C 而不是 C++【参考方案9】:

对于测试代码:如果要修改函数中的指针,则应将“指向指针的指针”传递给函数。更正后的代码如下:

#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;

【讨论】:

只能改函数:void LoadData(words **y, int * num) words *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; *y= x; 【参考方案10】:

每个编码人员都需要简化他们的代码以使其易于理解......即使对于初学者也是如此。

如果您了解这些概念,动态使用结构数组很容易。

// 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;
   

【讨论】:

我认为这并没有解决问题的重点:在创建数组后更改数组的大小。

以上是关于如何定义一个动态的数组的主要内容,如果未能解决你的问题,请参考以下文章

C语言如何定义一个动态数组?

IDL中如何定义 动态数组?

如何使用 MPI 传输带有动态数组的自定义结构?

c语言动态数组如何扩充空间

C语言如何定义动态数组

C语言如何定义动态数组