如何通过从功能到主字符串? [英] How to pass a string from a function to main?

查看:88
本文介绍了如何通过从功能到主字符串?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图寻找一个解决方案,但没有能够找到一个。是否有可能返回一个字符串?我想通过一个字符串从功能回到低于主。我想通过 listofdeatils 字符串。

下面是我的code:

 的#include<&stdio.h中GT;
#包括LT&;&stdlib.h中GT;
#包括LT&;&string.h中GT;无效ReadFile的();诠释的main()
{
    ReadFile的();
    的getchar();
    的printf(%S \\ n,l​​istofdetails [1]);
    的getchar();    返回0;
}无效ReadFile的()
{
    INT I;
    FILE * FP;
    FP = FOPEN(specification.txt,R);    焦炭** listofdetails;
    listofdetails =的malloc(sizeof的(字符*)* 6);    对于(I = 0; I&10 6;我+ +)
    {
        listofdetails [I] =的malloc(sizeof的(字符)* 40);
        与fgets(listofdetails由[i],40,FP);
        的printf(%S \\ n,l​​istofdetails [I]);
        免费(listofdetails [I]);
    }    免费(listofdetails);
    FCLOSE(FP);
}


解决方案

有几个选项:

第一种选择 - 你可以返回 listOfDetails 直接

 的#define NUM_DETAILS 6
#定义DETAIL_LENGTH 40
...
焦炭** ReadFile的(无效)
{
  焦炭** listOfDetails =
    的malloc(sizeof的* listOfDetails * NUM_DETAILS); //注意的sizeof操作  如果(listOfDetails)
  {
    ...
    listOfDetails [I] =
      的malloc(sizeof的* listOfDetails [I] * DETAIL_LENGTH); //注意的sizeof操作
    ...
  }  返回listOfDetails;
}INT主要(无效)
{
  ...
  焦炭**细节= ReadFile的();
  如果(详细信息)
  {
     ...    的for(int i = 0; I< NUM_DETAILS;我++)
    {
      免费(详细信息[I]);
    }
    免费(详细信息);
  }
}

这可能是从你现在写什么最直的路。请注意,在的malloc 电话,我用的sizeof * listOfDetails 的sizeof * listOfDetails [我] 。该类型前pression的 * listOfDetails 的char * ,所以的sizeof * listOfDetails 等同于的sizeof(字符*)。同样,前pression类型 * listOfDetails [I] 字符,所以的sizeof * listOfDetails [I] 等同于的sizeof(char)的

这有助于最大限度地减少维护问题,如果你决定更改 listOfDetails 的类型。这也是一个比较容易阅读IMO

注意现在负责释放由 READFILE 分配的内存;理想情况下,你想避免共享内存管理责任这样,但有时不能得到帮助。

二选 - 你可以通过 listOfDetails 作为参数传递给你的函数:

 无效READFILE(CHAR *** listOfDetails)//注意间接的额外级别
{
   ...
   * listOfDetails =的malloc(sizeof的** listOfDetails * NUM_DETAILS);
   如果(* listOfDetails)
   {
     ...
     (* listOfDetails)[我] =
       的malloc(sizeof的*(* listOfDetails)[我] * DETAIL_LENGTH); //需要括号!
     ...
   }
}INT主要(无效)
{
  焦炭** listOfDetails
  ...
  READFILE(安培; listOfDetails); //注意&安培;运营商;我想READFILE修改的值
                              //存储在listOfDetails,所以我必须通过
                              //指向它;自listOfDetails的类型
                              //为char **,结果指针将会有型
                              //炭***,这是在申报看出
                              // READFILE以上。
  ...
  //自由如上
}

有没有一吨这个选项和第一,但它增加了额外的间接水平(其中有些人会觉得反感)之间的差异。你还是共享内存管理责任。请注意,括号中的前pression要求(* listOfDetails)[我] ;我们不希望下标 listOfDetails 直接,我们希望下标什么的的。由于 [] 具有较高的precedence比一元 * ,我们必须明确地组符和操作数。

第三选项 - 创建独立的功能来分配和释放内存,通话双方从

 的char ** createDetailList(为size_t numDetails,为size_t detailLength)
{
  焦炭**细节=的malloc(sizeof的*详情* numDetails);
  如果(详细信息)
  {
    用于(为size_t我= 0; I< NUM_DETAILS;我++)
    {
      细节[I] =的malloc(sizeof的*详情请[我] * detailLength);
    }
  }
  返回细节;
}无效freeDetailList(字符** detailList,为size_t numDetails)
{
  用于(为size_t我= 0; I< numDetails;我++)
    免费(detailList [I]);
  免费(detailList);
}无效ReadFile的(字符** listOfDetails)
{
  ...
  FREAD(listOfDetails [I],DETAIL_LENGTH,FP);
  ...
}INT主要(无效)
{
  焦炭** listOfDetails = createDetailList(NUM_DETAILS,DETAIL_LENGTH);
  ...
  READFILE(listOfDetails); //注意没有和放大器;操作者在这种情况下
  ...
  freeDetailList(listOfDetails,NUM_DETAILS);
}

这样,同时负责分配和释放该数组。打破了内存管理code成单独的功能有两个目的:一,它减少杂波;二,它让我们重新使用这个code。假设你想读的多个文件的详细信息因某种原因多个列表:

  INT主要(无效)
{
   焦炭** list1的= createDetailList(NUM_DETAILS,DETAIL_LENGTH);
   焦炭**列表2 = createDetailList(NUM_DETAILS,DETAIL_LENGTH);
   ...
   READFILE(list1的FILE1.TXT); //请注意,我们传递文件的名称
   READFILE(列表2FILE2.TXT); //作为参数; ReadFile的定义
                                   //将需要相应地改变。
   ...
   freeDetailList(list1的,NUM_DETAILS);
   freeDetailList(列表2,NUM_DETAILS);
}

您还可以创建不同大小的名单(10个记录的每80个字符,说),但你需要以某种方式传达信息给 READFILE 函数(通常作为函数参数)。

这工作,因为你知道时间提前阵列需要多大是。如果你的的提前知道的时候你需要多少详细记录读取或每一个细节行的最大长度,那么这种做法是行不通的,而你又回到了分配内存您在 READFILE 函数去。

请注意,在这种情况下,我不指望 READFILE 修改 listOfDetails ,所以我不传递一个指向它的指针。

第四个选项 - 如果您的数组的大小是固定而不是非常大(这似乎是这里的情况),不与动态内存管理麻烦的。在声明它作为一个普通数组,并将其传递给函数作为参数:

 无效READFILE(CHAR(* listOfDetails)DETAIL_LENGTH],为size_t numDetails)//或字符listOfDetails [] [DETAIL_LENGTH]
{
  ...
  对于(i = 0; I< numDetails;我++)
  {
    与fgets(listofdetails [I],DETAIL_LENGTH,FP);
    的printf(%S \\ n,l​​istofdetails [I]);
  }
  ,,,
}INT主要(无效)
{
  焦炭细节[NUM_DETAILS] [DETAIL_LENGTH];
  ...
  READFILE(详细信息,NUM_DETAILS); //注意没有和放大器;运营商;当一个数组前pression
                                    //出现在大多数情况下,它将会被转换
                                    //(衰变)的指针的第一个元素。
                                    //在这种情况下,细节将被转换为一个
                                    //指向一个字符数组,你可以看到在
                                    // ReadFile函数的声明。
                                    //请注意,我也路过的行数
                                    //明确。
  ...
}

优点:无内存管理hijinks,没有多重指针引用等,主要缺点是,它只能使用数组,其中列数为 DETAIL_LENGTH ;你不能用它来阅读一个6x50阵列,例如。如果你只使用一个阵列,这是没有问题的。

指针不知道他们是否是指向一个对象或对象在数组中的顺序,所以通常需要指定的行数作为一个单独的参数。

您可以使用 NUM_DETAILS 不变,但的理想的职能应该完全通过参数列表沟通和返回值;他们不应该依靠全局变量或常量魔术间接共享状态。这个去耦合从更大的程序的功能,使得它更易于重复使用。例如,我会定义你的 READFILE 功能

 无效READFILE(字符** listOfDetails,
               为size_t numDetails,
               为size_t detailLength,
               为const char *文件名)
{
  FILE *计划生育=的fopen(文件名,R);
  如果(FP)
  {
    用于(为size_t我= 0; I< numDetails;我++)
    {
      FREAD(listOfDetails [I],detailLength,FP); //没有错误为了简洁检查
    }
  }
  FCLOSE(FP);
}

这个功能不依赖任何共享信息;它可以很容易地被重新使用的任何其他程序,或用于在同一程序来读取不同尺寸的多个列表。

请注意,在所有四种情况下,我用符号常量替换文字 6 40 。这有两个目的:第一,符号名比原始数据更有意义;第二,如果你决定要读7明细记录,或者记录现在需要80个字符长,所有你需要做的是改变常量的定义 - 你不必通过$ C $挖c和替换 6 的每个实例或 40

I tried looking for a solution but wasn't able to find one. Is it possible to return a string? I want to pass a string back from the function below to main. I want to pass the listofdeatils string.

Here's my code:

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

void readFile();

int main()
{
    readFile(); 
    getchar();
    printf("%s \n", listofdetails[1]);
    getchar();

    return 0;
}

void readFile()
{
    int i;
    FILE *fp;
    fp = fopen("specification.txt", "r");

    char ** listofdetails; 
    listofdetails = malloc(sizeof(char*)*6);

    for(i=0;i<6;i++)
    {
        listofdetails[i] = malloc(sizeof(char)*40);
        fgets(listofdetails[i], 40, fp);
        printf("%s \n", listofdetails[i]);
        free(listofdetails[i]);
    }

    free(listofdetails);
    fclose(fp);
}

解决方案

Several options:

First option - you could return listOfDetails directly:

#define NUM_DETAILS    6
#define DETAIL_LENGTH 40
...
char **readFile( void )
{
  char **listOfDetails = 
    malloc( sizeof *listOfDetails * NUM_DETAILS ); // note operand of sizeof

  if ( listOfDetails )
  {
    ...
    listOfDetails[i] = 
      malloc( sizeof *listOfDetails[i] * DETAIL_LENGTH ); // note operand of sizeof
    ...
  }

  return listOfDetails;
}

int main( void )
{
  ...
  char **details = readFile();
  if ( details )
  {
     ...

    for ( int i = 0; i < NUM_DETAILS; i++ )
    {
      free( details[i] );
    }
    free( details );
  }
}

This is probably the straightest path from what you currently have written. Note that in the malloc calls, I use sizeof *listOfDetails and sizeof *listOfDetails[i]. The type of the expression *listOfDetails is char *, so sizeof *listOfDetails is equivalent to sizeof (char *). Similarly, the type of the expression *listOfDetails[i] is char, so sizeof *listOfDetails[i] is equivalent to sizeof (char).

This helps minimize maintenance headaches if you ever decide to change the type of listOfDetails. It's also a little easier to read IMO.

Note that main is now responsible for freeing the memory allocated by readFile; ideally, you'd like to avoid sharing memory management responsibility like this, but sometimes it can't be helped.

Second option - you could pass listOfDetails as an argument to your function:

void readFile( char ***listOfDetails ) // note extra level of indirection
{
   ...
   *listOfDetails = malloc( sizeof **listOfDetails * NUM_DETAILS );
   if ( *listOfDetails )
   {
     ...
     (*listOfDetails)[i] = 
       malloc( sizeof *(*listOfDetails)[i] * DETAIL_LENGTH ); // parens are required!
     ...
   }
}

int main( void )
{
  char **listOfDetails
  ...
  readFile( &listOfDetails ); // note & operator; I want readFile to modify the value
                              // stored in listOfDetails, so I must pass a 
                              // pointer to it; since the type of listOfDetails
                              // is char **, the resulting pointer will have type
                              // char ***, which is seen in the declaration of
                              // readFile above.
  ...
  // free as above
}

There isn't a ton of difference between this option and the first, except that it adds an extra level of indirection (which some people will find objectionable). You still have shared memory management responsibility. Note that the parentheses are required in the expression (*listOfDetails)[i]; we don't want to subscript listOfDetails directly, we want to subscript what it points to. Since [] has higher precedence than unary *, we have to explicitly group operators and operands.

Third option - Create separate functions to allocate and free the memory, call both from main:

char **createDetailList( size_t numDetails, size_t detailLength )
{
  char **details = malloc( sizeof *details * numDetails );
  if ( details )
  {
    for ( size_t i = 0; i < NUM_DETAILS; i++ )
    {
      details[i] = malloc( sizeof *details[i] * detailLength );
    }
  }
  return details;
}

void freeDetailList( char **detailList, size_t numDetails )
{
  for ( size_t i = 0; i < numDetails; i++ )
    free( detailList[i] );
  free( detailList );
}

void readFile( char **listOfDetails )
{
  ...
  fread( listOfDetails[i], DETAIL_LENGTH, fp );
  ...
}

int main( void )
{
  char **listOfDetails = createDetailList( NUM_DETAILS, DETAIL_LENGTH );
  ...
  readFile( listOfDetails ); // note no & operator in this case
  ...
  freeDetailList( listOfDetails, NUM_DETAILS );
}

This way, main is responsible for both allocating and deallocating the array. Breaking the memory management code out into separate functions serves two purposes: one, it reduces clutter in main; two, it allows us to re-use this code. Suppose you wanted to read multiple lists of details from multiple files for some reason:

int main ( void )
{
   char **list1 = createDetailList( NUM_DETAILS, DETAIL_LENGTH );
   char **list2 = createDetailList( NUM_DETAILS, DETAIL_LENGTH );
   ...
   readFile( list1, "file1.txt" ); // Note that we're passing the name of the file
   readFile( list2, "file2.txt" ); // as an argument; the definition of readFile
                                   // will need to change accordingly.
   ...
   freeDetailList( list1, NUM_DETAILS );
   freeDetailList( list2, NUM_DETAILS );
}

You could also create lists of different sizes (10 records of 80 characters each, say), although you'd need to convey that information to the readFile function somehow (usually as function arguments).

This works because you know ahead of time how big your array needs to be. If you don't know ahead of time how many detail records you need to read or the maximum length of each detail line, then this approach won't work, and you're back to allocating memory as you go in the readFile function.

Note that in this case, I don't expect readFile to modify listOfDetails, so I'm not passing a pointer to it.

Fourth option - if your array is fixed in size and not terribly big (which seems to be the case here), don't bother with dynamic memory management at all. Declare it in main as a regular array and pass it to the function as an argument:

void readFile( char (*listOfDetails)[DETAIL_LENGTH], size_t numDetails ) // or char listOfDetails[][DETAIL_LENGTH]
{
  ...
  for(i=0;i<numDetails;i++)
  {
    fgets(listofdetails[i], DETAIL_LENGTH, fp);
    printf("%s \n", listofdetails[i]);
  }
  ,,,
}

int main( void )
{
  char details[NUM_DETAILS][DETAIL_LENGTH];
  ...
  readFile( details, NUM_DETAILS ); // note no & operator; when an array expression
                                    // appears in most contexts, it will be converted
                                    // ("decay") to a pointer to the first element.  
                                    // In this case, details will be converted to a
                                    // pointer to an array of char, as you can see in
                                    // the declaration of the readFile function.
                                    // Note that I'm also passing the number of rows 
                                    // explicitly.
  ...
}

Advantages: no memory management hijinks, no multiple dereferences, etc. The main drawback is that it can only work with arrays where the number of columns is DETAIL_LENGTH; you can't use it to read a 6x50 array, for example. If you're only using the one array, this isn't a problem.

Pointers don't know whether they're pointing to a single object or a sequence of objects in an array, so you usually need to specify the number of rows as a separate parameter.

You could use the NUM_DETAILS constant, but ideally functions should communicate exclusively through parameter lists and return values; they should not share state indirectly by relying on global variables or magic constants. This "decouples" the function from the larger program, making it easier to reuse. For example, I'd define your readFile function as

void readFile( char **listOfDetails, 
               size_t numDetails, 
               size_t detailLength, 
               const char *filename )
{
  FILE *fp = fopen( filename, "r" );
  if ( fp )
  {
    for( size_t i = 0; i < numDetails; i++ )
    {
      fread( listOfDetails[i], detailLength, fp ); // no error checking for brevity
    }
  }
  fclose( fp );
}

This function doesn't rely on any shared information; it can easily be re-used by any other program, or used to read multiple lists of different sizes in the same program.

Note that in all four cases I replace the literals 6 and 40 with symbolic constants. This serves two purposes: first, the symbol names are more meaningful than the raw numbers; second, if you decide you want to read 7 detail records, or that the records now need to be 80 characters long, all you need to do is change the definition of the constants - you don't have to dig through the code and replace every instance of 6 or 40.

这篇关于如何通过从功能到主字符串?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆