Sử dụng printf với một chuỗi kết thúc không null


107

Giả sử bạn có một chuỗi KHÔNG nullbị kết thúc và bạn biết kích thước chính xác của nó, vậy làm cách nào bạn có thể in chuỗi đó bằng printfC? Tôi nhớ lại một phương pháp như vậy nhưng tôi không thể tìm ra bây giờ ...


9
Trong Cngữ cảnh, tất cả các chuỗi được kết thúc bằng rỗng. Mảng của char mà không có một null trong số đó là không dây ... họ là mảng của char :)
PMG


Câu trả lời:


174

Có một khả năng xảy ra với printf, nó sẽ như thế này:

printf("%.*s", stringLength, pointerToString);

Không cần sao chép bất cứ thứ gì, không cần sửa đổi chuỗi hoặc bộ đệm gốc.


10
Nhưng dù sao đó là nguy hiểm, ai đó sẽ một ngày nào đó printf chuỗi này với% s
pmod

6
@Pmod: Không nhất thiết nếu bộ đệm không tiếp xúc với thế giới bên ngoài. Nó cũng rất hữu ích khi chỉ in các phần của một chuỗi (tất nhiên là có thể kết thúc bằng null). Nếu bạn thực sự muốn thấy điều này trong thực tế, hãy xem proxy OpenSER / Kamailio SIP nơi họ tránh sao chép nội dung do kỹ thuật này rất nhiều (cũng sử dụng sprintf).
DarkDust

6
+1 khác. Tôi yêu nó khi tôi học những điều về những điều cơ bản như printfthậm chí sau một thập kỷ ~ ... :)
Hertzel Guinness

1
Đối với tôi, nó rất hữu ích khi tôi nhận được một chuỗi được kết thúc không phải null từ một API (một số API windows làm được điều này!) Và phải trả lại nó theo cách 'hợp lý'. . Vì vậy: tuổi thọ cao đến% * s (.! Hoặc% * S mà cũng sẽ làm cho UNICODE chuyển đổi <-> SINGLE-BYTE cho bạn;))
FrizzTheSnail

3
@ user1424739: Trong trường hợp của bạn, printfsẽ in tối đa 11 ký tự hoặc cho đến khi nó gặp NULL, tùy điều kiện nào đến trước; trong ví dụ của bạn, NULL đứng trước. Việc chỉ định độ dài tối đa không làm cho NULL mất đi ý nghĩa "end-of-string" đối với printf.
DarkDust 17/02/19

29

Đây là phần giải thích về cách thức %.*shoạt động và nơi nó được chỉ định.

Các thông số kỹ thuật chuyển đổi trong chuỗi mẫu printf có dạng chung:

% [ param-no $] flags width [ . precision ] type conversion

hoặc là

% [ param-no $] flags width . * [ param-no $] type conversion

Hình thức thứ hai là để lấy độ chính xác từ danh sách đối số:

Bạn cũng có thể chỉ định độ chính xác của '*'. Điều này có nghĩa là đối số tiếp theo trong danh sách đối số (trước giá trị thực được in) được sử dụng làm độ chính xác. Giá trị phải là int và bị bỏ qua nếu nó là giá trị âm.

Cú pháp chuyển đổi đầu ra trong sổ tay hướng dẫn sử dụng glibc

Đối với %sđịnh dạng chuỗi, độ chính xác có một ý nghĩa đặc biệt:

Có thể chỉ định độ chính xác để chỉ ra số ký tự tối đa để viết; nếu không thì các ký tự trong chuỗi lên đến nhưng không bao gồm ký tự null kết thúc được ghi vào luồng đầu ra.

Các chuyển đổi đầu ra khác trong sổ tay glibc

Các biến thể hữu ích khác:

  • "%*.*s", maxlen, maxlen, val sẽ căn phải, chèn khoảng trắng trước;
  • "%-*.*s", maxlen, maxlen, val sẽ căn trái.

Nếu tôi hiểu đúng, điều sau sẽ đệm đầu ra nhưng vẫn ngăn chặn tràn chuỗi? "%-*.*s", padding, str_view.size(), str_view.data()
scx

20

Bạn có thể sử dụng một fwrite () để stdout!

fwrite(your_string, sizeof(char), number_of_chars, stdout);

Bằng cách này, bạn sẽ xuất các ký tự đầu tiên (số được xác định trong biến number_of_chars) vào một tệp, trong trường hợp này là stdout (đầu ra chuẩn, màn hình của bạn)!


2
Rất hữu ích khi bạn muốn kiểm tra một bộ đệm dài có chứa chuỗi và số không!
Elist

13

printf("%.*s", length, string) sẽ không làm việc.

Điều này có nghĩa là in độ dài LÊN ĐẾN byte HOẶC byte rỗng, tùy điều kiện nào đến trước. Nếu mảng ký tự không bị kết thúc bằng null của bạn chứa byte rỗng TRƯỚC độ dài, printf sẽ dừng trên những ký tự đó và không tiếp tục.


4
Và đây là câu trả lời cho câu hỏi của OP?
Shahbaz

12
nếu nó không được kết thúc bằng null, thì null là một ký tự hợp lệ cho chuỗi chứa. điều này vẫn cho rằng mảng được kết thúc bằng null, nó chỉ coi nó như một mảng dài hơn mà nó đang chọn lọc từ đó - có nghĩa là nếu bạn có một chuỗi có null trong đó, điều này sẽ gây ra vấn đề.
lahwran

3
printf("%.5s", pointerToNonNullTerminatedString);

Độ dài chuỗi sẽ là 5.


1
#include<string.h> 
int main()
{
/*suppose a string str which is not null terminated and n is its length*/
 int i;
 for(i=0;i<n;i++)
 {
 printf("%c",str[i]);
 }
 return 0;
}

Tôi đã chỉnh sửa mã, đó là cách khác:

#include<stdio.h>
int main()
{
printf ("%.5s","fahaduddin");/*if 5 is the number of bytes to be printed and fahaduddin is the string.*/

return 0;

}

Hiệu suất rất kém do nhiều lần đọc byte không cần thiết (đi kèm với hình phạt hiệu suất nếu byte không nằm trên địa chỉ được căn chỉnh từ trên hầu hết các CPU) và việc phân tích cú pháp và áp dụng định dạng cũng được thực hiện cho từng ký tự. Đừng làm điều đó :-) Xem câu trả lời của tôi để biết giải pháp.
DarkDust 22/09/10

@DarkDust: chỉ một máy bệnh lý mới phạt các lần đọc byte không được căn chỉnh theo ranh giới từ. Bạn đang nghĩ đến việc đọc từ không được căn chỉnh theo ranh giới từ? Hay một số mips cổ đại hay gì đó?
R .. GitHub DỪNG TRỢ GIÚP LÚC NỮA, 23/09/10

@R ..: Nếu coi x86 hại não và lạc hậu thì mình hoàn toàn đồng ý. Bởi vì x86 có một hình phạt cho việc đọc và ghi bộ nhớ không được căn chỉnh từ. ARM cũng vậy. Xem ví dụ câu hỏi này hoặc câu hỏi này . Vấn đề là (nếu tôi hiểu điều đó một cách chính xác) rằng dữ liệu được tìm nạp trong các phần kích thước từ từ bộ nhớ và nhận được byte chính xác là một vi-op khác. Không có gì to tát, nhưng trong một vòng lặp lớn, nó có thể tạo ra sự khác biệt.
DarkDust 23/09/10

@DarkDust: bạn hoàn toàn sai về điều đó đối với các lần đọc byte. Tại sao bạn không đi làm điểm chuẩn? x86 có các hoạt động byte hoàn toàn nguyên tử và luôn luôn có. Nó không tìm nạp các khối có kích thước từ (ngoại trừ ở cấp bộ đệm, tìm nạp các khối lớn hơn nhiều và việc căn chỉnh là không liên quan, nhưng tôi đang nói về dữ liệu đã được lưu trong bộ nhớ cache).
R .. GitHub DỪNG TRỢ GIÚP LÚC NỮA, 23/09/10

@DarkDust: PS3 không hỗ trợ đọc hoặc ghi byte không dấu trên SPU. Trong thực tế, nó thậm chí không hỗ trợ các loại vô hướng, chỉ có vector, phải được căn chỉnh. Trình biên dịch mô phỏng chúng. Và nhiều bộ vi xử lý ARM không hỗ trợ đọc hoặc ghi byte mà chỉ thực hiện đọc hoặc ghi từ.
Sylvain Defresne
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.