我正在使用循环和fgets来运行此输入文件
CSCI112 Programming with C 3
CSCI127 Joy and Beauty of Data 4
CSCI132 Basic Data Structures and Algorithms 4
CSCI338 Computer Science Theory 3
CSCI215 Social and Ethical Issues in CS 3
ARCH112 Introduction to Design 3
COMX112 Interpersonal Skills in the Workplace 1
HSTA101 American History 4
XXXXXXX XXXXXX X
我必须确定CSCI类的数量(和其他东西,但那些并不重要)。目前,我正在使用包含字符串ID,字符串名称和int信用的类结构。
我的问题是,在我的类数组中,所有ID都存储为" XXXXXXX"。我无法理解为什么for循环没有正确地为类赋值。
如果我运行该程序,则输出
Class: ID-XXXXXXX, Name-XXXXXX X, Credits-3
Class: ID-XXXXXXX, Name-XXXXXX X, Credits-4
Class: ID-XXXXXXX, Name-XXXXXX X, Credits-4
Class: ID-XXXXXXX, Name-XXXXXX X, Credits-3
Class: ID-XXXXXXX, Name-XXXXXX X, Credits-3
Class: ID-XXXXXXX, Name-XXXXXX X, Credits-3
Class: ID-XXXXXXX, Name-XXXXXX X, Credits-1
Class: ID-XXXXXXX, Name-XXXXXX X, Credits-4
CSCI classes: 0
CSCI class credits: 0
显然这些课程不对,CSCI编号错了。我不明白如何正确分配学分,但ID和名字不是?
这是我的代码:
#include <stdio.h>
#include <string.h>
#include "class.h"
int main(){
//variable declaration for classes
char line[100];
char line_copy[100];
char ccred;
class_t classes[100];
int i = 0;
//infinite loop
for(;;){
//read in input from file
fgets(line, sizeof(line), stdin);
strcpy(line_copy, line);
classes[i].ID = strtok(line, " ");
classes[i].name = strtok(NULL, "1234");
//remove trailing space from class name
classes[i].name[strlen(classes[i].name) - 1] = 0;
ccred = line_copy[strlen(line_copy) - 2];
classes[i].credits = ccred - '0';
//stop reading input if not a valid class
if(strcmp(classes[i].ID, "XXXXXXX") == 0){
break;
}
i++;
}
int ii;
for(ii = 0; ii < i; ii++){
printf("Class: ID-%s, ", classes[ii].ID);
printf("Name-%s, ", classes[ii].name);
printf("Credits-%d\n", classes[ii].credits);
}
//find CSCI classes and credits only
int CSCIclasses = 0;
int CSCIcredits = 0;
char toCompare[] = "CSCI";
int k;
for(k = 0; k < i; k++){
if(strncmp(toCompare, classes[k].ID, 4) == 0){
printf("CSCI course!");
CSCIclasses++;
CSCIcredits += classes[k].credits;
}
}
printf("CSCI classes: %d\n", CSCIclasses);
printf("CSCI class credits: %d\n", CSCIcredits);
return 0;
}
我的问题是:如何正确地为类结构赋值并获得适当数量的CSCI类和信用?
感谢您的帮助!
答案 0 :(得分:2)
strtok
函数返回指向您正在标记的缓冲区的指针。这意味着所有结构的所有ID
和name
指针都将指向同一个line
数组。
您可以使用动态分配malloc
然后strcpy
来复制字符串(或常见但非C标准strdup
函数)。或者使用数组(和strcpy
)作为结构中的字符串。
答案 1 :(得分:0)
虽然您现在明白line
以及您制作的任何副本,或任何引用line
内地址的指针都会指向您line
末尾的最终内容读取循环,您可能接下来遇到由于name
中的空白而试图标记每一行的问题。
虽然您可以使用strtok
,将每个先前的指针保存在'space'
上的标记上,然后使用前一个指针作为name
的结束指针,它会变得更容易只需使用strchr
查找第一个空格,strrchr
设置指向nul-char的指针(或使用strlen
设置指向结束字符的指针)然后备份查找最后'space'
。这样,您就知道第一个空格和最后一个空格之间的所有内容都是name
,而最后一个空格之后的字符是credits
。这使得处理起来相当简单。
总而言之,您可以执行以下操作,使用credits
的固定数组(您知道最多6个字符)并为name
分配存储空间,并消除{{1向下走一条指针,找出你需要的东西并不修改line_copy
,例如
line
(注意:常量的定义。如果您需要一个(或更多)#include <stdio.h>
#include <stdlib.h> /* for malloc/free */
#include <string.h>
// #include "class.h"
#define MAXID 8 /* maximum ID, characters & structs */
#define MAXC 128 /* if you need constants, define them */
#define MAXS MAXC /* (don't use magic numbers) */
typedef struct {
char ID[MAXID], /* fixed 8 chars for 6 + 1 needed for ID */
*name, /* you must allocate storage for name */
credits;
} class_t;
int main(){
char line[MAXC] = "", /* variable declaration for classes */
*toCompare = "CSCI"; /* CSCI classes and credits only */
int CSCIclasses = 0,
CSCIcredits = 0,
i, n = 0;
size_t maxlen = 0;
class_t classes[MAXS] = {{ .ID = "" }};
for (; n < MAXS; ) { /* loop continually for input */
char *p = line, /* pointer to line */
*ep = NULL; /* end pointer for line */
if (!fgets (line, sizeof(line), stdin)) /* read/validate line */
break;
ep = strchr (line, ' '); /* set end pointer to 1st space */
if (ep) { /* validate 1st space found */
size_t len = ep - p; /* get length of ID */
if (len > MAXID - 1) { /* validate it fits + nul-char */
fprintf (stderr, "error: ID exceeds MAXID.\n");
return 1;
}
strncpy (classes[n].ID, p, len); /* copy ID */
classes[n].ID[len] = 0; /* nul-terminate ID */
}
else
continue; /* get next line */
p = ep + 1; /* set pointer to start of name */
ep = strrchr (line, 0); /* set end pointer to nul-character */
while (ep > p && *ep != ' ') /* backup to last space */
ep--;
if (*ep == ' ') { /* if space, parse remainder o fline */
size_t len = ep - p; /* len of name */
if (!(classes[n].name = malloc (len + 1))) { /* allocate */
perror ("malloc-classes[].name");
break;
}
ep++; /* move end pointer to credits */
strncpy (classes[n].name, p, len); /* copy to name */
classes[n].name[len] = 0; /* nul-termiante name */
if ('0' <= *ep && *ep <= '9') /* is credits digit? */
classes[n++].credits = *ep - '0'; /* assign credits */
else
classes[n++].credits = 0; /* set credits zero */
if (len > maxlen)
maxlen = len;
}
}
for (i = 0; i < n; i++) /* output class information */
printf ("Class: ID-%s, Name-%s, %-*s Credits-%d\n", classes[i].ID,
classes[i].name, (int)(maxlen - strlen(classes[i].name) + 1),
" ", classes[i].credits);
putchar ('\n'); /* tidy up with newline */
for (i = 0; i < n; i++) { /* output CSCI courses, free memory */
if (strncmp (toCompare, classes[i].ID, 4) == 0) {
printf("CSCI course! - %s\n", classes[i].name);
CSCIclasses++;
CSCIcredits += classes[i].credits;
}
free (classes[i].name); /* free 'name' - no longer needed */
}
printf ("CSCI classes: %d\n", CSCIclasses); /* output CSCI summary */
printf ("CSCI class credits: %d\n", CSCIcredits);
return 0;
}
他们或使用#define
来执行此操作。请勿撒上整个代码都包含enum
等幻数。在顶部定义它们,因此如果您的需求发生变化,您可以通过一个简单的位置进行更改,其余部分将自动处理)
示例使用/输出
100
仔细看看,如果您有任何其他问题,请告诉我。