2011-03-02 34 views
6

Có phải con trỏ NULL được phép làm chuỗi để lưu trữ kết quả trong cuộc gọi đến sscanf không? Tôi không tìm thấy bất cứ điều gì về nó trong bất kỳ tài liệu nào, nhưng nó có vẻ là làm việc tốt. Điều tương tự với scanf.NULL arg được phép sscanf?

Ví dụ:

int main(int arc, char* argv[]) 
{ 
    char* s = NULL; 
    sscanf("Privjet mir!", "%s", s); 
    printf("s: %s\n", s); 
    return 0; 
} 

Output: s: (null)

Trả lời

6

Số:

Trận một chuỗi các phi trắng-không gian ký tự; con trỏ tiếp theo phải là một con trỏ tới mảng ký tự là đủ dài để giữ chuỗi đầu vào và ký tự kết thúc rỗng ('\ 0'), được thêm tự động. Chuỗi đầu vào dừng ở khoảng trắng hoặc ở chiều rộng trường tối đa, tùy điều kiện nào xảy ra trước.

(http://linux.die.net/man/3/sscanf)

+0

Câu trả lời này cũng dạy chúng tôi rằng cấm null không cần phải đề cập đến từ "null" một cách rõ ràng.Nói rằng một cái gì đó phải là "một con trỏ đến " hoàn toàn cấm null. – Lii

1

Các manpage nói rằng, khi sử dụng %s, đối số phải là một con trỏ với không gian đủ cho chuỗi và \0. Vì vậy, tôi đoán là hành vi trong trường hợp của bạn là không xác định. Nó có thể làm việc, nó cũng có thể sụp đổ hoặc hỏng bộ nhớ và gây ra các vấn đề sau này.

1

Không, điều này không được phép. sscanf% s mong đợi một char * trỏ đến một bộ đệm đủ lớn, printf% s muốn một bộ đệm nul char *. Bất kỳ điều gì khác dẫn đến hành vi không xác định. (Và điều đó có nghĩa là một số triển khai có thể phát hiện và xử lý một con trỏ rỗng theo một cách nhất định, các triển khai khác có thể không)

1

Tôi không tìm thấy bất kỳ điều gì trong tiêu chuẩn một cách rõ ràng liên quan đến NULL*printf/*scanf.

Tôi cho rằng đây là hành vi undefined , vì nó đếm như đi qua một cuộc tranh cãi đó không phải là chặt chẽ với sự xác định định dạng (§7.19.6.1 ¶13, §7.19.6.2 ¶13): %s có nghĩa là một bạn sẽ chuyển con trỏ tới phần tử đầu tiên của một mảng ký tự (đủ lớn cho chuỗi được mua cho *scanf, có chứa một chuỗi NUL -terminated cho *printf) - và qua NULL không đáp ứng yêu cầu này.


1. Trong trường hợp này UB hiển thị là "chỉ bỏ qua việc mua lại" và "in (null)", trên các nền tảng khác có thể dẫn đến máy bay rơi xuống bầu trời hoặc thông thường nasal demons.

-2

Phân bổ bộ nhớ cho s. Gán s cho mảng ký tự. Sau đó chạy chương trình. Sau đây sẽ hoạt động.

int main(int arc, char* argv[]) 
{ 
    char s[100]; 
    sscanf("Privjet mir!", "%[^\t]s", s); 
    printf("s: %s\n", s); 
    return 0; 
} 
+0

Không thực sự trả lời câu hỏi của tôi ... – Lii

4

Như được đề cập bởi những câu trả lời khác NULL không hợp lệ để vượt qua để sscanf như một tham số bổ sung.

http://www.cplusplus.com/reference/cstdio/sscanf nói về lý luận thêm:

Tùy thuộc vào chuỗi định dạng, chức năng có thể mong đợi một chuỗi các đối số bổ sung, mỗi có chứa một con trỏ để lưu trữ phân bổ nơi việc giải thích của các nhân vật được chiết xuất được lưu trữ với loại thích hợp.

For the %s specifier these extracted characters are:

Bất kỳ số lượng ký tự không phải khoảng trắng, dừng tại ký tự khoảng trắng đầu tiên được tìm thấy. Một ký tự null kết thúc được tự động thêm vào cuối chuỗi được lưu trữ.

Vì vậy, khi "ký tự khoảng trắng" và "ký tự không kết thúc" được lưu trữ, sẽ có một khoảng cách. Đó là chính xác những gì Visual Studio sẽ mang lại (bạn có thể kiểm tra điều này không thành công ở http://webcompiler.cloudapp.net/):

enter image description here

Bây giờ như xa như phi Visual Studio biên dịch, mã khai thác libc cho các %s specifier: https://github.com/ffainelli/uClibc/blob/master/libc/stdio/_scanf.c#L1376 có hàng đầu chú thích: /* We might have to handle the allocation ourselves */ điều này là do:

Thư viện GNU C hỗ trợ trình chỉ định chuyển đổi phân bổ động (như phần mở rộng không chuẩn) qua ký tự a. Tính năng này dường như có mặt ít nhất là xa như glibc 2.0.
Kể từ phiên bản 2.7, glibc cũng cung cấp công cụ sửa đổi m cho cùng mục đích với công cụ sửa đổi a.

[Source]

Vì vậy, vì chiết xuất libc đến một bộ đệm xây dựng trong nội bộ để sscanf và sau đó kiểm tra rằng các tham số đệm không có lá cờ thiết lập trước khi gán cho nó, nó sẽ không bao giờ viết các ký tự vào một tham số NULL đệm.

Tôi không thể nhấn mạnh rằng đây không phải là tiêu chuẩn và không được bảo đảm để được giữ nguyên ngay cả khi cập nhật thư viện nhỏ. Cách tốt hơn để thực hiện việc này là sử dụng thông số phụ * mà:

Cho biết dữ liệu sẽ được đọc từ luồng nhưng bị bỏ qua (tức là dữ liệu không được lưu trữ ở vị trí được chỉ định bởi đối số) .

[Source]

Điều này có thể được thực hiện như thế này ví dụ:

s == NULL ? sscanf("Privjet mir!", "%*s") : sscanf("Privjet mir!", "%s", s); 

Rõ ràng là đúng ngành của ternary là một không-op, nhưng tôi đã bao gồm nó với kỳ vọng rằng các dữ liệu khác được dự kiến ​​sẽ được đọc từ chuỗi.

Các vấn đề liên quan