2016-03-14 22 views
11

Trong C, Nếu tôi có:C chuỗi thiết lập bằng substring

char *reg = "[R5]"; 

và tôi muốn

char *reg_alt = "R5" (tương đương với điều tương tự, nhưng không có dấu ngoặc), làm thế nào để làm điều này?

tôi đã cố gắng

*char reg_alt = reg[1:2]; 

nhưng điều này không hoạt động.

Trả lời

15

Không có được xây dựng trong cú pháp để đối phó với các chất nền như vậy, vì vậy bạn cần sao chép nội dung theo cách thủ công:

char res[3]; 
memcpy(res, &reg[1], 2); 
res[2] = '\0'; 
+0

Ngoài câu trả lời tốt này là một thực tế là bạn cũng có thể sao chép chất nền từ chuỗi gốc ngược lại bằng cách sử dụng vòng lặp for. –

+1

'memmove', không giống như' memcpy', sẽ cho phép nguồn và đích trùng lặp. Bạn không cần phải phát minh lại nó với một vòng lặp rõ ràng. –

1

Cần phải là một char?

Bởi vì rằng công việc chỉ khi là một "chuỗi" Vì vậy, có lẽ bạn cần điều này

char reg[] = "[R5]"; 

Sau đó, bạn có thể làm những điều khác hoặc chỉ chia chuỗi như thế này question

+0

Tôi cần chuyển nó thành char * cho các chức năng khác vì vậy tôi không muốn viết lại tất cả chúng để lấy char [] thay vì – Austin

+2

Bạn cần thực hiện theo cách thủ công, nhưng hãy ghi nhớ –

+0

Đối số thuộc loại ' char [] 'và' char * 'là điều tương tự trong C. Vấn đề là, trong một hàm nơi một mảng được tạo ra, chúng là những thứ khác nhau. – Peter

3

Khi sử dụng các chuỗi null-terminated (mặc định trong C), bạn có thể thực sự tạo ra một chuỗi con của một chuỗi khác bằng cách thay đổi con trỏ ký tự bắt đầu, nhưng bạn không thể làm cho chuỗi con mới có một null-terminator khác.

Tùy chọn là sử dụng thư viện chuỗi Pascal. Các chuỗi Pascal có độ dài tiền tố thay vì các chuỗi C được kết thúc bằng null, có nghĩa là các chuỗi Pascal có thể chia sẻ nội dung của bộ đệm chuỗi lớn hơn và tạo chuỗi con là giá rẻ (O(1) -eap). Một chuỗi Pascal trông như thế này:

struct PString { 
    size_t length; 
    char* start; 
} 

PString substring(const PString* source, size_t offset, size_t length) { 
    // Using C99 Designated Initializer syntax: 
    return PString { .length = length, .start = source.start + offset }; 
} 

Nhược điểm là hầu hết các thư viện và nền tảng thư viện C sử dụng null-terminated strings và trừ khi Pascal-string của bạn kết thúc bằng một ký tự null bạn sẽ cần phải sao chép các chuỗi con vào bộ đệm mới (trong thời gian O(n)).

Tất nhiên, nếu bạn đang cảm thấy nguy hiểm (và sử dụng bộ đệm nhân vật có thể thay đổi) sau đó bạn có thể hack nó để tạm thời chèn một null-terminator, như vậy:

struct CStr { 
    char* start; 
    char* end; 
    char temp; 
} 

CStr getCStr(PString* source) { 
    char* terminator = (source.start + source.length); 
    char previous = *terminator; 
    *terminator = '\0'; 
    return CStr { .start = source.start, .end = terminator, .temp = previous }; 
} 

void undoGetCStr(CStr cstr) { 
    *cstr.end = cstr.temp; 
} 

Được sử dụng như sau:

PString somePascalString = doSomethingWithPascalStrings(); 
CStr temp = getCStr(somePascalString); 
printf("My Pascal string: %s", temp.start); // using a function that expects a C-string 
undoGetCStr(temp); 

... sau đó cho bạn hiệu suất O(1) PString-to-CString, miễn là bạn không quan tâm đến tính an toàn của luồng.

+1

Những bất lợi chính của câu trả lời này là các thư viện chuỗi Pascal thường không được phân phối với các trình biên dịch C và các thư viện. – Peter

+0

@Peter Tôi đã thêm một hack đơn giản cho phép bạn sử dụng các chuỗi Pascal với các hàm mong đợi các chuỗi C. – Dai

13

Tôi khuyên bạn nên đọc một văn bản cơ bản trên C, thay vì giả sử các kỹ thuật từ các ngôn ngữ khác sẽ chỉ hoạt động.

Đầu tiên, char *reg = "[R5]"; không phải là một chuỗi. Nó là một con trỏ, được khởi tạo để trỏ đến (tức là giá trị của nó là địa chỉ của) ký tự đầu tiên của một chuỗi ký tự ("[R5]").

Thứ hai, reg_alt cũng là một con trỏ chứ không phải chuỗi. Chỉ định cho nó sẽ chứa một địa chỉ của một cái gì đó. Chuỗi không phải là công dân hạng nhất trong C, do đó toán tử gán không hoạt động với chúng.

Thứ ba, 1:2 không chỉ định phạm vi - đó thực sự là cú pháp không hợp lệ. Vâng, tôi biết các ngôn ngữ khác. Nhưng không C. Do đó nhận xét của tôi rằng bạn không thể giả định C sẽ cho phép mọi thứ theo cách mà các ngôn ngữ khác làm.

Nếu bạn muốn lấy chuỗi con từ một chuỗi khác, có nhiều cách khác nhau. Ví dụ;

char substring[3]; 
    const char *reg = "[R5]"; /* const since the string literal should not be modified */ 

    strncpy(substring, &reg[1], 2);  /* copy 2 characters, starting at reg[1], to substring */ 
    substring[2] = '\0';  /* terminate substring */ 

    printf("%s\n", substring); 

strncpy() được khai báo trong tiêu đề chuẩn <string.h>. Việc chấm dứt chuỗi con là cần thiết, vì định dạng printf()%s tìm kiếm ký tự bằng 0 để đánh dấu kết thúc.

+1

Giữa 'memcopy()' và 'strncopy()', có bất kỳ lý do nào để sử dụng cái này qua cái kia không? – Austin

+5

Không có điều gì như 'memcopy()' hoặc 'strncopy()'. 'strncpy()' sẽ phát hiện không có terminators trên chuỗi, và ngừng sao chép. Nó cũng sẽ ngừng sao chép nếu chuỗi nguồn ngắn hơn độ dài được chỉ định. 'memcpy()' sẽ sao chép bất kể - điều này sẽ gây ra hành vi không xác định nếu chuỗi nguồn ngắn hơn độ dài được chỉ định. – Peter

+2

@Austin: Mặt khác, bạn cần phải biết rằng 'strncpy()' ... 1) lấp đầy không gian còn lại với null byte, tức là * luôn * ghi đầy đủ 'n' byte và 2) sẽ để lại đích ** unterminated ** nếu không có byte rỗng trong 'n' byte đầu tiên của chuỗi nguồn. Đó là một chức năng phức tạp theo cách đó. – DevSolar

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