C结构体和结构体指针

3

我正在尝试使用指针来定义数组,而不是使用大小声明,因为我不知道一个地图可能有多少元素。尝试使用链表,但没有成功。如果这是一个报告,请原谅我。我是新手,如果看起来像个愚蠢的问题,请见谅。

#include<stdio.h>

typedef struct _keyValue
{
    char *key;
    char *value;
} _keyValue;

typedef struct _keyValues
{
    /* _keyValue keyValue[5];  - This works*/
    _keyValue *keyValue;
    int size;
} _keyValues;

_keyValues map;

main()
{
    map.keyValue[0].key     = "Key One";
    map.keyValue[0].value   = "Value One";

    map.keyValue[1].key     = "Key Two";
    map.keyValue[1].value   = "Value Two";

    map.size = 2;

    printf("Key: %s Value: %s", map.keyValue[0].key, map.keyValue[0].value);
}

请勿使用以下划线开头的名称;它们基本上是为“实现”保留的。 - Jonathan Leffler
此外,请在问题上更加具体;“尝试了链表但不成功”并不能为他人回答您的问题提供足够的信息。 - Eric Finn
3个回答

5

map.keyValue在你的示例中是一个未初始化的指针。你需要通过使用malloc来分配内存为数组提供存储空间。

main()
{
    map.keyValue = malloc(sizeof(*map.keyValue) * 2);
    map.size = 2;

    map.keyValue[0].key     = "Key One";
    map.keyValue[0].value   = "Value One";

您可以使用realloc来扩展数组。

int newMapSize = ...
_keyValue* temp = realloc(map.keyValue, sizeof(*map.keyValue) * newMapSize);
if (temp == NULL) {
    /* allocation failed.  Handle out of memory error and exit */
}
map.keyValue = temp;
map.size = newMapSize;
// map.keyValue[0..newMapSize-1] are now available

非常感谢。感激您的快速回复。 - Me Unagi
如果您要使用重新分配内存的方法,标准实现是在需要更多空间时将元素数量加倍。 - Benjamin Leinweber
1
是的,一种常见的方法是每次“realloc()”时将您的存储空间加倍。其他常见方法包括将存储空间增长1.5倍,或按固定或滑动元素数量增加。在任何情况下,哪种策略最好可能取决于诸如存储使用速度、增长率增加程度、元素大小等因素。在某些情况下,最好实施多种策略,并在运行时在它们之间进行选择。 - This isn't my real name

2
如果您不知道它们会有多大,那么请使用动态分配。这里的关键函数是mallocfree
以下是一个建议,如果您不知道它们会有多大,可以如何使用您的结构体:
首先在您的代码中包含以下内容:
#include <stdio.h>   /* for printf */ 
#include <string.h>  /* for strcpy, as you cannot directly assign strings to a malloc'd pointer */
#include <stdlib.h>  /* for malloc and free, for managing memory dynamically */

然后我们定义键和值的大小:
const int key_size   = 10; /* let's define how big our keys and values will be */
const int value_size = 25;

这里是如何使用你的结构体:
map.size = 30; /* decide how many keyValues we will have */

map.keyValue = malloc(sizeof(_keyValue) * map.size);   /* create storage big enough for 30 _keyValue structs
                                                        * malloc will allow you to assign memory to key and treat it as an array
                                                        * malloc assigns memory from the heap
                                                        * equal to the size specified (30), 
                                                        * this can be potentially as large as your computer's memory */

map.keyValue[0].key = malloc(sizeof(char) * key_size); /* let's create a key at position 0 */

strcpy(map.keyValue.key, "some key"); /* copying some values into key */

map.keyValue[0].value = malloc(sizeof(char) * value_size); /* let's create some space for a value for the 0th element */

strcpy(map.keyValue.value, "some value");


... /* you process and work with those values as you see fit */

free(map.keyValue[0]) /* malloc assigned memory needs to be returned to the OS as it's manually managed, 
                       * here we free the element at position 0 we created earlier
                       * if you have more than element here use a loop e.g: 
                       * for (int i = 0; i < map.size; i++) { free(map.KeyValue[i]) }
                       */


free(map.keyValue); /* free the keyValue itself that stored all the keyValue structs*/

一个提示,以下划线开头的声明不被推荐使用,因为它们被保留给语言使用。

1
#include <stdlib.h>

int main(void){
    map.size = 2;
    map.keyValue = malloc(sizeof(_keyValue)*map.size);

    map.keyValue[0].key     = "Key One";
    map.keyValue[0].value   = "Value One";

    map.keyValue[1].key     = "Key Two";
    map.keyValue[1].value   = "Value Two";


    printf("Key: %s Value: %s", map.keyValue[0].key, map.keyValue[0].value);

    return 0;
}

如果我不知道尺寸
#include <stdlib.h>
#include <string.h>

int main(void){
    char buff[128] = "";

    map.size = 5;//decide the size temporarily
    map.keyValue = malloc(sizeof(_keyValue)*map.size);

    int count = 0, retv;
    while(1){
        printf("input key : ");
        retv=scanf(" %127s", buff);
        if(retv != 1 || strcmp(buff, "end")==0) break;
        map.keyValue[count].key = strdup(buff);
        printf("input value : ");
        scanf(" %127s", buff);
        map.keyValue[count].value = strdup(buff);
        ++count;
        if(count == map.size)//full
            map.keyValue = realloc(map.keyValue, sizeof(_keyValue)*(map.size+=5));//increase the size
    }

    int i;
    for(i=0;i<count;++i)
        printf("Key: %s Value: %s\n", map.keyValue[i].key, map.keyValue[i].value);

    //dealloc
    for(i=0;i<count;++i){
        free(map.keyValue[i].key);
        free(map.keyValue[i].value);
    }
    free(map.keyValue);

    return 0;
}

你提供的代码看起来是正确的,但如果能额外解释一下改变了什么以及为什么改变会让它对OP更有价值。 - simonc
如果我不知道地图的大小,并使用循环来填充值,该怎么办? - Me Unagi
1
@MeUnagi,你和我(;-p)对simonc的解释很好。如果大小事先未知,可以通过realloc扩展当前保护区域的大小。 - BLUEPIXY

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接