массив целых и указатель на целое число в c ++ - PullRequest
2 голосов
/ 15 июля 2009

Если у меня есть int x[10] и int *y, как я могу определить разницу между ними?

У меня есть две идеи:

  1. sizeof () отличается.

  2. & x имеет другой тип --- int (*p)[10] = &x работает, но не int **q = &x.

Кто-нибудь еще?

В некотором коде библиотеки шаблонов мне нужно определить, является ли указатель "реальным" указателем или вырожденным из массива. Я не могу посмотреть на исходный код, так как пользователь библиотеки не существует, пока я не напишу библиотеку. ... Я могу обойти это, переписав код, так что теперь это только теоретическое упражнение.

Ответы [ 6 ]

5 голосов
/ 15 июля 2009

Обычного метода не существует - либо вы уже знаете тип, потому что вы только что объявили объект, либо тип потеряет указатель и будет потерян. Пожалуйста, объясните, какую проблему вы пытаетесь решить, различая их.

2 голосов
/ 15 июля 2009

Предполагается, что вы не пытаетесь сделать это для типа, объявленного в области действия функции:

struct yes { char pad; };
struct no { yes pad[2]; };

template <typename T, size_t N> yes is_array_test(T (&arr)[N]);
no is_array_test(...);

#define IS_ARRAY(x) (sizeof(is_array_test(x))==sizeof(yes))
2 голосов
/ 15 июля 2009

Идея sizeof не очень хороша, потому что если в массиве окажется один элемент, а тип элемента окажется такого же размера, что и указатель, то он будет такого же размера, как размер указатель.

Подход сопоставления типов выглядит более многообещающим и, вероятно, может быть использован для выбора специализации шаблона (если это то, что вы делаете).

0 голосов
/ 14 марта 2012

Я только что попробовал эквивалент в режиме g ++ 4.5 C ++ 0x для массивов символов, и он не позволит мне определить

template <typename T>void moresilly(const T v[],const char *description)

И

template <typename T>void moresilly(const T *v,const char *description)

утверждает, что оба они одного типа.

У меня была функция:

template <typename T>void silly(const T & v,const char *description)
{
    cout<<"size of "<<description<<" is "<< sizeof(T)<<endl;
    moresilly(v,description);
}

Он правильно получает размер массива, если передан, и указателя, если передан, но я не могу использовать moresilly, чтобы различать указатель и массив, поэтому я не могу отличить массив из 4 символов от указателя на n символов.

Это может работать, вроде как, иметь шаблоны для T [1], T [2], T [3] и т. Д., Но уже есть сообщение о том, что разные компиляторы обрабатывают это (или некоторый подобный случай) по-разному и что GNU предпочитает совпадение указателей в C ++ 11.

... добавлено позже: После некоторого эксперимента я нашел что-то, что работает в g ​​++ 4.5

template <typename T,size_t L>void moresilly(const T (&v)[L],const char *description)
{
    cout<<description<<" is an array"<<endl;
}
template <typename T>void moresilly(const T *v,const char *description)
{
    cout<<description<<" is a pointer"<<endl;
}
template <typename T>void moresilly(const T v,const char *description)
{
    cout<<description<<" is a raw value"<<endl;
}
template <typename T>void silly(const T & v,const char *description)
{
    cout<<"size of "<<description<<" is "<< sizeof(T)<<endl;
    moresilly(v,description);
}

со следующими корректно работает

    silly("12345","immediate string of 5 characters plus zero");
    silly((const char *)"12345","immediate constant char pointer of 5 characters plus zero");
    char testarray[]="abcdef";
    silly(testarray,"char array of 6 characters plus zero");
const char testarray2[]="abcdefg";
silly(testarray2,"const char array of 7 characters plus zero");

Обратите внимание, что если первая функция определена с "const T v [L]" вместо "const T (& v) [L]", она не будет работать, никогда ничего не сопоставляя.

Итак, я решил вашу проблему, но не ожидаю, что это сработает в других версиях компилятора, включая будущие. Вот почему я ненавижу с ++. Каким-то образом определение языка настолько неясно, что компиляторы полны нестабильных краевых случаев.

Это полезный трюк, но я могу его использовать.

0 голосов
/ 15 июля 2009

Они бывают разных типов.

Как определить разницу между int32 и uint32, или uint32 и char [4]?

Правильный способ думать об этом состоит в том, что единственный способ, которым они похожи, состоит в том, что в определенных контекстах (включая индексирование массива!) Массив превращается в указатель.

0 голосов
/ 15 июля 2009

int x [10] будет всегда выделяться в стеке в том месте, где он вызывается. Значение x никогда не может быть изменено.

int * y просто объявляет указатель на память, значение указателя может быть изменено в любое время без каких-либо ограничений.

int * y может иметь любое произвольное значение. Это означает, что он может указывать на выделенную в стеке память или кучу выделенной памяти. Технически это также может указывать на неверную память, но это не имеет никакого смысла.

int x [10] гарантирует, что вы всегда указываете на действительную память и вам не нужно беспокоиться об освобождении памяти.

при использовании int * y вам нужно беспокоиться о памяти, на которую он указывает.

Также имейте в виду, что из-за того, что у вашей программы есть динамически распределенная память, тем больше она будет подвержена ошибкам, утечкам, проблемам производительности, ассиметрии распределения \ освобождения и многим другим видам проблем.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...