【问题标题】:Using getchar() to store address of string literal in char*pointer使用 getchar() 将字符串文字的地址存储在 char*pointer 中
【发布时间】:2021-11-02 07:35:23
【问题描述】:

目标是将字符串litteral的地址存储在char*中,它是struct的成员 ID。我考虑过使用数组。 数组的问题是,如果我将最大字符数设置为 7,用户 可能输入小于7,所以会浪费内存。 使用 getchar() 的好处是我可以将 char 的最大值设置为 7,但如果用户输入较少,那也没关系。

    typedef struct id
    {
    int age;
    char* name;
    }id;

    id Mary;

    char L;
    int c =0;

    printf("Enter your age: ");
    scanf("%d",&Mary.age);

    printf(" Enter your name: );

    if(  (L=getchar() != '\n'    )
    {
    // stroring string litteral in char*
 
    }


    printf("%s", Mary.name);       

【问题讨论】:

  • 我不太明白您的问题是什么,但您需要在某处收集数据。目前你不这样做,所以你会得到内存故障。不同寻常的是,您会收集到某个大小 char[256] 的本地堆栈变量/数组中,然后在知道大小后将其分配 & strcpy 到您的最终结构。
  • 这个问题的问题是你使用了“字符串文字”这个词。用户输入是字符串variable,而不是literalen.wikipedia.org/wiki/Literal_(computer_programming)。这让你很不清楚你实际上在问什么。
  • 是的,谢谢
  • 旁白:“字面意思”是指某物在其自身的文本中进行了描述。字符串文字 "abc" 包含字符 a、b 和 c,因为这些字母位于字符串文字的源文本中。 char *name; 不是文字,因为我们将在 name 中存储任意字符,而不是其文本中的字符 n、a、m 和 e。它只是一个字符串,而不是字符串文字。

标签: c pointers getchar


【解决方案1】:

对于这类问题没有灵丹妙药的解决方案。 您的选择是:

  • 使用具有最大长度的数组 - 但正如您所提到的,如果用户输入较短的长度,这可能会造成浪费。尽管如此,这通常是您在实际代码中会找到的解决方案 - 实际上,如果内存不是一个大问题,这比尝试处理涉及内存分配的其他动态解决方案更快、更简单。

  • 在用户输入姓名之前询问用户姓名的长度 - 然后您可以使用char* name = malloc(input_length);char name[input_length] 动态分配适当大小的缓冲区;在 C99+ 中。你也可以做一个灵活的数组成员之类的事情:

    struct name {
          size_t length;
          char buffer[];
    };
    
    struct name* username = malloc(sizeof(*username) + username_length);
    
  • 如果您不想询问用户用户名的长度,您可以在每个新的getchar 之后执行一系列realloc 调用,这将调整动态分配的数组的大小 - 但这是一个糟糕的主意除非您对程序中消耗的每个内存字节感到压力,否则您甚至不应该考虑这一点。

【讨论】:

    【解决方案2】:

    这是一个常见问题:“如何读取未知长度的输入字符串?” Daniel Kleinstein 在他的回答中提到了几个通用解决方案。我会在这里给出一个更基于实现的答案

    首先,您的程序不会尝试存储string literal,而是从输入流中读取的字符串(例如stdin)。 其次,不可能将字符串存储在“char*”中。该字符串存储在char* 指向的内存中。需要先分配这块内存。

    以下代码最接近您想要执行的操作。它一次读取一个字符,每次复制到的内存大小增加 1 个字节。

    #include <stdbool.h>
    #include <stdio.h>
    #include <stdlib.h>
    
    typedef struct
    {
        int age;
        char *name;
    } Id;
    
    int main(void)
    {
        Id mary;
    
        printf(" Enter your name: ");
    
        size_t nameSize = 0U;
        mary.name = NULL;
        while (true)
        {
            mary.name = (char*) realloc(mary.name, ++nameSize); // cast is optional
            if (mary.name == NULL)
            {
                printf("Memory allocation error\n");
                exit(EXIT_FAILURE);
            }
    
            int ch = getchar(); // Note the `int` type, necessary to detect EOF
            if (ch == '\n' || ch == EOF)
            {
                mary.name[nameSize - 1] = '\0';
                break;
            }
    
            mary.name[nameSize - 1] = (char) ch;
        }
    
        printf("%s\n", mary.name);
    
        free(mary.name);
    }
    

    这不会浪费一个字节的内存,但是,频繁的内存重新分配会使这段代码变慢。一个好的折衷方案是一次读取一个固定长度的字符串,而不是一次读取一个字符。
    在实践中这样做:在固定长度的堆栈上创建一个缓冲区(例如 64 个字符),使用fgets 读入该缓冲区,并将该内容复制到mary.name。如果字符串不适合缓冲区,请再次重复调用fgets,重新分配mary.name,并将缓冲区的内容附加到mary.name,直到找到换行符为止。

    另一个更简单的解决方案是为字符串设置最大长度,为该长度分配内存,读取最大长度的字符串,最后将内存重新分配到(可能更小)字符串的实际大小。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-04-11
      • 2012-02-28
      • 1970-01-01
      • 1970-01-01
      • 2011-03-28
      相关资源
      最近更新 更多