0

我正在尝试复制用户输入的字符串的其余部分。始终输入以下内容:机场、00:00、00:00。数字是飞行时间和停留时间。在我的代码中,我已经让它吐出机场,但尝试使用 strchr 查找第一个“,”之后的所有内容是一种痛苦。有没有办法可以删除机场并将其余部分放入新字符串并继续使用 strchr?我必须重新格式化用逗号分隔的字符串是目标。最终结果应该是“城市有飞行时间 tt.tt 小时和停留时间 tt.tt 小时”。我不能使用 scanf 等,所以看起来 strchr 和 strcopy 可能是我唯一的选择。任何帮助表示赞赏。

尝试在字符串中的最后一个“,”之后查找字符时,我目前所拥有的内容给了我一个错误。

分配规则:不要使用 strtok()、任何与 scanf 相关的函数、任何对字符串数据进行标记化的函数。

int main()
{
    int counter = 0;
    int flightTimeNum = 0;
    char userInput[81] ="";
    char userInputNew[81] = "";
    char cityNew[20] = "";
    char flightTime[20] = "";
    char layOverTime[20] = "";


    fgets(userInput, 81, stdin);
    char *city;
    char *flight;
    char *layover;

    city = strchr(userInput, ',');
    strncpy(cityNew, userInput, city - userInput);
    printf("%s\n" ,cityNew);

    layover = strrchr(userInput, ',');
    strncpy(layOverTime, userInput, layover - userInput);
    printf("%s\n", layOverTime);

    printf("Press ENTER key to Continue\n");
    getchar();

}
4

4 回答 4

3

如果要使用strchr,可以考虑通过用空终止符替换每个“,”来创建子字符串,\0然后根据前一个字符串的长度设置指向每个子字符串的指针。

或者,您可以通过字符串累积字符直到到达 a,然后终止缓冲区并开始将字符串的下一部分累积到下一个缓冲区中,然后重复直到到达userInput.

第一种方法的示例,请注意您应该验证您是否能够创建预期数量的子字符串等,以防用户输入无效数据。

// NULL terminate each substring
char *p = userInput;    // Point to the beginning of the string
for(;;) {
    p = strchr(p, ','); // Find first ',' starting from 'p'
    if (!p) break;      // If not found break out of loop
    *p = '\0';          // otherwise replace ',' with a null terminator
    ++p;                // move pointer 'p' to the next character
}

// Setup pointers to each substring
city = userInput; 
flight = city + strlen(city) + 1;
layover = flight + strlen(flight) + 1;
于 2019-03-30T00:03:01.713 回答
2

虽然您可以使用指针和(或通过简单地将指针沿缓冲区向下移动)来自由解析每一行的信息strchr,但在处理格式化输入时,使用格式化输入函数可能会有sscanf很大帮助。

让我们来看看两者。在您的问题中,您想用fgets(good) 阅读,然后找到第一个逗号,然后将该行的其余部分复制到新缓冲区。到目前为止一切都很好。唯一需要注意的是,一旦找到第一个逗号,您仍然必须将指针从逗号前移,跳过任何空格,直到在剩余时间(该行的其余部分)到达第一个字符。

一种简单的方法,即在第一个逗号之后输出字符串的其余部分,省略任何中间空格,可以是:

#include <stdio.h>
#include <string.h>
#include <ctype.h>

#define MAXC 1024   /* if you need a constant, define one (or more) */

int main (void) {

    char buf[MAXC];

    while (fgets (buf, MAXC, stdin)) {      /* read with fgets */
        char *p;
        buf[strcspn (buf, "\r\n")] = 0;     /* trim '\n' from end */
        if ((p = strchr (buf, ','))) {      /* find 1st ',' */
            do
                p++;                    /* advance pointer */
            while (*p && isspace (*p)); /* to end or 1st non-whitespace */
        }
        printf ("rest of string: '%s'\n", p);   /* output rest of line */
    }
}

注意:声明常量时,不要吝啬缓冲区大小。)

示例输入文件

$ cat dat/airport_times.txt
KOCH, 01:01, 01:51
KAXX, 03:50, 05:40
KADS, 07:40, 09:30

示例使用/输出

$ ./bin/airport_gettimes <dat/airport_times.txt
rest of string: '01:01, 01:51'
rest of string: '03:50, 05:40'
rest of string: '07:40, 09:30'

现在让我们看看使用fgetsread 和 formatted-input 函数sscanf来解析每一行中所有需要的值。(或者您可以fscanf在一次调用中使用它,但您最好使用fgets然后sscanf(1)确保您使用整行数据并且(2)可以独立验证读取和解析值。

方法类似,用 读取fgets,但不是用 查找第一个逗号,而是strchrsscanf一次调用中将 ICAO、到达时间和离开时间读取到单独的缓冲区中。始终验证任何scanf函数的返回,以确保发生预期的转换次数。

提前考虑,我们不要只使用三个独立且不相关的缓冲区。相反,让我们声明 astruct来保存所有三个icao, ariv & dept缓冲区。这样,如果将多个条目读入内存,您可以简单地声明一个结构数组并为以后的用户读取/解析所有值。(数组留给你)

这里的一个简单示例可能是:

#include <stdio.h>
#include <string.h>
#include <ctype.h>

#define MAXC 1024   /* if you need a constant, define one (or more) */
#define ICAO    6   /* will work for ICAO and time buffer lengths */

typedef struct {
    char icao[ICAO],
        ariv[ICAO],
        dept[ICAO];
} flight_t;

int main (void) {

    char buf[MAXC];

    while (fgets (buf, MAXC, stdin)) {      /* read with fgets */
        flight_t flt = { .icao = "" };      /* declare struct */
        /* separate all value in line into struct, validating return */
        if (sscanf (buf, "%5[^,], %5[^,], %5[^,]", 
                    flt.icao, flt.ariv, flt.dept) == 3)
            /* if sscanf succeeds, output (or use) the values */
            printf ("%s  %s (arrival)  %s (departure)\n",
                    flt.icao, flt.ariv, flt.dept);
    }
}

注意:如何在每个字符类转换说明符之前使用字段宽度修饰符来保护每个缓冲区的数组边界。如果您对格式字符串有疑问,请询问。)"%5[^,], %5[^,], %5[^,]"

相同的输入文件。

示例使用/输出

$ ./bin/airport_parsetimes <dat/airport_times.txt
KOCH  01:01 (arrival)  01:51 (departure)
KAXX  03:50 (arrival)  05:40 (departure)
KADS  07:40 (arrival)  09:30 (departure)

这里的好处是,您现在将所有值协调为单个对象,但独立存储,因此您可以根据需要访问任何icao, arivdept值,而在结构数组的情况下,仍然能够对任何数组进行排序结构成员,同时保持国际民航组织、到达和离开时间的关联。

将拼图的各个部分拼凑在一起的方法有很多很多。下一步是动态分配结构数组,并realloc根据需要允许您读取未知且无限数量的记录(最多为计算机的物理内存)。然而,这两种方法,(1) 使用指针解析缓冲区,或 (2) 使用格式化输入函数涵盖了大多数情况。剩下的就是根据需要建立在该基础上。

于 2019-03-30T00:41:12.740 回答
0

strchr()将返回一个指向字符的指针,这意味着它将在字符串中向前移动。您可以将其用作新字符串以进行进一步的操作:

char str[] = "airport, 00:00, 00:00.";
char* rem = strchr(str, ','); // rem is now ", 00:00, 00:00."
rem += 2; // rem is now "00:00, 00:00."
rem = strchr(rem, ','); // rem is now ", 00:00, 00:00."
rem += 2; // rem is now "00:00."
*strchr(rem, '.') = 0; // rem is now "00:00" (dot removed)

当然NULL,当角色不存在时,您应该检查返回...

编辑:太诱人了我自己的实现让你看看指针在 C 中是如何工作的:

char str[] = "airport, 00:00, 00:00.";
char* city = str; // "airport, 00:00, 00:00."
char* departure = strchr(str, ','); // ", 00:00, 00:00."
char* arrival = strchr(departure+1, ','); // ", 00:00."
// Clean up
*departure = 0; // city is now "airport"
departure += 2; // depature is now "00:00, 00:00."
*arrival = 0; // departure is now "00:00"
arrival += 2; // arrival is now "00:00."
*strchr(arrival, '.') = 0;  // arrival is now "00:00"

同样,如果是用户输入,您必须检查strchr()返回NULL,因为它发生。

于 2019-03-30T00:04:45.520 回答
0

这是使用函数查找第一个数字的替代解决方案。

如果您只知道您关心的字符串以数字开头,这将比 strstr() 更好地工作。

#include <stdio.h>
#include <string.h>

char* find_digit(char* string)
{
  while(*string != '\0') {
    char ch = *string;

    if(*string >='0' && *string <= '9') {
      return string;
    }
    string++;

  }
}
int main()
{
  char str[] = "airport, 00:00, 00:00.";

  char* ret = find_digit(str);

  char* remainder = ret + strlen(needle);

  printf("Remainder is: %s\n",remainder);

  return 0;
}
于 2019-03-29T23:33:16.750 回答