【问题标题】:How can I malloc typedef structs in c?如何在 c 中 malloc typedef 结构?
【发布时间】:2021-06-28 14:36:10
【问题描述】:

我们的老师要求我们制作一个视频俱乐部菜单,他给了我们这些结构供我们使用:

typedef struct date
{
    int day, month, year;
}date;


typedef struct directorInfo
{
    const char* directorSurname;
    const char* directorName;
}directorInfo;


typedef struct movie
{
    int id;
    const char* title;
    directorInfo* director;
    date* releaseDate;
}movie;

我很困惑,我不知道如何分配其中的每一个。 这就是我所做的:

int main() 
{
    
    int totalMovies = 50;
    
    movie *movie_ptr = (movie*)malloc( totalMovies * sizeof(movie) );                               
    date *date_ptr = (date*)malloc( totalMovies * sizeof(date) );                                   
    directorInfo *directorInfo_ptr = (directorInfo*)malloc( totalMovies * sizeof(directorInfo) );   
    
    
    
    movie_ptr->title = (char*)malloc( 200 * sizeof(char) );                                                     
    directorInfo_ptr->directorName = (char*)malloc( 200 * sizeof(char) );
    
    movie_ptr[0].director->directorName = "John";

    printf("%s", movie_ptr[0].director->directorName);

有没有更快、更专业的方法?我觉得这一切都错了,而且当我尝试打印 directorName 时它不会打印任何东西。 (我很抱歉这里的任何高级编码人员看到此代码并睁大眼睛)

【问题讨论】:

  • 没有 typedef 结构这样的东西
  • 为什么不呢? @user253751 我用过好几次了
  • 这同样适用于 C++ 和 C:核心语言几乎不会为您做任何事情。您必须完成所有工作,并编写所有代码来完成它。 C 和 C++ 在某处都没有捷径,只需要使用它就可以使一切发生。如果您必须 malloc 几个不同的对象,并且每个对象都有指针,而这些指针本身也必须依次为 malloced,那么必须编写执行此操作的代码。
  • 详细说明...“typedef struct”不是一个术语。它是两个连续的关键字,每个关键字都有自己的效果。任何一个的存在都不会影响另一个的行为。所以“typedef struct”没有传达任何有意义的东西。
  • 通常你可以使用一个函数来为你做这件事(显然你必须自己写)

标签: c struct malloc typedef


【解决方案1】:

除非您将此代码编译为 C++ 或使用古老的 K&R C 实现,否则您可以放弃 malloc 调用的强制转换 - 省去一些混乱和维护方面的麻烦。此外,您可以将目标用作 sizeof 操作数:

movie *movie_ptr = malloc( totalMovies * sizeof *movie_ptr );      

由于表达式 *movie_ptr 的类型是moviesizeof *movie_ptr == sizeof (movie)1。当movie_ptr 的声明与实际的malloc 调用分开时,这尤其有用:

movie *movie_ptr;

// a bunch of code here

movie_ptr = malloc( totalMovies * sizeof *movie_ptr );

这样您就不必不断重复类型名称,从而使维护更容易。

现在,至于更大的问题——如何更好地组织你的代码来解决这类问题——这里有一些建议:

我将首先将读取、分配和分配数据到不同类型的逻辑抽象到单独的函数中。

例如,有一个专门用于从标准输入流中读取日期的函数:

int getDate( int *day, int *month, int *year )
{
  int success = 1;

  printf( "Release year: " );  
  if ( scanf( "%d", year ) != 1 )  // this is the barest minimum level
    success = 0;                   // of error handling, but it's better than nothing
  ...
  return success;
}

然后有另一个函数来获取该数据并分配一个date 对象:

date *createDate( int day, int month, int year )
{
  date *d = malloc( sizeof *d );
  /**
   * ALWAYS check the result of malloc, calloc, or realloc before attempting
   * to use the pointer, since they will return NULL if they cannot 
   * satisfy the request.
   */
  if ( d ) // or if ( d != NULL )
  {
    d->day = day;
    d->month = month;
    d->year = year;
  }
  return d;
}

然后在您的主代码中,您可以这样称呼它们:

int day, month, year;
date *d = NULL;

if ( getDate( &day, &month, &year ) )
  d = createDate( day, month, year );

也可以将这些操作组合到第三个函数中:

date *dateFromStdInput( void )
{
  int day, month, year;
  date *d = NULL;

  if ( getDate( &day, &month, &year ) )
    d = createDate( day, month, year );

  return d;
}

然后在你的主代码中调用:

date *d = dateFromStdInput();

I/O 和内存分配是完全独立的操作,因此通常您希望编写单独的函数来处理每个操作,这样您就可以更改其中一个而不影响另一个。这需要一些深谋远虑,但最终它使代码更易于维护和更新。

为你的导演信息做类似的事情,然后你可以像这样创建一个新的movie对象:

date *d = dateFromStdInput();
directorInfo *dir = dirFromStdInput();

char title[MAX_TITLE_LEN + 1];

/**
 * Make sure we have successfully read title, director, and date info
 * before we attempt to create a new movie object:
 */
if ( fgets( title, sizeof title, stdin ) && dir && d )
{
  movie *m = createMovie( title, dir, d );
}

“但是,”你说,“我想创建一个 array 电影。”好吧,你可以做的是创建一个 pointersmovie 的数组,然后为每个元素分配一个新的movie 对象:

movie **m = malloc( totalMovies * sizeof *m ); // sizeof *m == sizeof (movie *)
if ( m )
{
  for ( int i = 0; i < totalMovies; i++ )
  {
    date *d = dateFromStdInput();
    director *dir = dirFromStdInput();
    char title[MAX_TITLE_LEN+1];

    if ( fgets( title, sizeof title, stdin ) && dir && d )    
      m[i] = createMovie( title, dir, d );
  }
}

要解除分配,您需要编写一个单独的解除分配函数,该函数知道如何以正确的顺序解除分配:

void freeMovie( movie *m )
{
  free( m->releaseDate );
  free( m->director->name );
  free( m->director->surname );
  free( m->director );
  free( m->title );
  free( m );
}
  

再次,这些是我脑海中的建议;毫无疑问,有更好的方法来构建这段代码,但无论如何它应该能让你开始。


  1. 记住sizeof是一个操作符,而不是一个函数;仅当操作数是 intmovie 之类的类型名称时才需要括号。添加它们并没有什么坏处; sizeof (*movie_ptr) 将以相同的方式工作。但同样,它节省了一些混乱。

【讨论】:

  • 次要:if ( fgets( title ) &amp;&amp; dir &amp;&amp; d )if ( dir &amp;&amp; d &amp;&amp; fgets( title ) ) 更好,以免在之前的分配失败时尝试输入。
  • @chux-ReinstateMonica:修复了fgets 电话。我会责怪睡眠不足。
【解决方案2】:

结构的内存分配,嵌套结构,需要遵循最顶层结构的分配,如果它们是指针,则深入到嵌套结构内存未分配在这种情况下,每个结构指针都需要分配显式记忆,例如在您的情况下是这样的

以下代码将分配structures 类型为movieun-initialized array

// this created/allocates an array of 50 movies
movie *m = malloc( sizeof(movie) * 50);

// for each movie m[i]
for (int i = 0; i < 50; ++i)
{
    m[i].title = malloc( sizeof(char) * 128 ); // say title size is 128 characters;
    m[i].director = malloc( sizeof(director));
    m[i].director->directorName = malloc( sizeof(char) * 128 );
    m[i].director->directorSurname = malloc( sizeof(char) * 128 );
    m[i].releaseDate = malloc( sizeof(date));
} // repeat for others

释放也遵循相反的路径,首先释放所有结构元素,然后释放实际结构,例如

// Free loop

for (int i = 0; i < 50; ++i)
{
    free(m[i].releaseDate);
    free(m[i].directorName->directorName);
    free(m[i].directorName->directorSurname);
    free(m[i],director);
    free(m[i]);
} // repeat for others

free(m);

【讨论】:

    猜你喜欢
    • 2020-03-22
    • 1970-01-01
    • 2013-03-29
    • 2018-04-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多