Làm thế nào để khai báo một mảng chuỗi trong C ++?


89

Tôi đang cố gắng lặp lại tất cả các phần tử của một mảng chuỗi tĩnh theo cách tốt nhất có thể. Tôi muốn có thể khai báo nó trên một dòng và dễ dàng thêm / bớt các phần tử khỏi nó mà không cần phải theo dõi số lượng. Nghe thật đơn giản phải không?

Không có giải pháp có thể xảy ra:

vector<string> v;
v.push_back("abc");
b.push_back("xyz");

for(int i = 0; i < v.size(); i++)
    cout << v[i] << endl;

Các vấn đề - không có cách nào để tạo vectơ trên một dòng với danh sách các chuỗi

Có thể không phải là giải pháp 2:

string list[] = {"abc", "xyz"};

Các vấn đề - không có cách nào để lấy số lượng chuỗi tự động (mà tôi biết).

Phải có một cách dễ dàng để làm điều này.


Các thư viện boost assign vẻ là chính xác những gì bạn đang tìm kiếm. Nó làm cho việc gán hằng số cho vùng chứa dễ dàng hơn bao giờ hết.
Craig H

Câu trả lời:


108

C ++ 11 đã thêm danh sách khởi tạo để cho phép cú pháp sau:

std::vector<std::string> v = {"Hello", "World"};

Hỗ trợ cho tính năng C ++ 11 này đã được thêm vào ít nhất GCC 4.4 và chỉ trong Visual Studio 2013 .


2018. Chỉ mới bắt đầu C ++ và đã thực hiện một số nghiên cứu liên quan đến mảng linh hoạt. Đã kết thúc chỉ sử dụng vector ...
Robert Molina

37

Bạn có thể khởi tạo ngắn gọn a vector<string>từ một char*mảng được tạo tĩnh :

char* strarray[] = {"hey", "sup", "dogg"};
vector<string> strvector(strarray, strarray + 3);

Nhân tiện, điều này sao chép tất cả các chuỗi, vì vậy bạn sử dụng gấp đôi bộ nhớ. Bạn có thể sử dụng gợi ý của Will Dean để thay thế số 3 kỳ diệu ở đây bằng kích thước mảng (str_array) - mặc dù tôi nhớ có một số trường hợp đặc biệt trong đó phiên bản kích thước mảng cụ thể đó có thể gây ra Điều gì đó tồi tệ (xin lỗi, tôi không thể nhớ chi tiết ngay lập tức) . Nhưng nó thường hoạt động chính xác.

Ngoài ra, nếu bạn thực sự quan tâm đến vấn đề một dòng, bạn có thể xác định macro thay đổi để một dòng duy nhất DEFINE_STR_VEC(strvector, "hi", "there", "everyone");hoạt động.


strarraynằm trong tiêu đề, nó sẽ không vi phạm quy tắc một định nghĩa?
jww 21/02/17

22

Vấn đề - không có cách nào để lấy số chuỗi tự động (mà tôi biết).

Có một cách chuẩn mực để thực hiện việc này, mà rất nhiều người (bao gồm cả MS) định nghĩa macro như arraysizesau:

#define arraysize(ar)  (sizeof(ar) / sizeof(ar[0]))

1
Ngoài ra, người ta có thể sử dụng một cái gì đó như thế này: template<typename T, size_t N> inline size_t arraysize(T (&ar)[N]) { return N; } (Inline từ khóa không cần thiết, nhưng dùng để ghi nhận ý định Một trình biên dịch hiện đại của chức năng nên về mặt lý thuyết có thể trả lại toàn bộ chức năng, tôi tin rằng..
Justin Time - Khôi phục Monica

1
Điều này không thành công đối với con trỏ. Việc đếm các phần tử mảng nên được thực hiện theo một cách khác trong C ++.
jww 21/02/17

8

Khai báo một mảng chuỗi trong C ++ như sau: char array_of_strings[][]

Ví dụ : char array_of_strings[200][8192];

sẽ chứa 200 chuỗi, mỗi chuỗi có kích thước 8kb hoặc 8192 byte.

dùng strcpy(line[i],tempBuffer); để đưa dữ liệu vào mảng chuỗi.


FYI, char array_of_strings [] [] không thể chấp nhận chuỗi C ++, hãy nhớ chuyển đổi thành char * trước. cplusplus.com/reference/string/string/c_str
Luqmaan

array_of_stringsnằm trong tiêu đề, nó sẽ không vi phạm quy tắc một định nghĩa?
jww 21/02/17

7

Một khả năng là sử dụng con trỏ NULL làm giá trị cờ:

const char *list[] = {"dog", "cat", NULL};
for (char **iList = list; *iList != NULL; ++iList)
{
    cout << *iList;
}

Char ** thực sự có nghĩa là gì? Trong java, nó sẽ là một danh sách các chuỗi?
IAmGroot

1
@Doomsknight: Trong trường hợp này, có. Trong dòng đầu tiên, tôi xác định một mảng char*. Trong bộ nhớ, điều này được trình bày dưới dạng 3 con trỏ - một trỏ tới "dog", một trỏ tới "cat" và một trỏ tới NULL. Tôi có thể lấy một con trỏ tới con trỏ đầu tiên đó và lấy một char**- một con trỏ để trỏ tới char. Khi tôi tăng giá trị đó, tôi di chuyển char ** để trỏ đến mục tiếp theo trong danh sách - một con trỏ tới con trỏ trỏ đến "cat", sau đó tôi lại tăng và nhận được một con trỏ trỏ đến con trỏ NULL, và Tôi biết tôi đã xong. (
Eclipse

4

Bạn có thể sử dụng các hàm beginendtừ thư viện phạm vi Boost để dễ dàng tìm thấy các phần cuối của một mảng nguyên thủy và không giống như giải pháp macro, điều này sẽ gây ra lỗi biên dịch thay vì hành vi bị hỏng nếu bạn vô tình áp dụng nó cho một con trỏ.

const char* array[] = { "cat", "dog", "horse" };
vector<string> vec(begin(array), end(array));

3

Bạn có thể sử dụng gợi ý của Will Dean [ #define arraysize(ar) (sizeof(ar) / sizeof(ar[0]))] để thay thế số 3 ma thuật ở đây bằng kích thước mảng (str_array) - mặc dù tôi nhớ có một số trường hợp đặc biệt trong đó phiên bản kích thước mảng cụ thể đó có thể gây ra Điều gì đó không tốt (xin lỗi tôi không thể nhớ chi tiết ngay). Nhưng nó thường hoạt động chính xác.

Trường hợp nó không hoạt động là khi "mảng" thực sự chỉ là một con trỏ, không phải là một mảng thực tế. Ngoài ra, do cách mảng được truyền cho các hàm (được chuyển đổi thành con trỏ đến phần tử đầu tiên), nó không hoạt động trên các lệnh gọi hàm ngay cả khi chữ ký trông giống như một mảng - some_function(string parameter[])thực sự là như vậy some_function(string *parameter).


3

Đây là một ví dụ:

#include <iostream>
#include <string>
#include <vector>
#include <iterator>

int main() {
    const char* const list[] = {"zip", "zam", "bam"};
    const size_t len = sizeof(list) / sizeof(list[0]);

    for (size_t i = 0; i < len; ++i)
        std::cout << list[i] << "\n";

    const std::vector<string> v(list, list + len);
    std::copy(v.begin(), v.end(), std::ostream_iterator<string>(std::cout, "\n"));
}

2

Thay vì macro đó, tôi có thể đề xuất cái này:

template<typename T, int N>
inline size_t array_size(T(&)[N])
{
    return N;
}

#define ARRAY_SIZE(X)   (sizeof(array_size(X)) ? (sizeof(X) / sizeof((X)[0])) : -1)

1) Chúng tôi muốn sử dụng macro để biến nó thành hằng số thời gian biên dịch; kết quả của lời gọi hàm không phải là hằng số thời gian biên dịch.

2) Tuy nhiên, chúng tôi không muốn sử dụng macro vì macro có thể vô tình được sử dụng trên một con trỏ. Hàm chỉ có thể được sử dụng trên mảng thời gian biên dịch.

Vì vậy, chúng tôi sử dụng hàm được định nghĩa để làm cho macro "an toàn"; nếu hàm tồn tại (tức là nó có kích thước khác 0) thì chúng ta sử dụng macro như trên. Nếu hàm không tồn tại, chúng ta trả về một giá trị xấu.


2
#include <boost/foreach.hpp>

const char* list[] = {"abc", "xyz"};
BOOST_FOREACH(const char* str, list)
{
    cout << str << endl;
}

1
#include <iostream>
#include <string>
#include <vector>
#include <boost/assign/list_of.hpp>

int main()
{
    const std::vector< std::string > v = boost::assign::list_of( "abc" )( "xyz" );
    std::copy(
        v.begin(),
        v.end(),
        std::ostream_iterator< std::string >( std::cout, "\n" ) );
}

1

Bạn có thể khai báo trực tiếp một mảng chuỗi như string s[100];. Sau đó, nếu bạn muốn truy cập các phần tử cụ thể, bạn có thể lấy nó trực tiếp như s[2][90]. Đối với mục đích lặp, lấy kích thước của chuỗi bằng cách sử dụng s[i].size()hàm.

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.