- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在尝试创建一个while循环来扫描一组单词,直到输入新行。我无法使用fgets,因为我需要每个单词的长度来计算单词的平均值,这是我的代码。任何帮助将不胜感激。
while(1){
scanf("%s",&input);
if(input=="\n")
break;
最佳答案
为什么fgets()简化了事情(请参阅下面的非fgets()解决方案)
如@user3386109所示,当您要读取一行输入时,则需要使用面向行的输入功能(例如fgets()
或POSIX getline()
)来一次读取整行的单词。
然后,您可以使用fgets()
将strtok()
填充的缓冲区拆分为令牌。在这里,您要基于分隔符space
或'\n'
分割单词(可以添加tab
或','
或其他所需的分隔符来分隔相邻单词)strtok
将任意数量的顺序分隔符视为单个定界符,因此,例如,如果该行包含空字段,则不能对该行进行逗号分隔。 (例如,1,2,,4,...
将被视为3个令牌,而不是4个带有一个空字段的令牌)
要理解的另一件事是strtok()
修改其操作的字符串。因此,如果需要保留原件,请进行复印。如果需要保存令牌(例如在数组中),则需要将令牌复制到该存储中(如果不为每个令牌使用数组,则还需要分配存储)
如果您已将行读入缓冲区buf
,则在第一次调用strtok()
时,将buf
作为参数以及定界符传递给第一个令牌(word),例如
char *p = strtok(buf, " \n");
strtok()
以获取指向所有剩余令牌的指针之后,您将
NULL
作为参数以及定界符(您可以在两次调用之间更改定界符)作为参数传递。
p = strtok (NULL, " \n")
strtok()
返回
NULL
。
sum
并保持标记的计数,以便可以计算每个标记(单词)的平均长度,可以做类似下面的事情。 (注意:由于没有存储任何令牌供以后使用,因此无需将令牌复制到数组等。)
#include <stdio.h>
#include <string.h>
#define MAXC 1024
int main (void) {
char buf[MAXC];
while (fgets (buf, MAXC, stdin)) {
int n = 0, sum = 0;
puts ("\ngroup:");
for (char *p = strtok(buf, " \n"); p; p = strtok (NULL, " \n")) {
puts (p);
sum += strlen (p);
n++;
}
printf ("average len: %.2f\n", (double)sum / n);
}
}
fgets()
)的返回控制。
$ cat dat/groups.txt
My dog has fleas
My cat has none
Lucky feline
$ ./bin/strgroupavglen < dat/groups.txt
group:
My
dog
has
fleas
average len: 3.25
group:
My
cat
has
none
average len: 3.00
group:
Lucky
feline
average len: 5.50
fgets()
,现在该回到旧的面向字符的良好输入和状态循环了。
int
或
1
设置为
0
或
true
的简单
false
变量即可跟踪状态/条件)
int inword;
)
int in_line;
-您不能使用
inline
-关键字以及所有...)
length, sum, word_count
等。使用一些计数器变量即可精确地完成所需的操作(旧方法-手动)通过包含
ctype.h
标头并利用
isspace()
宏来确定读取的字符是否为空格,可以使您的工作更轻松-否则,它是单词中的字符。
#include <stdio.h>
#include <ctype.h>
#define MAXC 128
int main (void) {
char word[MAXC]; /* array to hold word */
int c, /* char to read from stdin */
in_line = 0, /* state variable in/out line */
inword = 0, /* state varaible in/out word */
len = 0, /* word length */
n = 0, /* word count per-line */
sum = 0; /* sum of chars in words per-line */
while ((c = getchar()) != EOF) { /* read chars until EOF */
if (isspace (c)) { /* if space */
if (inword) { /* if inword */
word[len] = 0; /* nul-terminate word */
puts (word); /* output word */
n++; /* increment word-count */
sum += len; /* add length to sum */
if (c == '\n') { /* if \n, output average */
printf ("average len: %.2f\n", (double)sum / n);
in_line = 0; /* reset in_line flag */
n = 0; /* set word count 0 */
sum = 0; /* set sum zero */
}
}
len = 0; /* set length 0 if space of any kind */
}
else { /* if not space */
if (!in_line) { /* if not in_line */
puts ("\ngroup:"); /* output group heading */
in_line = 1; /* set in_line flag 1 */
}
word[len++] = c; /* add char to word, increment len */
inword = 1; /* set inword flag 1 */
}
}
if (n && inword) /* if word count and inword (non-POSIX EOF) */
printf ("average len: %.2f\n", (double)sum / n);
}
if (n && inword)
,则最终的
'\n'
输出最终的平均值)
scanf()
。对于新的C程序员来说,这通常不是首选,因为
scanf()
在使用格式字符串和考虑
stdin
中剩余的字符(取决于所使用的转换说明符)方面都充满了陷阱。
scanf()
在您的情况下起作用,您必须有一种方法来确定一行的结尾。否则,您将无法对每行字符求和并输出平均长度。您可以使用
"%s%c"
形式来读取单词和其后的字符(
"%s"
在遇到第一个空格或
EOF
时停止。)。
" %[..]"
形式在这里没有提供任何好处,因为您只需要用
[^..]
否定字符类,并将空格作为不可读内容包括在内即可。
scanf()
读取输入并产生相同输出的方法与控制每个组的标题并仅输出有关后面有单词时的标题。为了适应这种情况,您需要预读该行开头的字符,并确保它不是
'\n'
或
EOF
,然后将
ungetc()
字符放回
stdin
中。
scanf()
放在一起,您可以执行以下操作:
#include <stdio.h>
#include <string.h>
#define MAXC 128
int main (void) {
char c = 0; /* test character */
while ((c = getchar()) != EOF && c != '\n') {
char buf[MAXC]; /* declare buffer */
int n = 0, sum = 0; /* count and sum */
ungetc (c, stdin); /* put the char back */
puts ("\ngroup:"); /* output groups header */
while (1) { /* loop until no word or until \n */
int rtn = scanf (" %s%c", buf, &c); /* read word & char */
if (rtn < 1) /* if no word, break */
break;
puts (buf); /* output word */
sum += strlen (buf); /* add length to sum */
n++; /* increment word count */
if (c == '\n') /* if end of line, break */
break;
}
if (n) /* only average if words in group */
printf ("average len: %.2f\n", (double)sum / n);
}
}
fgets()
的情况下执行此操作-但我会让您自己确定,从而简化了所需的逻辑。如果您还有其他问题,请告诉我。
fgets()/strtok()
解析标记(单词)很简单,并且为每个单词提供存储很简单(如果使用
strdup
,则只需使用
strlen() + 1
,或者只是分配
char ***pointer;
字节)。单个对象中的字符串-您必须为(1)每个组的指针(2)每个组中的每个字符串的指针和(3)每个单词的存储分配存储空间。
NULL
,则通常应考虑重构或重新排列代码,以避免出现间接层之一。但是,对于像这样要处理未知数量的组,每个组包含未知数量的字符串以及每个字符串包含未知数量的字符的情况,您没有太多选择。
used + 1 == allocated
生成字符串指针的最后一个指针的方法(提供前哨NULL)。这使您不必为其他组的组和字符串数保留计数器,从而能够遍历集合并获取信息。
Allocation 1 Allocation 2
group pointers string pointers
+------+ +------+------+------+------+------+
| g1 | ---> | s1 | s2 | s3 | s4 | NULL |
+------+ +------+------+------+------+------+
| g2 | ... | | | |
+------+ +---+ +---+ ... ....
| g3 | ... | M | | d |
+------+ +---+ +---+
| NULL | | y | | o | Allocations 3+
+------+ +---+ +---+ storage for each string
| \0| | g |
+---+ +---+
| \0|
+---+
'\0'
,( +1为
realloc
节省了空间,最后,您
getchar()
有了更多存储空间并继续使用。使用
valgrind
向字符串中添加未知数量的字符的简单示例可以是:
#include <stdio.h>
#include <stdlib.h>
int main (void) {
int c, allocated = 2, used = 0; /* char, bytes-allocated, bytes-used */
char *string = NULL; /* pointer to allocated storage */
string = malloc (allocated); /* allocate initial storage for 2-chars */
if (string == NULL) { /* validate EVERY allocation */
perror ("malloc-string");
return 1;
}
while ((c = getchar()) != '\n' && c != EOF)
{
/* check if reallocation needed */
if (used + 1 == allocated) { /* recall +1 is needed for \0 at end */
/* always realloc to a temporary pointer */
void *tmp = realloc (string, 2 * allocated);
if (tmp == NULL) { /* validate EVERY reallocation */
perror ("realloc-string");
break; /* storage pointed to by string still good, don't exit */
}
string = tmp; /* assign reallocated block to string */
allocated *= 2; /* update allocated with new size */
}
string[used++] = c; /* assign character to string */
}
string[used] = 0; /* nul-terminate string */
printf ("%s\nallocated: %d\nused : %d\n", string, allocated, used);
free (string); /* don't forget to free what you allocate */
}
$ echo "My dog has fleas and my cat has none" | ./bin/reallocgetchar
My dog has fleas and my cat has none
allocated: 64
used : 36
(used == allocated)
是正常选择。每个平台都有类似的内存检查器。它们都很容易使用,只需通过它运行程序即可。
$ echo "My dog has fleas and my cat has none" | valgrind ./bin/reallocgetchar
==4893== Memcheck, a memory error detector
==4893== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==4893== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==4893== Command: ./bin/reallocgetchar
==4893==
My dog has fleas and my cat has none
allocated: 64
used : 36
==4893==
==4893== HEAP SUMMARY:
==4893== in use at exit: 0 bytes in 0 blocks
==4893== total heap usage: 8 allocs, 8 frees, 5,246 bytes allocated
==4893==
==4893== All heap blocks were freed -- no leaks are possible
==4893==
==4893== For counts of detected and suppressed errors, rerun with: -v
==4893== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
realloc
时检查是否需要重新分配
realloc
指向临时指针-当
NULL
失败时,它将返回
pointer = realloc (pointer, ..)
;如果您盲目地执行
pointer
,则您已经用
NULL
覆盖了
char **
所保存的地址,从而创建了内存泄漏。
char***
类型,这是一个分配的指针块,其中为每个字符串分配的存储空间分配给了每个指针)并绑定通过最后分配的指针块(类型为
grpsalloced
)将每组字符串与每个分配的指针块的地址一起分配给分配给该最终内存块中的指针的每个组。
grpsused
和
grpsused
跟踪分配和使用的组数以下,其中
groups[grpsused]
成为我们集合中组的索引,例如
stralloced
。对于每个组中的字符串,我们跟踪
strused
和
strused
分配和使用的指针,其中
group[grpsused][strused]
变量成为该组中我们字符串的索引,例如
[..]
。
'*'
就像
strtok()
一样用作指针的取消引用。
grpsused
解析的每个单词作为字符串存储在组中,并将所有组一起收集到最终对象中,您可以将其作为参数传递或独立于读取循环进行循环,您可以执行以下操作:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define NGROUPS 2 /* initial no. of groups to allocate */
#define MAXC 1024 /* max characters for read buffer */
int main (void) {
char buf[MAXC];
char ***groups = NULL; /* being a 3-star programmer isn't a compliment */
/* but it is necessary to access groups of strings */
int grpsalloced = NGROUPS, /* initial no. of groups (pointers) allocated */
grpsused = 0; /* counter to track groups (pointers) used */
groups = malloc (grpsalloced * sizeof *groups); /* allocate ngroups pointers */
if (groups == NULL) { /* validate EVERY allocation */
perror ("malloc-groups");
return 1;
}
/*
* add groups of strings, reallocating as needed, ensure last pointer to
* string in each group is NULL, and ensure last pointer to group is NULL
*/
while (fgets (buf, MAXC, stdin)) { /* read each line into buffer */
int stralloced = NGROUPS, /* reuse NGROUPS to set no. strings per-group */
strused = 0; /* strings used in group */
/* allocate ptrs for current group, assign to next available groups pointer */
groups[grpsused] = malloc (stralloced * sizeof *groups[grpsused]);
if (!groups[grpsused]) { /* validate group allocation */
perror ("malloc-groups[groupsused]");
break; /* again, break, don't exit, any prior groups data still good */
}
/* loop separating tokens (words) from buffer */
for (char *p = strtok(buf, " \n"); p; p = strtok (NULL, " \n")) {
size_t len = strlen (p);
/* allocate storage for each token (word), use strdup if available */
groups[grpsused][strused] = malloc (len + 1);
if (!groups[grpsused][strused]) {
perror ("malloc-groups[groupsused][n]");
break;
}
/* copy string to allocated storage */
memcpy (groups[grpsused][strused], p, len + 1);
strused++; /* increment string count */
/* check if more pointers for current group required */
if (strused == stralloced) {
void *tmp = realloc (groups[grpsused], /* realloc str ptrs */
2 * stralloced * sizeof *groups[grpsused]);
if (!tmp) { /* validate reallocation */
perror ("realloc-groups[groupsused]");
break;
}
groups[grpsused] = tmp; /* assign new block of pointers */
stralloced *= 2; /* increment allocated pointer count */
}
groups[grpsused][strused] = NULL; /* sentinel NULL at end str ptrs */
}
grpsused++; /* increment groups used counter */
if (grpsused == grpsalloced) { /* when groups reallocation needed */
/* always realloc to a temporary pointer, here doubling no. of pointers */
void *tmp = realloc (groups, 2 * grpsalloced * sizeof *groups);
if (!tmp) {
perror ("realloc-groups");
break; /* don't exit, original data for groups still valid */
}
groups = tmp; /* assign reallocated block to groups */
grpsalloced *= 2; /* update no. of group ptrs allocated */
}
}
groups[grpsused] = NULL; /* sentinel NULL at end of group pointers */
/*
* iterate over group pointers, iterate over each string pointer in group
*/
char ***g = groups; /* pointer to groups */
while (*g) {
char **s = *g; /* pointer to 1st group */
int n = 0, sum = 0; /* integers for string counter and sum */
puts ("\ngroup:"); /* output heading */
while (*s) { /* loop over each string pointer in group */
puts (*s); /* output string */
sum += strlen (*s); /* add length to sum */
free (*s); /* free storage for string (can be done later) */
s++; /* advance to next string */
n++; /* increment string counter */
}
printf ("average len: %.2f\n", (double)sum / n); /* group result */
free (*g); /* free current group (can be done later) */
g++; /* advance to next group pointer */
}
free (groups); /* free memory for group pointers */
}
strused
和
关于c - 如何不使用(fgets)继续扫描直到换行C,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60198370/
猫f1.txt阿曼维沙尔阿杰贾伊维杰拉胡尔曼尼什肖比特批评塔夫林现在输出应该符合上面给定的条件 最佳答案 您可以在文件读取循环中设置一个计数器并打印它, 计数=0 读取行时做 让我们数一数++ if
我正在尝试查找文件 1 和文件 2 中的共同行。如果公共(public)行存在,我想写入文件 2 中的行,否则打印文件 1 中的非公共(public)行。fin1 和 fin2 是这里的文件句柄。它读
我有这个 SQL 脚本: CREATE TABLE `table_1` ( `IDTable_1` int(11) NOT NULL, PRIMARY KEY (`IDTable_1`) );
我有 512 行要插入到数据库中。我想知道提交多个插入内容是否比提交一个大插入内容有任何优势。例如 1x 512 行插入 -- INSERT INTO mydb.mytable (id, phonen
如何从用户中选择user_id,SUB(row, row - 1),其中user_id=@userid我的表用户,id 为 1、3、4、10、11、23...(不是++) --id---------u
我曾尝试四处寻找解决此问题的最佳方法,但我找不到此类问题的任何先前示例。 我正在构建一个基于超本地化的互联网购物中心,该区域分为大约 3000 个区域。每个区域包含大约 300 个项目。它们是相似的项
preg_match('|phpVersion = (.*)\n|',$wampConfFileContents,$result); $phpVersion = str_replace('"','',
我正在尝试创建一个正则表达式,使用“搜索并替换全部”删除 200 个 txt 文件的第一行和最后 10 行 我尝试 (\s*^(\h*\S.*)){10} 删除包含的前 10 行空白,但效果不佳。 最
下面的代码从数据库中获取我需要的信息,但没有打印出所有信息。首先,我知道它从表中获取了所有正确的信息,因为我已经在 sql Developer 中尝试过查询。 public static void m
很难说出这里问的是什么。这个问题是含糊的、模糊的、不完整的、过于宽泛的或修辞性的,无法以目前的形式得到合理的回答。如需帮助澄清此问题以便重新打开它,visit the help center 。 已关
我试图在两个表中插入记录,但出现异常。您能帮我解决这个问题吗? 首先我尝试了下面的代码。 await _testRepository.InsertAsync(test); await _xyzRepo
这个基本的 bootstrap CSS 显示 1 行 4 列: Text Text Text
如果我想从表中检索前 10 行,我将使用以下代码: SELECT * FROM Persons LIMIT 10 我想知道的是如何检索前 10 个结果之后的 10 个结果。 如果我在下面执行这段代码,
今天我开始使用 JexcelApi 并遇到了这个:当您尝试从特定位置获取元素时,不是像您通常期望的那样使用sheet.getCell(row,col),而是使用sheet.getCell(col,ro
我正在尝试在我的网站上开发一个用户个人资料系统,其中包含用户之前发布的 3 个帖子。我可以让它选择前 3 条记录,但它只会显示其中一条。我是不是因为凌晨 2 点就想编码而变得愚蠢? query($q)
我在互联网上寻找答案,但找不到任何答案。 (我可能问错了?)我有一个看起来像这样的表: 我一直在使用查询: SELECT title, date, SUM(money) FROM payments W
我有以下查询,我想从数据库中获取 100 个项目,但 host_id 多次出现在 urls 表中,我想每个 host_id 从该表中最多获取 10 个唯一行。 select * from urls j
我的数据库表中有超过 500 行具有特定日期。 查询特定日期的行。 select * from msgtable where cdate='18/07/2012' 这将返回 500 行。 如何逐行查询
我想使用 sed 从某一行开始打印 n 行、跳过 n 行、打印 n 行等,直到文本文件结束。例如在第 4 行声明,打印 5-9,跳过 10-14,打印 15-19 等 来自文件 1 2 3 4 5 6
我目前正在执行验证过程来检查用户的旧密码,但问题是我无法理解为什么我的查询返回零行,而预期它有 1 行。另一件事是,即使我不将密码文本转换为 md5,哈希密码仍然得到正确的答案,但我不知道为什么会发生
我是一名优秀的程序员,十分优秀!