我已经尝试解决问题一年多了,只是似乎还没有解决问题的技能,所以我希望有人可以帮助我吗?我是堆栈溢出的新手,而且绝对是菜鸟程序员。我正在使用Codelite作为程序来编写和编译代码。
在C语言中,我想将矩阵加载,保存并打印到终端/屏幕中,不仅是数字矩阵,还包括字符串和数字矩阵。如果这不可能,则可以通过将值加载到单独的矩阵中来从包含名称和数字的文本文件(制表符分隔的(.txt)或逗号分隔的列表(.csv))列表中加载值?
答案 0 :(得分:0)
为了使您的头想做什么,您必须了解C提供了哪些工具来帮助您将不同类型的数据作为一个单元进行协调。 C提供了一个结构(或struct)。任何时候考虑要在保持不同类型之间的关系的同时管理字符数据和数字数据时,请考虑struct。
在这里,根据您显示的数据和您尝试过int column=4;
的事实,您似乎有一个firstname
,lastname
,some_ID
和{{1 }}与每个数据记录相关联。这将直接导致包含两个字符数组和两个数值的结构。 (出于示例目的,我们将简单地使用具有自动存储功能的固定大小的数组来存储名称-但您可以随意声明指针并为每个名称分配名称)。
首先,让我们some_num
使用我们需要使用的常量,因此我们不在代码中使用 magic-numbers (但请注意,#define
字段宽度修饰符不能是变量,因此是一个例外):
scanf
(不要忽略缓冲区的大小,如果您的名字可以接近64个字符,则将大小加倍)
现在让我们定义一个结构,使用/* if you need a constant #define one (or more) */
#define MAXPPL 16 /* max people (e.g. number of elements in array) */
#define MAXNM 64 /* max name length for both first, last */
#define MAXC 1024 /* max characters for read buffer (per-line) */
为方便起见,我们可以使用typedef
作为类型,而不必在需要该类型的任何地方键入person_t
,例如
struct person
现在我们有了一个结构,可以容纳typedef struct person { /* use a struct to coordinate differing types */
char first[MAXNM],
last[MAXNM];
unsigned id,
num;
} person_t;
和first
名称(每个63个字符+ 以n终止的字符)和两个last
值,我称之为unsigned
和id
(因为缺少更好的词)。同样,请验证num
是否适用于数字类型。 4字节的unsigned
可以处理unsigned
中的值,并根据需要选择新的类型,例如0 to 4294967295
或使用long long unsigned
uint64_t
有了这个,剩下的挑战就很简单了。您声明一个stdint.h
数组(结构的数组),将每一行数据读入一个person_t
大小的缓冲区(这应该足够了,但是无论如何都要通过检查{{每次读取并确保其小于1个字符后MAXC
个字符,最后一个字符为strlen()
),然后将每一行解析为MAXC-1
,'\n'
,first
和last
,将解析后的值存储在数组中,同时确保您尝试存储的名称和数字不超过声明的数量。
例如,要在读取每一行数据时填充数组的id
个元素,可以执行以下操作:
num
上面,请注意,MAXPPL
只是一个记录计数器,每添加一个int main (int argc, char **argv) {
char buf[MAXC] = ""; /* read buffer */
unsigned n = 0; /* person count */
person_t people[MAXPPL] = {{ .first = "" }}; /* array of people */
/* use filename provided as 1st argument (stdin by default) */
FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;
if (!fp) { /* validate file open for reading */
perror ("file open failed");
return 1;
}
/* fill up to MAXPPL struct while reading each line of data */
while (n < MAXPPL && fgets (buf, MAXC, fp)) {
/* temp struct to hold parsed values */
person_t tmp = { .first = "" };
/* validate entire line read here - left to you */
,n
,first
和last
元素就会增加数组,因此只有在id
时尝试读取才能保护您避免存储超出您的存储空间的元素。在您的情况下包括返回num
的情况,可以保证只有在n < MAXPPL
已被填充并且包含要解析的有效字符的情况下,才尝试从fgets
解析值。
这使我们到达了解析点。您已经将行读入buf
并验证了buf
包含字符,但是如何将行拆分成几段,以便您拥有buf
,buf
,{{1} }和first
值存储在每个struct元素中?有多种方法可以执行此操作,可以使用一对指针,然后沿着缓冲区检查分隔符,可以使用适当的分隔符调用last
(如果存在分隔符,则可以使用id
可能是csv文件中字段为空),或者,也许最简单的方法是使用num
将strtok
拆分为strsep
,sscanf
,{ {1}}和buf
,然后验证返回值(发生了4次会话)
您还提到了使用逗号分隔值文件或使用制表符分隔文件的可能性,您可以使用简单的first
处理这些文件,其中您先检查逗号分隔值,然后再检查空白分隔值(反之亦然-您的选择),例如
last
(注意:在两个id
调用之间使用不同的转化说明符-确保您了解原因,请参见scanf(3) - Linux manual page )
到那时,您已将所有数据读入struct数组,您可以根据需要随意处理它。充满数据的元素数量存储在num
中。因此,您可以使用简单的if ... else if ....
循环(例如
/* attempt comma separated parse */
if (sscanf (buf, "%63[^,],%63[^,],%u,%u",
tmp.first, tmp.last, &tmp.id, &tmp.num) == 4)
people[n++] = tmp;
/* attempt space/tab separated parse */
else if (sscanf (buf, "%63s %63s %u %u",
tmp.first, tmp.last, &tmp.id, &tmp.num) == 4)
people[n++] = tmp;
}
if (fp != stdin) fclose (fp); /* close file if not stdin */
将其完全放在一起,您将:
sscanf
示例输入文件
逗号分隔
n
制表符分隔
for
使用/输出示例
无论输入文件如何,输出都是相同的。
for (unsigned i = 0; i < n; i++) /* output results */
printf ("%-10s %-10s %10u %10u\n", people[i].first, people[i].last,
people[i].id, people[i].num);
仔细检查一下,如果还有其他问题,请告诉我。
答案 1 :(得分:-2)
我建议应用此处描述的概念,这对实现您的最终目标很有帮助:
https://ericlippert.com/2014/03/21/find-a-simpler-problem/
在您的情况下,我将采用这种方式:
还有一些其他提示,这些提示似乎与您相关(如您所显示的代码所隐含):
确保将字符串读入足够大的缓冲区中。在2D矩阵的每个像元中只有一个单字符缓冲区:
char t[r][c];
您明智地避免使用scanf()
,那很好。但是,即使使用fsanf(),也需要多加注意。始终检查返回值,它会告诉您扫描的距离。如果未成功,请确保您可以解决该问题。
这是一篇有关扫描的有用文章,通过试图说服您不要使用scanf(),它实际上教会了有关如何使用它的非常有用的知识。它还建议替代方法。最重要的是读取整行并将其解析为大字符串。
http://sekrit.de/webdocs/c/beginners-guide-away-from-scanf.html
让我知道您是否无法预测下一种输入。这将更加困难,但是也许我仍然可以推荐一些东西。请提供更多有关它如何变化的详细信息,并提供更多示例(不同模式的示例)以证明您输入的多样性。