有没有一种快速的方法来获取放入数组中的最后一个元素?
Is there a quick way to get the last element that was put in an array?
我使用 fgets
从 stdin
中读取一行并将其保存在 char
数组中,我想获取我写的行的最后一个字母,应该在\n
和[=15=]
.
之前的数组中
例如,如果我有一个 char line[10]
并在终端 1stLine
上写,有没有一种快速获取字母 e
的方法,而不是仅仅循环到它?
我看到了这个 post 但我认为它对我不起作用,即使我只是创建数组而不用 fgets
填充它,sizeof line
已经是 10 因为数组中已经有东西
我知道这不是 java 而且我不能只是 .giveMeLastItem()
,但我想知道是否有比循环直到 \n
之前的字符更聪明的方法来获得我写的最后一封信
代码类似于
char command[6];
fgets(command,6,stdin);
如果您知道标记值,例如:[=10=]
(或 \n
,或与此相关的任何值),并且您想要紧接在其之前的元素的值,您可以
- 使用
strchr()
找出哨兵的位置并
- 获取
retPtr-1
的地址并取消引用以获得您想要的值。
一旦你只有数组,就没有其他方法可以做到这一点。您可以使用 strlen(line)
然后根据该索引获取最后一个字符的位置,但这基本上完全相同(遍历数组)。
char lastChar = line[strlen(line)-1];
时间复杂度为 O(n),其中 n 是输入长度。
您可以将输入法改为char by char input并计算长度或存储最后一次输入。像这样的每个 O(1) 方法之前都使用 O(n) 时间(就像你读取的每个字符的 n 次 O(1))。但是除非你必须真正加速优化(当你使用用户输入时你不需要)应该只使用像 strlen(line)
这样的函数遍历数组(并存储结果,当你多次使用它时).
编辑:
strchr()
函数 Sourav Ghosh 提到的功能完全相同,但你 can/must 指定终止字符。
有许多不同的方法可以检查 fgets()
读取的行:
首先你应该检查 fgets()
的 return 值: NULL
的 return 值意味着到达文件末尾或发生某种错误,目标数组的内容未定义。也建议使用更长的数组。
char command[80];
if (fgets(command, sizeof command, stdin) == NULL) {
// end of file or read error
return -1;
}
你可以用len = strlen(command)
计算字符数,如果这个长度os不为零(*),command[len - 1]
是从文件,如果该行少于 5 个字节,它应该是 '\n'
。剥离换行需要测试:
size_t len = strlen(command);
if (len > 0 && command[len - 1] == '\n')
command[--len] = '[=11=]';
你可以使用strchr()
来定位换行符,如果有char *p strchr(command, '\n');
如果有换行符,你可以这样去掉它:
char *p = strchar(command, '\n');
if (p != NULL)
*p = '[=12=]';
你也可以用pos = strcspn(command, "\n")
统计"\n"
集合中的字符数。 pos
将指向换行符或空终止符。因此你可以去掉尾随的换行符:
command[strcspn(command, "\n")] = '[=13=]'; // strip the newline if any
你也可以写一个简单的循环:
char *p = command;
while (*p && *p != '\n')
p++;
*p = '\n'; // strip the newline if any
(*) strlen(command)
可以 return 0
如果文件在行首包含嵌入的空字符。 fgets()
将空字节视为普通字符,它会继续将字节读入数组,直到读取 size - 1
个字节或读取一个换行符。
一个简单的方法可以看成下面的方式
char last_letter = command[ strcspn( command, "\n" ) - 1 ];
前提是字符串不为空或只包含换行符 '\n'
.
这是一个演示程序。
#include <stdio.h>
#include <string.h>
int main(void)
{
enum { N = 10 };
char command[N];
while ( fgets( command, N, stdin ) && command[0] != '\n' )
{
char last_letter = command[ strcspn( command, "\n" ) - 1 ];
printf( "%c ", last_letter );
}
putchar( '\n' );
return 0;
}
如果要输入下面的字符串序列
Is
there
a
quick
way
to
get
the
last
element
that
was
put
in
an
array?
那么输出将是
s e a k y o t e t t t s t n n ?
最快的方法是像这样保留一个引用数组:
long ref[]
和 ref[x] 包含第 x 行最后一个字符的文件偏移量。将此引用保存在文件的开头,您将执行如下操作:
fseek(n*sizeof(long))
long ref = read_long()
fseek(ref)
read_char()
我认为这是读取第 n 行末尾最后一个字符的最快方法。
除了其他好的例子。
另一种方法是使用 fscanf()
/scanf()
和 %n
格式说明符将输入字符串后到目前为止读取的字符数写入参数。
然后你把这个数减一,然后用它作为 command
:
的索引
char command[6];
int n = 0;
if (fscanf(stdin, "%5[^\n]" "%n", command, &n) != 1)
{
fputs("Error at input!", stderr);
// error routine.
}
getchar();
if (n != 0)
{
char last_letter = command[n-1];
}
#include <stdio.h>
int main (void)
{
char command[6];
int n = 0;
if (fscanf(stdin, "%5[^\n]" "%n", command, &n) != 1)
{
fputs("Error at input!", stderr);
// error routine.
}
getchar();
if (n != 0)
{
char last_letter = command[n-1];
putchar(last_letter);
}
return 0;
}
执行:
./a.out
hello
o
我对上述三种从流中读取一行并测量其长度的方法进行了快速测试。我读 /usr/share/dict/words 100 次并用 clock()/1000:
测量
fgets + strlen = 420
getc = 510
fscanf with " 100[^\n]%n" = 940
这是有道理的,因为 fgets 和 strlen 只执行 2 次调用,getc 每个字符执行一次调用,而 fscanf 可能执行一次调用,但要设置很多机制来处理复杂的格式,因此开销更多。请注意 fscanf 格式中添加的 space 以跳过上一行留下的换行符。
我使用 fgets
从 stdin
中读取一行并将其保存在 char
数组中,我想获取我写的行的最后一个字母,应该在\n
和[=15=]
.
例如,如果我有一个 char line[10]
并在终端 1stLine
上写,有没有一种快速获取字母 e
的方法,而不是仅仅循环到它?
我看到了这个 post fgets
填充它,sizeof line
已经是 10 因为数组中已经有东西
我知道这不是 java 而且我不能只是 .giveMeLastItem()
,但我想知道是否有比循环直到 \n
之前的字符更聪明的方法来获得我写的最后一封信
代码类似于
char command[6];
fgets(command,6,stdin);
如果您知道标记值,例如:[=10=]
(或 \n
,或与此相关的任何值),并且您想要紧接在其之前的元素的值,您可以
- 使用
strchr()
找出哨兵的位置并 - 获取
retPtr-1
的地址并取消引用以获得您想要的值。
一旦你只有数组,就没有其他方法可以做到这一点。您可以使用 strlen(line)
然后根据该索引获取最后一个字符的位置,但这基本上完全相同(遍历数组)。
char lastChar = line[strlen(line)-1];
时间复杂度为 O(n),其中 n 是输入长度。
您可以将输入法改为char by char input并计算长度或存储最后一次输入。像这样的每个 O(1) 方法之前都使用 O(n) 时间(就像你读取的每个字符的 n 次 O(1))。但是除非你必须真正加速优化(当你使用用户输入时你不需要)应该只使用像 strlen(line)
这样的函数遍历数组(并存储结果,当你多次使用它时).
编辑:
strchr()
函数 Sourav Ghosh 提到的功能完全相同,但你 can/must 指定终止字符。
有许多不同的方法可以检查 fgets()
读取的行:
首先你应该检查
fgets()
的 return 值:NULL
的 return 值意味着到达文件末尾或发生某种错误,目标数组的内容未定义。也建议使用更长的数组。char command[80]; if (fgets(command, sizeof command, stdin) == NULL) { // end of file or read error return -1; }
你可以用
len = strlen(command)
计算字符数,如果这个长度os不为零(*),command[len - 1]
是从文件,如果该行少于 5 个字节,它应该是'\n'
。剥离换行需要测试:size_t len = strlen(command); if (len > 0 && command[len - 1] == '\n') command[--len] = '[=11=]';
你可以使用
strchr()
来定位换行符,如果有char *p strchr(command, '\n');
如果有换行符,你可以这样去掉它:char *p = strchar(command, '\n'); if (p != NULL) *p = '[=12=]';
你也可以用
pos = strcspn(command, "\n")
统计"\n"
集合中的字符数。pos
将指向换行符或空终止符。因此你可以去掉尾随的换行符:command[strcspn(command, "\n")] = '[=13=]'; // strip the newline if any
你也可以写一个简单的循环:
char *p = command; while (*p && *p != '\n') p++; *p = '\n'; // strip the newline if any
(*) strlen(command)
可以 return 0
如果文件在行首包含嵌入的空字符。 fgets()
将空字节视为普通字符,它会继续将字节读入数组,直到读取 size - 1
个字节或读取一个换行符。
一个简单的方法可以看成下面的方式
char last_letter = command[ strcspn( command, "\n" ) - 1 ];
前提是字符串不为空或只包含换行符 '\n'
.
这是一个演示程序。
#include <stdio.h>
#include <string.h>
int main(void)
{
enum { N = 10 };
char command[N];
while ( fgets( command, N, stdin ) && command[0] != '\n' )
{
char last_letter = command[ strcspn( command, "\n" ) - 1 ];
printf( "%c ", last_letter );
}
putchar( '\n' );
return 0;
}
如果要输入下面的字符串序列
Is
there
a
quick
way
to
get
the
last
element
that
was
put
in
an
array?
那么输出将是
s e a k y o t e t t t s t n n ?
最快的方法是像这样保留一个引用数组:
long ref[]
和 ref[x] 包含第 x 行最后一个字符的文件偏移量。将此引用保存在文件的开头,您将执行如下操作:
fseek(n*sizeof(long))
long ref = read_long()
fseek(ref)
read_char()
我认为这是读取第 n 行末尾最后一个字符的最快方法。
除了其他好的例子。
另一种方法是使用 fscanf()
/scanf()
和 %n
格式说明符将输入字符串后到目前为止读取的字符数写入参数。
然后你把这个数减一,然后用它作为 command
:
char command[6];
int n = 0;
if (fscanf(stdin, "%5[^\n]" "%n", command, &n) != 1)
{
fputs("Error at input!", stderr);
// error routine.
}
getchar();
if (n != 0)
{
char last_letter = command[n-1];
}
#include <stdio.h>
int main (void)
{
char command[6];
int n = 0;
if (fscanf(stdin, "%5[^\n]" "%n", command, &n) != 1)
{
fputs("Error at input!", stderr);
// error routine.
}
getchar();
if (n != 0)
{
char last_letter = command[n-1];
putchar(last_letter);
}
return 0;
}
执行:
./a.out
hello
o
我对上述三种从流中读取一行并测量其长度的方法进行了快速测试。我读 /usr/share/dict/words 100 次并用 clock()/1000:
测量fgets + strlen = 420
getc = 510
fscanf with " 100[^\n]%n" = 940
这是有道理的,因为 fgets 和 strlen 只执行 2 次调用,getc 每个字符执行一次调用,而 fscanf 可能执行一次调用,但要设置很多机制来处理复杂的格式,因此开销更多。请注意 fscanf 格式中添加的 space 以跳过上一行留下的换行符。