我试图从用户获得一些数据,并将其发送到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';

如果每一行都有'\n',则直接从fgets输出中删除'\n'

line[strlen(line) - 1] = '\0';

否则:

void remove_newline_ch(char *line)
{
    int new_line = strlen(line) -1;
    if (line[new_line] == '\n')
        line[new_line] = '\0';
}

下面是一个从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.


也许最简单的解决方案是使用我最喜欢的一个鲜为人知的函数strcspn():

buffer[strcspn(buffer, "\n")] = 0;

如果你想让它也处理'\r'(比如,如果流是二进制的):

buffer[strcspn(buffer, "\r\n")] = 0; // works for LF, CR, CRLF, LFCR, ...

该函数会计算字符的数量,直到遇到'\r'或'\n'(换句话说,它会找到第一个'\r'或'\n')。如果它没有碰到任何东西,它就会停在'\0'(返回字符串的长度)。

请注意,即使没有换行符,这也可以正常工作,因为strcspn在'\0'处停止。在这种情况下,整行代码只是将“\0”替换为“\0”。


对于单个“\n”切边,

void remove_new_line(char* string)
{
    size_t length = strlen(string);
    if((length > 0) && (string[length-1] == '\n'))
    {
        string[length-1] ='\0';
    }
}

对于多个“\n”切边,

void remove_multi_new_line(char* string)
{
  size_t length = strlen(string);
  while((length>0) && (string[length-1] == '\n'))
  {
      --length;
      string[length] ='\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;
}

下面的函数是我在Github上维护的字符串处理库的一部分。它从字符串中删除不需要的字符,这正是你想要的

int zstring_search_chr(const char *token,char s){
    if (!token || s=='\0')
        return 0;

    for (;*token; token++)
        if (*token == s)
            return 1;

    return 0;
}

char *zstring_remove_chr(char *str,const char *bad) {
    char *src = str , *dst = str;
    while(*src)
        if(zstring_search_chr(bad,*src))
            src++;
        else
            *dst++ = *src++;  /* assign first, then incement */

    *dst='\0';
        return str;
}

一个示例用法是

Example Usage
      char s[]="this is a trial string to test the function.";
      char const *d=" .";
      printf("%s\n",zstring_remove_chr(s,d));

  Example Output
      thisisatrialstringtotestthefunction

你可能想要检查其他可用的功能,甚至为项目贡献:) https://github.com/fnoyanisi/zString


 for(int i = 0; i < strlen(Name); i++ )
{
    if(Name[i] == '\n') Name[i] = '\0';
}

你应该试试。这段代码基本上遍历字符串,直到找到'\n'。当它被找到时,'\n'将被空字符结束符'\0'取代

注意,在这一行中比较的是字符而不是字符串,那么就不需要使用strcmp():

if(Name[i] == '\n') Name[i] = '\0';

因为你将使用单引号而不是双引号。如果你想了解更多,这里有一个关于单引号和双引号的链接


如果可以选择使用getline(不要忽略其安全性问题),如果希望使用大括号指针,则可以避免使用字符串函数,因为getline返回的是字符数。如下图所示

#include <stdio.h>
#include <stdlib.h>
int main()
{
    char *fname, *lname;
    size_t size = 32, nchar; // Max size of strings and number of characters read
    fname = malloc(size * sizeof *fname);
    lname = malloc(size * sizeof *lname);
    if (NULL == fname || NULL == lname)
    {
        printf("Error in memory allocation.");
        exit(1);
    }
    printf("Enter first name ");
    nchar = getline(&fname, &size, stdin);
    if (nchar == -1) // getline return -1 on failure to read a line.
    {
        printf("Line couldn't be read..");
        // This if block could be repeated for next getline too
        exit(1);
    }
    printf("Number of characters read :%zu\n", nchar);
    fname[nchar - 1] = '\0';
    printf("Enter last name ");
    nchar = getline(&lname, &size, stdin);
    printf("Number of characters read :%zu\n", nchar);
    lname[nchar - 1] = '\0';
    printf("Name entered %s %s\n", fname, lname);
    return 0;
}

注意:getline的[安全问题]不应该被忽视。


我的新手方式;-)请让我知道这是正确的。这似乎对我所有的案子都有效:

#define IPT_SIZE 5

int findNULL(char* arr)
{
    for (int i = 0; i < strlen(arr); i++)
    {
        if (*(arr+i) == '\n')
        {
            return i;
        }
    }
    return 0;
}

int main()
{
    char *input = malloc(IPT_SIZE + 1 * sizeof(char)), buff;
    int counter = 0;

    //prompt user for the input:
    printf("input string no longer than %i characters: ", IPT_SIZE);
    do
    {
        fgets(input, 1000, stdin);
        *(input + findNULL(input)) = '\0';
        if (strlen(input) > IPT_SIZE)
        {
            printf("error! the given string is too large. try again...\n");
            counter++;
        }
        //if the counter exceeds 3, exit the program (custom function):
        errorMsgExit(counter, 3); 
    }
    while (strlen(input) > IPT_SIZE);

//rest of the program follows

free(input)
return 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){}。


一般来说,与其删除不想要的数据,不如从一开始就避免写入数据。如果你不想在缓冲区中使用换行符,不要使用fgets。相反,请使用getc或fgetc或scanf。也许是这样的:

#include <stdio.h>
#include <stdlib.h>
int
main(void)
{
        char Name[256];
        char fmt[32];
        if( snprintf(fmt, sizeof fmt, "%%%zd[^\n]", sizeof Name - 1) >= (int)sizeof fmt ){
                fprintf(stderr, "Unable to write format\n");
                return EXIT_FAILURE;
        }
        if( scanf(fmt, Name) == 1 ) {
                printf("Name = %s\n", Name);
        }
        return 0;
}

注意,这种特殊的方法将不读取换行符,因此您可能希望使用像“%255[^\n]%*c”这样的格式字符串来丢弃它(例如,sprintf(fmt,“%%%zd[^\n]%%*c”,sizeof Name - 1);),或者可能在scanf后面加上getchar()。


这就是我的解。非常简单。

// 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';
    }
}