我正在尝试复制用户输入字符串的其余部分。始终在以下位置输入:机场,00:00、00:00。数字是飞行时间和停留时间。在我的代码中,我已经得到它吐出了机场,但是尝试使用strchr在第一个“,”之后查找所有内容是很痛苦的。有什么方法可以删除机场并将其余的放到新的字符串中并继续使用strchr?我必须重新格式化用逗号分隔的字符串是目标。最终结果应为“城市的飞行时间为tt.tt小时,停留时间为tt.tt小时”。我不能使用scanf之类的东西,因此看起来strchr和strcopy可能是我唯一的选择。任何帮助表示赞赏。
尝试在字符串中最后一个“,”之后找到字符时,我目前给我一个错误。
分配规则:请勿使用strtok(),与scanf相关的任何函数,对字符串数据进行标记化的任何函数。
re
答案 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, ariv
或dept
值。结构数组,仍然能够对任何结构成员上的数组进行排序,同时保持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
,因为它会 发生。