无法为结构分配值

时间:2018-04-06 03:36:14

标签: c struct

我正在使用循环和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类和信用?

感谢您的帮助!

2 个答案:

答案 0 :(得分:2)

strtok函数返回指向您正在标记的缓冲区的指针。这意味着所有结构的所有IDname指针都将指向同一个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

仔细看看,如果您有任何其他问题,请告诉我。