我尝试寻找解决方案,但未能找到解决方案。是否可以返回一个字符串?我想将一个字符串从下面的函数传递回main。我想传递listofdeatils
字符串。
这是我的代码:
#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);
}
答案 0 :(得分:1)
试试这个:
void readFile(char listofdetails[6][40]);
int main()
{
char listofdetails[6][40];
readFile(listofdetails);
printf("%s \n", listofdetails[1]);
return 0;
}
void readFile(char listofdetails[6][40])
{
int i;
FILE *fp;
fp = fopen("specification.txt", "r");
for(i=0;i<6;i++)
{
fgets(listofdetails[i], 40, fp);
printf("%s \n", listofdetails[i]);
}
fclose(fp);
}
答案 1 :(得分:1)
所以只需返回字符串。显然,在函数中不要free()
。
而不是void
,您的函数可以返回char**
,或者您可以更改为分配所有字符的单个数组并将其索引为矩阵。
答案 2 :(得分:1)
有几个选择:
第一个选项 - 您可以直接返回listOfDetails
:
#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 );
}
}
这可能是你目前写的最直接的路径。请注意,在malloc
来电中,我使用sizeof *listOfDetails
和sizeof *listOfDetails[i]
。表达式*listOfDetails
的类型为char *
,因此sizeof *listOfDetails
等同于sizeof (char *)
。同样,表达式*listOfDetails[i]
的类型为char
,因此sizeof *listOfDetails[i]
等同于sizeof (char)
。
如果您决定更改listOfDetails
的类型,这有助于最大限度地减少维护难题。阅读IMO也更容易一些。
请注意,main
现在负责释放由readFile
分配的内存;理想情况下,您希望避免像这样分担内存管理责任,但有时它无法帮助您。
第二个选项 - 您可以将listOfDetails
作为参数传递给您的函数:
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
}
此选项与第一个选项之间没有太大区别,只是它增加了额外的间接级别(有些人会觉得这是令人反感的)。您仍然有共同的内存管理责任。请注意,表达式(*listOfDetails)[i]
中需要括号;我们不想直接下标listOfDetails
,我们想要下标指向的内容。由于[]
的优先级高于一元*
,因此我们必须明确地将运算符和操作数分组。
第三个选项 - 创建单独的函数来分配和释放内存,同时从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 );
}
这样,main
负责分配和解除分配数组。将内存管理代码分解为单独的函数有两个目的:一,它减少了main
中的混乱;二,它允许我们重用这段代码。假设您想要出于某种原因从多个文件中读取多个详细信息列表:
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 );
}
你也可以创建不同大小的列表(10条记录,每条80个字符,比方说),尽管你需要以某种方式将这些信息传递给readFile
函数(通常作为函数参数)。
这是有效的,因为您提前知道您的阵列需要多大。如果不提前知道您需要读取多少详细记录或每个明细行的最大长度,那么这种方法将不起作用,并且您将重新分配内存为你进入readFile
功能。
请注意,在这种情况下,我不希望readFile
修改listOfDetails
,因此我没有传递指向它的指针。
第四个选项 - 如果您的阵列大小固定且不是非常大(这里似乎就是这种情况),请不要理会动态内存管理。在main
中将其声明为常规数组,并将其作为参数传递给函数:
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.
...
}
优点:没有内存管理hijinks,没有多重解除引用等。主要缺点是它只能用于列数为DETAIL_LENGTH
的数组;例如,你不能用它来读取6x50阵列。如果您只使用一个阵列,这不是问题。
指针不知道它们是指向数组中的单个对象还是一系列对象,因此通常需要将行数指定为单独的参数。
您可以使用NUM_DETAILS
常量,但理想函数应该通过参数列表和返回值进行通信;他们不应该依靠全局变量或魔术常数间接地共享状态。这将函数与较大的程序“分离”,使其更容易重用。例如,我将您的readFile
函数定义为
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 );
}
此功能不依赖于任何共享信息;它可以很容易地被任何其他程序重复使用,或者用于在同一程序中读取不同大小的多个列表。
请注意,在所有四种情况下,我都用符号常量替换文字6
和40
。这有两个目的:首先,符号名称比原始数字更有意义;第二,如果您决定要阅读7个详细记录,或者记录现在需要80个字符长,那么您需要做的就是更改常量的定义 - 您不必深入挖掘代码并替换6
或40
的每个实例。
答案 3 :(得分:0)
您可以将功能修改为
char ** readFile()
然后在函数定义的末尾添加
return listofdetails;
如下所述,这项工作规定listofdetails
的大小是固定的,因此您可以编写一个释放已分配内存的对应函数。
答案 4 :(得分:0)
在C语言中,您应该将字符串视为字符的指针,继续终止&#39; \ 0&#39;字符。
然后你基本上有两种方法可以返回一个&#39;字符串&#39;主要的。
答案 5 :(得分:-3)
将字符串传递给函数并使用strcpy()将字符串复制到该字符串 另一种方法是返回字符串并使返回类型为char *