我试图从用户获得一些数据,并将其发送到gcc中的另一个函数。代码是这样的。
printf("Enter your Name: ");
if (!(fgets(Name, sizeof Name, stdin) != NULL)) {
fprintf(stderr, "Error reading Name.\n");
exit(1);
}
然而,我发现它最后有一个换行符\n字符。如果我输入John,它最终会发送John\n。我如何删除\n并发送一个合适的字符串。
我试图从用户获得一些数据,并将其发送到gcc中的另一个函数。代码是这样的。
printf("Enter your Name: ");
if (!(fgets(Name, sizeof Name, stdin) != NULL)) {
fprintf(stderr, "Error reading Name.\n");
exit(1);
}
然而,我发现它最后有一个换行符\n字符。如果我输入John,它最终会发送John\n。我如何删除\n并发送一个合适的字符串。
当前回答
优雅的方式:
Name[strcspn(Name, "\n")] = 0;
略显丑陋的方式:
char *pos;
if ((pos=strchr(Name, '\n')) != NULL)
*pos = '\0';
else
/* input too long for buffer, flag error */
有点奇怪的方式:
strtok(Name, "\n");
注意,如果用户输入一个空字符串(即只按Enter), strtok函数就不能正常工作。它保留\n字符。
当然,还有其他原因。
其他回答
size_t ln = strlen(name) - 1;
if (*name && name[ln] == '\n')
name[ln] = '\0';
Tim Čas one line对于调用fgets获得的字符串来说非常神奇,因为您知道它们在末尾包含一个换行符。
如果您处于不同的上下文中,并且希望处理可能包含多个换行符的字符串,则可能需要查找strrspn。它不是POSIX,这意味着您不会在所有unix上找到它。我为自己的需要写了一个。
/* Returns the length of the segment leading to the last
characters of s in accept. */
size_t strrspn (const char *s, const char *accept)
{
const char *ch;
size_t len = strlen(s);
more:
if (len > 0) {
for (ch = accept ; *ch != 0 ; ch++) {
if (s[len - 1] == *ch) {
len--;
goto more;
}
}
}
return len;
}
对于那些在C中寻找等效Perl chomp的人来说,我认为这就是它(chomp只删除后面的换行符)。
line[strrspn(string, "\r\n")] = 0;
strrcspn函数:
/* Returns the length of the segment leading to the last
character of reject in s. */
size_t strrcspn (const char *s, const char *reject)
{
const char *ch;
size_t len = strlen(s);
size_t origlen = len;
while (len > 0) {
for (ch = reject ; *ch != 0 ; ch++) {
if (s[len - 1] == *ch) {
return len;
}
}
len--;
}
return origlen;
}
下面是一个从fgets()保存的字符串中删除潜在'\n'的快速方法。 它使用strlen(),带有2个测试。
char buffer[100];
if (fgets(buffer, sizeof buffer, stdin) != NULL) {
size_t len = strlen(buffer);
if (len > 0 && buffer[len-1] == '\n') {
buffer[--len] = '\0';
}
现在根据需要使用buffer和len。
该方法的附带好处是为后续代码提供len值。它可以比strchr(Name, '\n')更快。参考YMMV,但两种方法都有效。
在某些情况下,原始fgets()将不包含在"\n"中: A)行太长,不适合buffer,所以只有'\n'前面的char被保存在buffer中。未读字符保留在流中。 B)文件的最后一行没有以“\n”结尾。
如果输入在某个地方嵌入了空字符'\0',strlen()报告的长度将不包括'\n'位置。
其他一些回答的问题:
strtok(buffer, "\n"); fails to remove the '\n' when buffer is "\n". From this answer - amended after this answer to warn of this limitation. The following fails on rare occasions when the first char read by fgets() is '\0'. This happens when input begins with an embedded '\0'. Then buffer[len -1] becomes buffer[SIZE_MAX] accessing memory certainly outside the legitimate range of buffer. Something a hacker may try or found in foolishly reading UTF16 text files. This was the state of an answer when this answer was written. Later a non-OP edited it to include code like this answer's check for "". size_t len = strlen(buffer); if (buffer[len - 1] == '\n') { // FAILS when len == 0 buffer[len -1] = '\0'; } sprintf(buffer,"%s",buffer); is undefined behavior: Ref. Further, it does not save any leading, separating or trailing whitespace. Now deleted. [Edit due to good later answer] There are no problems with the 1 liner buffer[strcspn(buffer, "\n")] = 0; other than performance as compared to the strlen() approach. Performance in trimming is usually not an issue given code is doing I/O - a black hole of CPU time. Should following code need the string's length or is highly performance conscious, use this strlen() approach. Else the strcspn() is a fine alternative.
这就是我的解。非常简单。
// Delete new line
// char preDelete[256] include "\n" as newline after fgets
char deletedWords[256];
int iLeng = strlen(preDelete);
int iFinal = 0;
for (int i = 0; i < iLeng; i++) {
if (preDelete[i] == '\n') {
}
else {
deletedWords[iFinal] = preDelete[i];
iFinal++;
}
if (i == iLeng -1 ) {
deletedWords[iFinal] = '\0';
}
}
以最明显的方式删除换行符的步骤:
通过使用strlen(), header string.h来确定NAME内部字符串的长度。注意,strlen()不计算结束的\0。
size_t sl = strlen(NAME);
查看字符串是否以一个\0字符(空字符串)开头或只包含一个\0字符。在这种情况下,sl将为0,因为如上所述strlen()不会计算\0,并在它第一次出现时停止:
if(sl == 0)
{
// Skip the newline replacement process.
}
检查正确字符串的最后一个字符是否是换行符'\n'。如果是这种情况,将\n替换为\0。注意,索引计数从0开始,所以我们需要执行NAME[sl - 1]:
if(NAME[sl - 1] == '\n')
{
NAME[sl - 1] = '\0';
}
请注意,如果您只在fgets()字符串请求时按下Enter(字符串内容仅由换行符组成),则NAME中的字符串此后将成为空字符串。
我们可以结合第二步。和3。通过使用逻辑运算符&&,将它们组合在一个if语句中:
if(sl > 0 && NAME[sl - 1] == '\n')
{
NAME[sl - 1] = '\0';
}
完成的代码:
size_t sl = strlen(NAME);
if(sl > 0 && NAME[sl - 1] == '\n')
{
NAME[sl - 1] = '\0';
}
如果你更喜欢一个函数使用这种技术,一般处理fgets输出字符串,而不需要每次都重新输入,这里是fgets_newline_kill:
void fgets_newline_kill(char a[])
{
size_t sl = strlen(a);
if(sl > 0 && a[sl - 1] == '\n')
{
a[sl - 1] = '\0';
}
}
在您提供的示例中,它将是:
printf("Enter your Name: ");
if (fgets(Name, sizeof Name, stdin) == NULL) {
fprintf(stderr, "Error reading Name.\n");
exit(1);
}
else {
fgets_newline_kill(NAME);
}
注意,如果输入字符串中嵌入了\0,则此方法不起作用。如果是这样的话,strlen()将只返回第一个\0之前的字符数。但这并不是一种常见的方法,因为大多数字符串读取函数通常在第一个\0处停止,直到该空字符。
除了这个问题本身。尽量避免双重否定,这会使你的代码不清晰:(fgets(Name, sizeof Name, stdin) != NULL){}。你可以简单地执行if (fgets(Name, sizeof Name, stdin) == NULL){}。