2015-11-06 4 views
2
bool foo(const char* arg, const char* str[]){ 
    for (int i=0; i < (signed)sizeof(str); i++){ 
     if(strcmp(arg, str[i])) == 0){ 
     return true; 
     } 
    } 
    return false; 
    } 

    int main(){ 
     foo("c", {"a", "b", "c"}); 
     return 0; 
    } 

Я хочу передать массив const char * функции непосредственно так, как показано здесь. Но я продолжаю получать ошибку: cannot convert '<brace-enclosed initializer list>' to 'const char**'C++ pass array directy to function

+0

You shou ld вызывает функцию foo() следующим образом: 'foo (" c ", [" a "," b "," c "])' –

+1

@VuongHoang вы пробовали это? это не python – melak47

ответ

4

Хотя есть способ, чтобы сделать эту работу, используя шаблоны и передачи C-массивов по ссылке, я не уверен, если это то, что вы действительно хотите: example

В C++ 11 Я бы много предпочитают использовать std::intializer_list, чтобы сделать вызов foo("c", {"a", "b", "c"}) работу по назначению:

#include <initializer_list> 

bool foo(const char* arg, std::initializer_list<const char*> strings) { 
    for (const char* str : strings) { 
     /* ... */ 
    } 
} 

в то время как мы в этом, вы должны рассмотреть возможность использования строковых объектов C++ 's более унаследованных от C:

#include <initializer_list> 
#include <string> 

bool foo(const std::string& arg, std::initializer_list<std::string> strings) { 
    for (const auto& str : strings) { 
     if (arg == str) { 
      return true; 
     } 
    } 
    return false; 
} 

Обратите внимание, что std::initializer_list не принадлежит значениям, которым он обеспечивает доступ, поэтому, если вы хотите его сохранить, вместо этого используйте соответствующий контейнер, например std::vector.

Кроме того, если проверка на наличие arg в str все, что вы хотите сделать, почему бы не использовать std::find?

#include <algorithm> 
#include <initializer_list> 
#include <string> 

bool foo(const std::string& arg, std::initializer_list<std::string> strings) { 
    return std::find(strings.begin(), strings.end(), arg) != strings.end(); 
} 
+0

Первый вариант выглядит исправленным в соответствии с моим linter, но я получаю ошибки компиляции, в соответствии с выходом, который я не использую C++ 11, на windows с cygwin64 У меня есть g ++ 4.9.3, а в opensuse VM у меня есть g ++ 5.1. 1 ни одна из ведьм не может скомпилировать это. – Drew

+0

Оба этих компилятора способны к C++ 11 и более поздним, но вам придется использовать флаг компилятора '-std = C++ 11'. – melak47

+0

поэтому его makefile мне нужно изменить, чтобы получить C++ 11, спасибо – Drew

0

Используйте указатель указателя на символ (char **), чтобы достичь этого. Вы не можете объявлять параметры как массивы, но вы можете передавать массивы в функции, поскольку они будут преобразованы в двойные указатели.

+0

Проблема не в функции, проблема заключается в попытке использовать '{" a "," b "," c "}' как литерал в вызывающем. – Barmar

+0

Вы протестировали это? – Quantum

+0

Конечно, это одна проблема ... – Quantum

0

Хотя рекомендуется отказаться от программирования C-стиля при использовании C++ и использовать СТЛ контейнеры вместо этого, я хотел бы отметить, что следующий «один вкладыш» работает:

bool foo(const char* arg, const char* const* str, size_t siz) { 
    for (size_t i = 0; i < siz; i++) 
     if (!strcmp(arg, str[i])) return true; 
    return false; 
} 

int main() { 
    cout << foo("c", array<char*, 3> { "a", "b", "c" }.data(), 3); 
    system("pause"); 
} 

удивительным сюрпризом является то, что если мы определим второй аргумент обув, как const char**, компилятор (VS2015) кричит и говорит:

bool foo(...): cannot convert argument 2 from 'char **' to 'const char **'

: O не может преобразовать из неконстантного в const ??? Это имеет смысл?

Редактировать: @NeilKirk объяснил это в своем комментарии. Нормальный. Соответственно, подпись должна быть такой:

bool foo(const char* arg, const char* const* str, size_t siz) 

и все работает должным образом.

+0

Это не работает должным образом. 'sizeof (str)' будет возвращать 'sizeof (char **)', исходный размер массива будет потерян. – melak47

+0

Ребята, я согласен с потерянным размером, поэтому я изменил код, чтобы включить параметр размера. Тем не менее, я все еще удивляюсь, что компилятор не может разлагать неконстант на const!? –

+1

'const char * text =" hi "; char * p; const char ** cp = & p; * cp = текст; * p = 'X'; 'Упс, измененные данные const! –

0

Вы также можете передать массив по ссылке через функцию шаблона, чтобы вы могли определить его размер во время компиляции (обратите внимание, что в вашем случае массив распадается на указатель, поэтому sizeof не делает то, что вы думать).Пример:

#include <iostream> 
#include <cstring> 

template<int N> 
bool foo(const char* arg, const char* (&str)[N]) 
{ 
    for (std::size_t i = 0; i < N; i++) { 
     if (std::strcmp(arg, str[i]) == 0) { 
      return true; 
     } 
    } 
    return false; 
} 

int main() { 
    const char* arr[] = {"abc", "de"}; 
    std::cout << std::boolalpha << foo("de", arr); 
} 

Live on Coliru

И кстати, попробуйте использовать алгоритмы из стандартной библиотеки C++ и std::string вместо strcmp() и сырых C-строк:

#include <algorithm> 
#include <iostream> 
#include <vector> 

bool foo(const std::string arg, const std::vector<std::string>& str) 
{ 
    return std::find(str.begin(), str.end(), arg) != str.end(); 
} 

int main() 
{ 
    std::cout << std::boolalpha << foo("de", {"abc", "de"}); 
} 

Live on Coliru