目前在学校,我正在开发一个类似街机的游戏项目。我有这个想法,每次我们进入下一个级别而不仅仅是“级别1”,“级别2”等时,在级别上放置一个随机名称... 所以我想知道如何使用fscanf或fgets或类似的东西做到这一点?我的文本文件包含70行不同的名称。
非常感谢:D
答案 0 :(得分:0)
如果每行只有一个名字,那么请使用fgets()。
/******************************************************************************************
* This function reads a file line by line putting each line as a C-sting in an array
******************************************************************************************/
void read_names(char **names_table, int *n_names)
{
FILE *fp = fopen(<filename>, "r");
int i = 0;
for(i = 0; i < MAX_N_NAMES; ++i){
char *name = malloc(MAX_NAME_LENGTH);
fgets(name, MAX_NAME_LENGTH, fp);
if(name == NULL)
break;
name_table[i] = name;
}
*n_names = i; // There's a gotcha here
}
通过这种方式,你可以调用你的函数一次,然后我把它留给你来决定你的数组应该存在的位置(在内存中,谁拥有和管理它)。然后我会使用rand() % n_names
为该级别选择该数组的随机索引。
在程序的某个地方,你应该有
enum NameParams { MAX_N_NAMES = 80, MAX_NAME_LENGTH = 20 };
(我比#define
更喜欢这个,因为调试器会显示常量的名称。)
这应该让你开始,你可能想要做的一件事就是标记你使用的名称,以便不将它们用于两个级别。我会使用另一个int
s数组(C没有bool)来标记所使用的级别。这有一个问题,你必须做rand()%n_names,直到你找到一个未使用的名字。
或者你可以将name_table洗牌一次,并将name_table [i]用于第i级。
void swap_indices(char **array, int i, int j)
{
char *tmp = array[i];
array[i] = array[j];
array[j] = tmp;
}
void shuffle(char **array, int length)
{
// Do a bunch of swaps, depending on how much you care about randomness,
// you might want to look up shuffling algorithms or see if some already
// exist that you could use, but if you don't care that much, just
// do a bunch of swaps.
}
最后,我建议使用一个独立的C文件(模块)来管理像这样的结构作为全局变量。您的.h文件可能如下所示(您将其包含在其他文件中,它将允许您访问模块的公共接口)。
#ifndef _LEVEL_NAMES_H_
#define _LEVEL_NAMES_H_
enum NameErrorCodes { ERR_NONE = 0, ERR_FILE, ERR_OTHER};
int names_init(char *filename);
char *get_name();
#endif
然后你的c文件看起来像这样:
#include "LevelNames.h"
struct LevelNames{
int n_names;
char * names[MAX_N_NAMES];
};
static struct LevelNames level_names; // static makes this global variable
// accessible only from this file
// It does the same thing for functions
static int read_names(char *filename);
static void swap_indices(char **array, int i, int j);
static void shuffle_names();
/*******************************************************************************
*
*******************************************************************************/
int names_init(char *filename)
{
int err = 0;
err = read_names(filename);
if( err != ERR_NONE )
return err;
shuffle_names();
}
/*******************************************************************************
*
*******************************************************************************/
char *get_name(int level)
{
if(level >= level_names.n_names || level < 0)
return NULL;
return level_names.names[i];
}
/*******************************************************************************
*
*******************************************************************************/
static int read_names(char *filename)
{
FILE *fp = fopen(<filename>, "r");
if( fp == NULL )
return ERR_FILE;
int i;
for(i = 0; i < MAX_N_NAMES; ++i){
char *name = malloc(MAX_NAME_LENGTH);
fgets(name, MAX_NAME_LENGTH, fp);
if(name == NULL)
break;
level_names.names[i] = name;
}
level_names. = i; // There's a gotcha here
return ERR_NONE;
}
/*******************************************************************************
*
*******************************************************************************/
static void swap_indices(char **array, int i, int j)
{
...
}
/*******************************************************************************
*
*******************************************************************************/
static void shuffle_names()
{
...
}
这就是我要做的。并且不要忘记read_names中的那个陷阱。
我想以全局变量的讨论结束。你可能在学校被告知,你应该永远不要使用全局变量。这件事情是由很多原因导致的。他们是很好的理由,你应该听听那些对你这么说的人。
但是,我有一个模块,其唯一目的是管理一系列名称。因此,这个模块有一个全局变量是有道理的。此外,这个变量必须是静态的。这样,模块的客户端就不知道你的全局变量(他们不应该知道)。
C标准库的许多模块都有一个他们管理的静态全局变量。如果你想使用一个全局变量,因为你不知道应该如何从一个函数传递到另一个函数,那么弄清楚它并不使用全局变量。如果你想模仿C ++或Java中静态类的行为,那么这样做是合法的。