Xóa ký tự dòng mới khỏi đầu vào fgets ()


235

Tôi đang cố gắng để có được một số dữ liệu từ người dùng và gửi nó đến một chức năng khác trong gcc. Mã là một cái gì đó như thế này.

printf("Enter your Name: ");
if (!(fgets(Name, sizeof Name, stdin) != NULL)) {
    fprintf(stderr, "Error reading Name.\n");
    exit(1);
}

Tuy nhiên, tôi thấy rằng \ncuối cùng nó có một nhân vật mới . Vì vậy, nếu tôi nhập Johnnó kết thúc gửi John\n. Làm thế nào để tôi loại bỏ điều đó \nvà gửi một chuỗi thích hợp.


21
if (!fgets(Name, sizeof Name, stdin))(ít nhất là không sử dụng hai phủ định ,! và! =)

4
@Roger Pate "không sử dụng hai phủ định" -> hmmm, nếu chúng ta đào sâu "không" và "phủ định" đều là phủ định . ;-). Có lẽ "Sử dụng if (fgets(Name, sizeof Name, stdin)) {.
chux - Phục hồi Monica

3
@chux, tôi chắc chắn ý bạn làif (fgets(Name, sizeof Name, stdin) == NULL ) {
R Sahu

@RSahu Đúng : pesky !:
chux - Tái lập Monica

Câu trả lời:


154

Cách hơi xấu xí:

char *pos;
if ((pos=strchr(Name, '\n')) != NULL)
    *pos = '\0';
else
    /* input too long for buffer, flag error */

Cách hơi lạ:

strtok(Name, "\n");

Lưu ý rằng strtokchức năng không hoạt động như mong đợi nếu người dùng nhập một chuỗi trống (tức là chỉ nhấn Enter). Nó để lại \nnhân vật nguyên vẹn.

Có những người khác là tốt, tất nhiên.


7
Bất kỳ thư viện thời gian chạy C nào nhận biết luồng (có nghĩa là, hầu hết mọi thư mục nhắm đến nền tảng đa luồng), strtok()sẽ an toàn cho luồng (nó sẽ sử dụng lưu trữ cục bộ của luồng cho trạng thái 'gọi liên'). Điều đó nói rằng, nói chung vẫn tốt hơn để sử dụng biến thể không chuẩn (nhưng đủ phổ biến) strtok_r().
Michael Burr

2
Xem câu trả lời của tôi cho biến thể hoàn toàn an toàn và reentrant, tương tự như strtokcách tiếp cận của bạn (và nó hoạt động với đầu vào trống). Trong thực tế, một cách tốt để thực hiện strtoklà sử dụng strcspnstrspn.
Tim Čas

2
Điều quan trọng là phải xử lý trường hợp khác nếu bạn ở trong môi trường có nguy cơ đường dây quá dài. Âm thầm cắt đầu vào có thể gây ra lỗi rất nguy hiểm.
Malcolm McLean

2
Nếu bạn thích một lớp lót và đang sử dụng glibc, hãy thử *strchrnul(Name, '\n') = '\0';.
twobit

Khi strchr(Name, '\n') == NULL, sau đó ngoài "đầu vào quá lâu cho bộ đệm, lỗi cờ", các khả năng khác tồn tại: Văn bản stdincuối cùng không kết thúc bằng một '\n'hoặc một ký tự null được nhúng hiếm được đọc.
chux - Phục hồi Monica

439

Có lẽ giải pháp đơn giản nhất sử dụng một trong những chức năng ít được biết đến yêu thích của tôi strcspn():

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

Nếu bạn muốn nó cũng xử lý '\r'(giả sử, nếu luồng là nhị phân):

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

Hàm đếm số ký tự cho đến khi nó chạm a '\r'hoặc a '\n'(nói cách khác, nó tìm thấy đầu tiên '\r'hoặc '\n'). Nếu nó không trúng bất cứ thứ gì, nó dừng lại ở '\0'(trả về độ dài của chuỗi).

Lưu ý rằng điều này hoạt động tốt ngay cả khi không có dòng mới, bởi vì strcspndừng lại ở a '\0'. Trong trường hợp đó, toàn bộ dòng chỉ đơn giản là thay thế '\0'bằng '\0'.


30
Điều này thậm chí xử lý hiếm bufferhơn bắt đầu với '\0', một cái gì đó gây đau buồn cho buffer[strlen(buffer) - 1] = '\0';cách tiếp cận.
chux - Phục hồi lại

5
@chux: Yup, tôi ước nhiều người biết đến hơn strcspn(). Một trong những chức năng hữu ích hơn trong thư viện, IMO. Tôi đã quyết định viết và xuất bản một loạt các bản hack C phổ biến như thế này ngày hôm nay; một strtok_rtriển khai sử dụng strcspnstrspnlà một trong những cách đầu tiên: codepad.org/2lBkZk0w ( Cảnh báo: Tôi không thể đảm bảo rằng nó không có lỗi; nó được viết vội vàng và có thể có một vài). Mặc dù vậy, tôi không biết nơi nào tôi sẽ xuất bản chúng, nhưng tôi dự định sẽ thực hiện nó theo tinh thần của "hack twiddling" nổi tiếng.
Tim Čas

4
Nhìn vào các cách để mạnh mẽ cắtfgets() . Đây strcspn()có vẻ là chỉ một lót chính xác. strlenlà nhanh hơn - mặc dù không đơn giản.
chux - Tái lập Monica

6
@sidbushes: Câu hỏi, cả trong tiêu đề và nội dung, đều hỏi về dòng mới từ fgets()đầu vào . Mà luôn luôn là dòng mới đầu tiên.
Tim Čas

9
@sidbushes: Tôi hiểu bạn đến từ đâu, nhưng tôi không thể chịu trách nhiệm về kết quả tìm kiếm của Google đối với các cụm từ cụ thể. Nói chuyện với Google, không phải tôi.
Tim as

83
size_t ln = strlen(name) - 1;
if (*name && name[ln] == '\n') 
    name[ln] = '\0';

8
Có lẽ sẽ ném ngoại lệ nếu chuỗi trống, phải không? Giống như chỉ số ngoài phạm vi.
Edward Olamisan

1
@EdwardOlamisan, tuy nhiên, chuỗi sẽ không bao giờ trống.
James Morris

5
@James Morris Trong trường hợp bất thường fgets(buf, size, ....)-> strlen(buf) == 0. 1) fgets()đọc là đầu tiên chara '\0'. 2) size == 13) fgets()trả về NULLthì bufnội dung có thể là bất cứ điều gì. (Mặc dù mã của OP kiểm tra NULL) Đề xuất:size_t ln = strlen(name); if (ln > 0 && name[ln-1] == '\n') name[--ln] = '\0';
chux - Phục hồi lại

2
Nếu chuỗi rỗng thì sao? lnsẽ là -1, lưu cho thực tế size_tlà không dấu, do đó ghi vào bộ nhớ ngẫu nhiên. Tôi nghĩ bạn muốn sử dụng ssize_tvà kiểm tra lnlà> 0.
abligh

2
@ legends2k: Việc tìm kiếm giá trị thời gian biên dịch (đặc biệt là giá trị 0 như trong strlen) có thể được thực hiện hiệu quả hơn nhiều so với tìm kiếm char-by-char đơn giản. Vì lý do nào tôi sẽ xem xét giải pháp này tốt hơn một strchrhoặc strcspndựa trên giải pháp .
AnT

17

Dưới đây là cách tiếp cận nhanh để loại bỏ tiềm năng '\n'khỏi chuỗi được lưu bởi fgets().
Nó sử dụng strlen(), với 2 bài kiểm tra.

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

Bây giờ sử dụng bufferlenkhi cần thiết.

Phương pháp này có lợi ích phụ của một lengiá trị cho mã tiếp theo. Nó có thể dễ dàng nhanh hơn strchr(Name, '\n'). Tham khảo YMMV, nhưng cả hai phương pháp đều hoạt động.


buffer, từ bản gốc fgets()sẽ không chứa trong "\n"một số trường hợp:
A) Dòng quá dài buffernên chỉ có chartrước dòng '\n'được lưu trong buffer. Các ký tự chưa đọc vẫn còn trong luồng.
B) Dòng cuối cùng trong tệp không kết thúc bằng a '\n'.

Nếu đầu vào có nhúng các ký tự null '\0'ở đâu đó, độ dài được báo cáo strlen()sẽ không bao gồm '\n'vị trí.


Một số vấn đề khác của câu trả lời:

  1. strtok(buffer, "\n");thất bại trong việc loại bỏ các '\n'khi buffer"\n". Từ câu trả lời này - được sửa đổi sau câu trả lời này để cảnh báo về giới hạn này.

  2. Sau đây thất bại vào những dịp hiếm hoi khi là người đầu tiên charđọc bởi fgets()'\0'. Điều này xảy ra khi đầu vào bắt đầu với một nhúng '\0'. Sau đó buffer[len -1]trở thành buffer[SIZE_MAX]truy cập bộ nhớ chắc chắn nằm ngoài phạm vi hợp pháp của buffer. Một cái gì đó tin tặc có thể thử hoặc tìm thấy trong việc dại dột đọc các tệp văn bản UTF16. Đây là trạng thái của một câu trả lời khi câu trả lời này được viết. Sau đó, một người không phải OP đã chỉnh sửa nó để bao gồm mã như kiểm tra câu trả lời này "".

    size_t len = strlen(buffer);
    if (buffer[len - 1] == '\n') {  // FAILS when len == 0
      buffer[len -1] = '\0';
    }
  3. sprintf(buffer,"%s",buffer);là hành vi không xác định: Tham chiếu . Hơn nữa, nó không lưu bất kỳ khoảng trắng hàng đầu, tách hoặc dấu. Bây giờ đã xóa .

  4. [Chỉnh sửa do câu trả lời sau tốt ] Không có vấn đề gì với lớp lót 1 buffer[strcspn(buffer, "\n")] = 0;ngoài hiệu năng so với strlen()cách tiếp cận. Hiệu suất trong việc cắt xén thường không phải là vấn đề do mã được thực hiện I / O - một lỗ đen về thời gian của CPU. Nếu mã sau cần độ dài của chuỗi hoặc có ý thức hiệu suất cao, hãy sử dụng strlen()phương pháp này . Khác strcspn()là một thay thế tốt.


Cảm ơn câu trả lời hữu ích. Chúng ta có thể sử dụng strlen(buffer)khi kích thước bộ đệm được phân bổ động bằng cách sử dụng mallockhông?
rrz0

@ Rrz0 buffer = malloc(allocation_size); length = strlen(buffer);là xấu - dữ liệu tại bộ nhớ được trỏ đến bufferlà không xác định. buffer = malloc(allocation_size_4_or_more); strcpy(buffer, "abc"); length = strlen(buffer);vẫn ổn
chux - Phục hồi lại

cảm ơn vì điều đó!! Tôi đang tham gia một khóa học CS và điều này rất hữu ích cho một trong những bài tập. tôi ghi có câu trả lời của bạn trong mã nguồn.
Nathaniel Hoyt

8

Trực tiếp để xóa '\ n' khỏi đầu ra fgets nếu mỗi dòng có '\ n'

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

Nếu không thì:

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

1
Lưu ý rằng nó sẽ an toàn hơn để sử dụng strnlenthay vì strlen.
Mike Mertsock

3
Một nhận xét cho câu trả lời đầu tiên trong câu hỏi được liên kết trạng thái "Lưu ý rằng strlen (), strcmp () và strdup () là an toàn. Các lựa chọn thay thế 'n' cung cấp cho bạn chức năng bổ sung."
Étienne

4
@esker không, nó sẽ không. chèn một nkhông kỳ diệu làm tăng sự an toàn, trong trường hợp này thực tế nó sẽ làm cho mã nguy hiểm hơn. Tương tự như vậy strncpy, một chức năng không an toàn khủng khiếp. Bài đăng bạn liên kết đến là lời khuyên tồi.
MM

3
Điều này thất bại thảm hại cho một chuỗi rỗng ( ""). Cũng strlen()trả lại size_tkhông int.
alk

4
Điều này không an toàn cho một chuỗi rỗng, nó sẽ ghi ở chỉ số -1. Đừng dùng cái này.
Jean-François Fabre

3

Đối với cắt xén '\ n',

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

để cắt tỉa nhiều '\ n',

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

1
Tại sao lồng ifkhi bạn chỉ có thể viết một điều kiện bằng cách sử dụng &&? whileVòng lặp đó có cấu trúc kỳ lạ; nó chỉ đơn giản có thể while (length > 0 && string[length-1] == '\n') { --length; string[length] = '\0'; }.
melpomene

@melpomene cảm ơn bạn đã gợi ý. Cập nhật mã.
BEPP

1
Tôi muốn đề xuất rằng hàm đầu tiên được định nghĩa tự nhiên hơn là : size_t length = strlen(string); if (length > 0 && string[length-1] == '\n') { string[length-1] = '\0'; }. Điều này cũng phản ánh định nghĩa thứ hai tốt hơn (chỉ sử dụng ifthay vì while).
melpomene

@elpomene cảm ơn. Nó có ý nghĩa. Tôi đã cập nhật mã.
BEPP

1

Cách Newbie của tôi ;-) Xin vui lòng cho tôi biết nếu điều đó đúng. Nó dường như đang làm việc cho tất cả các trường hợp của tôi:

#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;
}

1

Các bước để loại bỏ ký tự dòng mới theo cách có lẽ rõ ràng nhất:

  1. Xác định độ dài của chuỗi bên trong NAMEbằng cách sử dụng strlen(), tiêu đề string.h. Lưu ý rằng strlen()không tính chấm dứt \0.
size_t sl = strlen(NAME);

  1. Hãy xem nếu chuỗi bắt đầu bằng hoặc chỉ bao gồm một \0ký tự (chuỗi trống). Trong trường hợp này slsẽ là 0strlen()như tôi đã nói ở trên không đếm được \0và dừng lại ở lần xuất hiện đầu tiên của nó:
if(sl == 0)
{
   // Skip the newline replacement process.
}

  1. Kiểm tra xem ký tự cuối cùng của chuỗi thích hợp có phải là ký tự dòng mới không '\n'. Nếu đây là trường hợp, thay thế \nbằng a \0. Lưu ý rằng số lượng chỉ mục bắt đầu tại 0vì vậy chúng tôi sẽ cần phải làm NAME[sl - 1]:
if(NAME[sl - 1] == '\n')
{
   NAME[sl - 1] = '\0';
}

Lưu ý nếu bạn chỉ nhấn Enter tại fgets()yêu cầu chuỗi (nội dung chuỗi chỉ bao gồm một ký tự dòng mới), chuỗi trong đó NAMEsẽ là một chuỗi trống sau đó.


  1. Chúng ta có thể kết hợp bước 2. và 3. với nhau chỉ trong một giai đoạn ifbằng cách sử dụng toán tử logic &&:
if(sl > 0 && NAME[sl - 1] == '\n')
{
   NAME[sl - 1] = '\0';
}

  1. Mã hoàn thành:
size_t sl = strlen(NAME);
if(sl > 0 && NAME[sl - 1] == '\n')
{
   NAME[sl - 1] = '\0';
}

Nếu bạn thích một hàm để sử dụng kỹ thuật này bằng cách xử lý các fgetschuỗi đầu ra nói chung mà không cần gõ lại mỗi lần, thì đây là 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';
    }
}

Trong ví dụ được cung cấp của bạn, nó sẽ là:

printf("Enter your Name: ");

if (fgets(Name, sizeof Name, stdin) == NULL) {
    fprintf(stderr, "Error reading Name.\n");
    exit(1);
}
else {
    fgets_newline_kill(NAME);
}

Lưu ý rằng phương thức này không hoạt động nếu chuỗi đầu vào có nhúng \0s trong nó. Nếu đó là trường hợp strlen()sẽ chỉ trả lại số lượng ký tự cho đến đầu tiên \0. Nhưng đây không phải là một cách tiếp cận phổ biến, vì hầu hết các hàm đọc chuỗi thường dừng lại ở đầu tiên \0và lấy chuỗi cho đến ký tự null đó.

Ngoài câu hỏi về chính nó. Cố gắng tránh các phủ định kép làm cho mã của bạn không rõ ràng : if (!(fgets(Name, sizeof Name, stdin) != NULL) {}. Bạn chỉ có thể làm if (fgets(Name, sizeof Name, stdin) == NULL) {}.


Không chắc chắn tại sao bạn muốn làm điều này. Điểm loại bỏ các dòng mới không phải là chuỗi kết thúc null; nó là để loại bỏ các dòng mới. Thay thế một \nbằng một \0cuối chuỗi là một cách "loại bỏ" dòng mới. Nhưng thay thế các \nký tự trong một chuỗi về cơ bản sẽ thay đổi chuỗi. Không có gì lạ khi có các chuỗi có nhiều ký tự dòng mới có chủ ý và điều này sẽ cắt đứt một cách hiệu quả các đầu của các chuỗi đó. Để loại bỏ các dòng mới như vậy, nội dung mảng cần dịch chuyển sang trái để ghi đè lên \n.
ex nihilo

@exnihilo Làm thế nào một người nào đó có thể nhập một chuỗi có nhiều dòng mới bên trong bằng cách sử dụng fgets()?
RobertS hỗ trợ Monica Cellio

Chà, bạn có thể nối các chuỗi thu được bằng nhiều lệnh gọi đến fgets(). Nhưng tôi không hiểu sự phản đối của bạn: bạn là người đề xuất mã để xử lý nhiều dòng mới.
ex nihilo

@exnihilo Bạn hay nói đúng, tôi sẽ lật đổ chiến lược. Tôi chỉ muốn thêm một cách rất khắc nghiệt nhưng có thể để có được kết quả mong muốn.
RobertS hỗ trợ Monica Cellio

@exnihilo Đã chỉnh sửa hoàn toàn câu trả lời của tôi và làm theo cách tiếp cận chính bằng cách sử dụng, strlenvv Biện minh cho việc không bị trùng lặp: 1. Giải thích mã theo các bước. 2. Được cung cấp như chức năng và giải pháp dựa trên bối cảnh. 3. Gợi ý để tránh các biểu thức phủ định kép.
RobertS hỗ trợ Monica Cellio

0

Tim là một lớp lót rất tuyệt vời đối với các chuỗi có được bởi một lệnh gọi đến fget, bởi vì bạn biết chúng chứa một dòng mới ở cuối.

Nếu bạn đang ở trong một bối cảnh khác và muốn xử lý các chuỗi có thể chứa nhiều dòng mới, bạn có thể đang tìm kiếm strrspn. Nó không phải là POSIX, có nghĩa là bạn sẽ không tìm thấy nó trên tất cả các Thông báo. Tôi đã viết một cho nhu cầu của riêng tôi.

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

Đối với những người tìm kiếm một Perl chomp tương đương trong C, tôi nghĩ rằng đây là nó (chomp chỉ loại bỏ dòng mới).

line[strrspn(string, "\r\n")] = 0;

Hàm 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;
}

1
"bởi vì bạn biết rằng chúng chứa một dòng mới ở cuối." -> Nó thậm chí hoạt động khi không có '\n'(hoặc nếu chuỗi là "").
chux - Phục hồi Monica

Đáp lại chux bình luận đầu tiên của bạn, câu trả lời của tôi bảo tồn điều đó. Tôi đã phải ném resetlen strrcspnkhi không có \n.
Philippe A.

Tại sao sử dụng goto end;thay vì return len;?
chqrlie

@chqrlie Tôi cần phải thoát khỏi vòng lặp 2 cấp độ không phù hợp này mà tôi đã tham gia. Tác hại đã được thực hiện. Tại sao không phải là một goto?
Philippe A.

Bạn có hai loại gotos trong mã của mình: một thứ vô dụng gotocó thể được thay thế bằng một returntuyên bố và một thứ ngược gotođược coi là xấu xa. Sử dụng strchrgiúp triển khai strrspnstrrcspntheo cách đơn giản hơn: size_t strrspn(const char *s, const char *accept) { size_t len = strlen(s); while (len > 0 && strchr(accept, s[len - 1])) { len--; } return len; }size_t strrcspn(const char *s, const char *reject) { size_t len = strlen(s); while (len > 0 && !strchr(reject, s[len - 1])) { len--; } return len; }
chqrlie

0

Nếu sử dụng getlinelà một tùy chọn - Không bỏ qua các vấn đề bảo mật của nó và nếu bạn muốn kết hợp các con trỏ - bạn có thể tránh các hàm chuỗi khi getlinetrả về số lượng ký tự. Một cái gì đó như dưới đây

#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;
}

Lưu ý : Các [ vấn đề an ninh ] với getlinekhông nên bỏ qua mặc dù.


-1

Hàm bên dưới là một phần của thư viện xử lý chuỗi tôi đang duy trì trên Github. Nó loại bỏ và các ký tự không mong muốn khỏi một chuỗi, chính xác những gì bạn muốn

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

Một ví dụ sử dụng có thể là

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

Bạn có thể muốn kiểm tra các chức năng có sẵn khác hoặc thậm chí đóng góp cho dự án :) https://github.com/fnoyanisi/zString


Bạn nên loại bỏ *trong *src++;và thực hiện bad, tokend const char *. Ngoài ra tại sao không sử dụng strchrthay vì zChrSearch? *srckhông thể có '\0'trong zStrrmvchức năng của bạn .
chqrlie

Cảm ơn @chqrlie! đã cập nhật mã để phản ánh đề xuất của bạn ..... chuỗi bắt đầu như một dự án thú vị với mục đích tạo thư viện thao tác chuỗi mà không sử dụng bất kỳ chức năng thư viện tiêu chuẩn nào, do đó tôi không sử dụngstrchr
fnisi

1
Viết một " thư viện thao tác chuỗi mà không sử dụng bất kỳ chức năng thư viện tiêu chuẩn nào " là một bài tập hay, nhưng tại sao lại bảo người khác sử dụng nó? Nếu bất cứ điều gì, nó sẽ chậm hơn và ít được kiểm tra hơn bất kỳ thư viện tiêu chuẩn nào.
melpomene

Đây là một công việc khác với những gì câu hỏi yêu cầu. Nó có thể được sử dụng để thoát khỏi dòng mới duy nhất, nhưng nó cảm thấy như quá mức cần thiết.
Jonathan Leffler

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

Bạn nên cung cấp cho nó một thử. Mã này về cơ bản lặp qua chuỗi cho đến khi tìm thấy '\ n'. Khi tìm thấy '\ n' sẽ được thay thế bằng dấu kết thúc ký tự null '\ 0'

Lưu ý rằng bạn đang so sánh các ký tự và không phải chuỗi trong dòng này, thì không cần phải sử dụng strcmp ():

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

vì bạn sẽ sử dụng dấu ngoặc đơn và không phải dấu ngoặc kép. Đây là một liên kết về dấu ngoặc đơn so với dấu ngoặc kép nếu bạn muốn biết thêm


2
Sẽ tốt hơn nếu bạn giải thích và chỉnh sửa định dạng mã của mình.
Anh Phạm

Thông thường tốt hơn là giải thích một giải pháp thay vì chỉ đăng một số hàng mã ẩn danh. Bạn có thể đọc Làm thế nào để tôi viết một câu trả lời hay và cũng Giải thích các câu trả lời hoàn toàn dựa trên mã .
Massimiliano Kraus

1
Tôi xin lỗi đây là đóng góp đầu tiên của tôi ở đây. Tôi sẽ sửa nó. Cảm ơn đã phản hồi
Matheus Martins Jerônimo

3
Không hiệu quả: for(int i = 0; i < strlen(Name); i++ )sẽ gọi strlen(Name)nhiều lần (thay đổi vòng lặp Name[]) vì vậy với độ dài N, đây là một O(N*N)giải pháp. Chỉ cần 1 cuộc gọi đến strlen(Name), nếu có, để cung cấp giải pháp O (N) `. Không rõ tại sao int iđược sử dụng thay vì size_t i. Hãy xem xétfor(size_t i = 0; i < Name[i]; i++ )
chux - Tái lập Monica

@chux Giống hơnfor (size_t i = 0; Name[i]; i++) { if (Name[i] == '\n') { Name[i] = '\0'; break; } }
melpomene

-1

Hãy thử cái này:

        int remove_cr_lf(char *str)
        {
          int len =0;


          len = strlen(str);

          for(int i=0;i<5;i++)
          {
            if (len>0)
            if (str[len-1] == '\n')
            {
              str[len-1] = 0;
              len--;
            }

            if (len>0)
            if (str[len-1] == '\r')
            {
              str[len-1] = 0;
              len--;
            }
          }

          return 0;
        }

1
len = strlen(str)có thể tràn: strlentrả về size_t, không int. Điều gì với những if (len>0) if (...)điều kiện kỳ lạ ? Bạn không biết về &&? Nếu bạn định xóa nhiều phiên bản kéo dài của CR / LF, tại sao lại giới hạn ở mức 5? Tại sao không loại bỏ tất cả chúng? Tại sao hàm có intkiểu trả về khi nó luôn trả về 0? Tại sao không trở lại void?
melpomene
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.