【问题标题】:how do i use pointers for storing multiple strings using malloc如何使用指针使用 malloc 存储多个字符串
【发布时间】:2019-01-04 11:50:43
【问题描述】:

我试图制作一个程序来动态分配内存以使用指针存储多个字符串,但它似乎无法正常工作。

#include <stdio.h>
#include<conio.h>

void main()
{
    FILE *fp;
    int num;

    printf("enter no of students");
    scanf("%d",&num);
    char *names = (char*) malloc(num * 100 * sizeof(char));

    printf("enter the names");
    fp = fopen("file.txt","w");

    for (int i = 0; i < num; i++)
    {
        fgets(*(names + i * 100), 100, stdin);
        fprintf(fp, "%s\n", (names + i * 100));
    }

    fclose(fp);

    fp = fopen("file.txt", "r");
    printf("names stored in *ptr");
}

【问题讨论】:

  • 您只分配了一个数组。我相信您需要一个 char **names 变量,然后分配 100 个 100 个空格的数组...或者,您可以在读取输入时重用该数组...

标签: c string pointers malloc file-handling


【解决方案1】:

你有几个问题。首先scanf 不能很好地与fgets 配合使用——它会在输入流中留下一个换行符,这意味着当你调用fgets 时它只会读取它。解决这个问题的最简单方法是在询问学生人数时使用fgets 读取整行,并使用sscanf 获取实际人数,如下所示:

char temp[100];
fgets(temp,100,stdin);
sscanf(temp,"%d",&num);

其次,您只创建了一个非常大的长字符串,而不是多个字符串。因此,要创建num 字符串,您首先要分配这样的字符串“数组”

names=malloc(sizeof(char *)*num);

然后使用循环为字符串分配空间

for(int i=0; i<num; i++)
{
     names[i]=malloc(100);
} 

您还会看到不需要从malloc 转换返回值,但您确实需要包含正确的文件,即“stdlib.h”。从技术上讲,您不需要sizeof(char),因为它始终是 1。

你不检查来自fopen的返回值,所以你不处理它无法打开文件进行写入的情况。

不知道为什么你最后还要打开文件进行阅读,因为你没有对它做任何事情,它只会在程序结束时自动关闭。

而且您应该始终养成编写代码以释放分配的内存的习惯,即使您不需要这样做,因为代码就是这么简单。

从技术上讲,main 应该返回 int

代码的最终版本可能如下所示:

#include <stdio.h>
#include <stdlib.h>

int main()
{
    FILE *fp;
    int num;
    char temp[100];

    printf("enter no of students");
    fgets(temp,100,stdin);
    sscanf(temp,"%d",&num);
    char **names=malloc(num*sizeof(char*));


    printf("enter the names");
    fp=fopen("file.txt","w");
    if(fp==NULL)
    {
        printf("Failed to open\n");
        return 1;
    }
    for(int i=0;i<num;i++)
    {
        names[i]=malloc(100);
        fgets(names[i],100,stdin);
        fprintf(fp,"%s\n",names[i]);
    }
    fclose(fp);

    for(int i=0;i<num;i++)
    {
        free(names[i]);
    }
    free(names);

    printf("names stored in *ptr");
}

【讨论】:

    【解决方案2】:

    您需要有一个指向字符的指针表。

    char **strtable = NULL
    size_t nstrings = 0; 
    
    int addstring(const char *str)
    {
        int result = -1;
        char **tmp = realloc(strtable, (nstrings + 1)* sizeof(*strtable));
    
        if(tmp)
        {
            tmp[nstrings] = malloc(strlen(str) + 1);
            if(tmp[nstrings])
            {
                result = 0;
                strtable = tmp;
                strcpy(tmp[nstrings++], str);
            }
        }
        return result;
    }
    

    使用它,您可以添加输入(读取)的字符串并轻松迭代。

    【讨论】:

    • 他知道学生的数量,因此他不必在每次调用时低效地重新分配:scanf("%d",&amp;num);。他也不需要单独的函数来执行此操作:只需将其合并到他的 main 中即可。
    • strlen(string) ==> strlen(str)
    • @PaulOgilvie 1. 我给他指路,而不是给出地球上最有效的代码。在这种情况下,realloc 的 BTW 效率低于边际。 2. C 是过程语言,将所有内容都包含在 main 中是一个非常糟糕的习惯。也许你的程序有一个庞大的 50000 行 main 并且根本没有函数,但这不是要效仿的例子。我认为你的评论是挑剔
    • @4386427 是的,你说得对,所以最终可能会有一个普通的代码编辑器。是时候进入 21 世纪了
    • @P__J__ 不知道你为什么给我写这个评论。我不做 SO UI。我只是帮你改进了你的答案。
    【解决方案3】:

    最简单的方法是将names 声明为“指向100 个字符的数组的指针”并仅使用一个malloc。之后,您可以使用names[i] 访问个人姓名。

    像这样:

    char (*names)[100] = malloc(num * sizeof *names);
    
    printf("enter the names\n");
    fp = fopen("file.txt","w");
    
    for (int i = 0; i < num; i++)
    {
        fgets(names[i], 100, stdin);
        fprintf(fp, "%s", names[i]);
    }
    
    fclose(fp);
    

    一些额外的cmets:

    1) sizeof(char) 始终为 1

    2) 请注意scanf("%d",&amp;num); 将在输入缓冲区中留下一个换行符。这会导致您的名字为空。您需要在扫描名称之前删除该换行符

    3) 另请注意,fgets 将包含换行符(至少在输入少于 99 个字符时)。

    4) 似乎您并不需要在将所有名称立即写入文件时将它们存储在数组中。所以你可以简单地这样做:

    printf("enter the names\n");
    fp = fopen("file.txt","w");
    
    for (int i = 0; i < num; i++)
    {
        char name[100];
        fgets(name, 100, stdin);
        fprintf(fp, "%s", name);
    }
    
    fclose(fp);
    

    【讨论】:

      【解决方案4】:

      我同意上面的答案,但如果你想保持相同的结构,你可以去

          #include<stdio.h>
          #include<conio.h>
          void main()
          {
          FILE *fp;
          int num;
      
          printf("enter no of students ");
          scanf("%d",&num);
          char *names=malloc(num*100);
      
      
          printf("enter the names\n");
          fp=fopen("file.txt","w");
                      fseek(stdin,0,SEEK_END);
      
          for(int i=0;i<num;i++)
          {
      
          fgets((names + i * 100), 100, stdin);
          fprintf(fp, "%s", (names + i * 100));
              fseek(stdin,0,SEEK_END);
          }
          fclose(fp);
      
          fp=fopen("file.txt","r");
          printf("names stored in *ptr");
          fclose(fp);
          }
      

      【讨论】:

      • 1) 请正确缩进代码。 2) 为什么使用fseek
      • 我在第一次输入'num'后使用fseek正确清除了stdin缓冲区
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-05-18
      • 2010-11-10
      • 1970-01-01
      • 2020-09-30
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多