首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为结构赋值时遇到困难

为结构赋值时遇到困难
EN

Stack Overflow用户
提问于 2018-04-06 03:36:14
回答 2查看 36关注 0票数 0

我使用循环和fget来运行这个输入文件。

代码语言:javascript
复制
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循环没有正确地为类分配值。

如果我运行这个程序,输出是

代码语言:javascript
复制
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和名字却不是?

这是我的代码:

代码语言:javascript
复制
#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类和学分?

谢谢你的帮助!

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2018-04-06 03:40:22

strtok函数返回指向要标记的缓冲区的指针。这意味着所有结构的所有IDname指针都指向同一个line数组。

您可以使用mallocstrcpy的动态分配来复制字符串(或者通用但非C标准的strdup函数)。或者对结构中的字符串使用数组(和strcpy)。

票数 2
EN

Stack Overflow用户

发布于 2018-04-06 05:23:29

虽然您现在了解到,line和您所做的任何复制,或者引用line中某个地址的任何指针,都将指向line中在read循环末尾的最终内容,但是您接下来可能会遇到由于name中的空格而试图标记每一行的问题。

虽然可以使用strtok,在'space'上保存每个前一个指针,然后使用前一个指针作为name的结束指针,但是简单地使用strchr查找第一个空格,使用strrchr来设置指向nul-char的指针(或者使用strlen将指针设置为结束字符),然后使用备份查找最后一个'space'则容易得多。这样,您知道第一个空格和最后一个空格之间的所有内容都是name,最后一个空格之后的字符是credits。这使得处理起来相当简单。

总之,您可以这样做:为credits使用一个固定数组(您知道这是6-chars ),并为name分配存储空间,并消除line_copy沿行遍历指针,选择所需的内容并不会修改line

代码语言:javascript
复制
#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这样的神奇数字。在顶部定义它们,因此,如果您的需求发生变化,您可以在一个简单的地方进行更改,其余的将自动处理)

示例使用/输出

代码语言:javascript
复制
$ ./bin/classes <dat/classes.txt
Class: ID-CSCI112, Name-Programming with C,                      Credits-3
Class: ID-CSCI127, Name-Joy and Beauty of Data,                  Credits-4
Class: ID-CSCI132, Name-Basic Data Structures and Algorithms,    Credits-4
Class: ID-CSCI338, Name-Computer Science Theory,                 Credits-3
Class: ID-CSCI215, Name-Social and Ethical Issues in CS,         Credits-3
Class: ID-ARCH112, Name-Introduction to Design,                  Credits-3
Class: ID-COMX112, Name-Interpersonal Skills in the Workplace,   Credits-1
Class: ID-HSTA101, Name-American History,                        Credits-4
Class: ID-XXXXXXX, Name-XXXXXX,                                  Credits-0

CSCI course! - Programming with C
CSCI course! - Joy and Beauty of Data
CSCI course! - Basic Data Structures and Algorithms
CSCI course! - Computer Science Theory
CSCI course! - Social and Ethical Issues in CS
CSCI classes: 5
CSCI class credits: 17

仔细看一看,如果你还有什么问题,请告诉我。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/49684884

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档