尝试在字符后复制字符串的其余部分

时间:2019-03-29 23:20:34

标签: c string c-strings strcpy strchr

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

尝试在字符串中最后一个“,”之后找到字符时,我目前给我一个错误。

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

re

4 个答案:

答案 0 :(得分:3)

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

或者,您可以在字符串中累积字符,直到到达,,然后终止缓冲区,然后开始将字符串的下一部分累积到下一个缓冲区中,然后重复直到达到空终止符为止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;

答案 1 :(得分:2)

在处理格式化输入时,您可以自由地使用指针和strchr(或只需将指针向下移到缓冲区中)来解析每一行的信息,像sscanf这样的格式化输入功能可以提供很大帮助。

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

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

#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'

现在让我们看一下如何使用fgets进行读取,以及使用格式化输入函数sscanf来解析每一行中所有需要的值。 (或者您可以在一次通话中使用fscanf进行此操作,但是最好使用fgets然后sscanf到(1)确保使用了整行数据,并且(2 )可以独立验证值的读取和解析。

方法类似,用fgets读取,但是不用用strchr查找第一个逗号,只需使用sscanf将ICAO,到达时间和出发时间读入在一个调用中分离缓冲区。始终验证任何scanf函数的返回值,以确保发生了预期的转换次数。

请放心,我们不仅要使用三个独立且不相关的缓冲区。相反,我们声明一个struct来容纳所有三个icao, ariv & dept缓冲区。这样,如果将多个条目读取到内存中,则只需声明一个struct数组并读取/解析所有值以供以后的用户使用。 (数组留给您)

一个简单的例子可能是:

#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);
    }
}

注意:如何在每个字符类转换说明符之前使用 field-width 修饰符,以保护每个缓冲区的数组边界"%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值。结构数组,仍然能够对任何结构成员上的数组进行排序,同时保持icao,到达和离开时间的关联。

有很多很多方法可以将难题的各个部分放在一起。下一步将是根据需要动态分配struct和realloc数组,以允许您读取数量不受限制的记录(取决于计算机的物理内存)。但是,这两种方法(1)用指针解析缓冲区,或(2)使用格式化的输入函数可以覆盖大多数情况。剩下的一切只是在所需的基础上建立。

答案 2 :(得分: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;
}

答案 3 :(得分:0)

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

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,因为它会 发生。