C указатели: указывая на массив фиксированного размера

При использовании.Net 2.0 и Ajax - необходимо использовать:

ScriptManager.RegisterClientScriptBlock

Это будет работать лучше в средах Ajax тогда старый Page. Версия

ClientScript
107
задан Trevor Hickey 21 April 2016 в 05:39
поделиться

7 ответов

I would like to add to AndreyT's answer (in case anyone stumbles upon this page looking for more info on this topic):

As I begin to play more with these declarations, I realize that there is major handicap associated with them in C (apparently not in C++). It is fairly common to have a situation where you would like to give a caller a const pointer to a buffer you have written into. Unfortunately, this is not possible when declaring a pointer like this in C. In other words, the C standard (6.7.3 - Paragraph 8) is at odds with something like this:


   int array[9];

   const int (* p2)[9] = &array;  /* Not legal unless array is const as well */

This constraint does not seem to be present in C++, making these type of declarations far more useful. But in the case of C, it is necessary to fall back to a regular pointer declaration whenever you want a const pointer to the fixed size buffer (unless the buffer itself was declared const to begin with). You can find more info in this mail thread: link text

This is a severe constraint in my opinion and it could be one of the main reasons why people do not usually declare pointers like this in C. The other being the fact that most people do not even know that you can declare a pointer like this as AndreyT has pointed out.

9
ответ дан 24 November 2019 в 03:41
поделиться

Очевидная причина в том, что этот код не ' t compile:

extern void foo(char (*p)[10]);
void bar() {
  char p[10];
  foo(p);
}

По умолчанию для массива используется неквалифицированный указатель.

Также см. этот вопрос , использование foo (& p) должно работать.

4
ответ дан 24 November 2019 в 03:41
поделиться

Ну, попросту говоря, C не делает этого. Массив типа T передается как указатель на первый T в массиве, и это все, что вы получаете.

Это позволяет использовать некоторые классные и элегантные алгоритмы, например как цикл по массиву с выражениями типа

*dst++ = *src++

Обратной стороной является то, что управление размером зависит от вас. К сожалению, неспособность сделать это сознательно также привело к миллионам ошибок в коде C и / или возможностям злонамеренного использования.

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

Ваша структура может содержать любые данные, которые вы хотите; он может содержать ваш массив четко определенного размера.

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

1
ответ дан 24 November 2019 в 03:41
поделиться

Вы можете объявить массив символов несколькими способами:

char p[10];
char* p = (char*)malloc(10 * sizeof(char));

Прототип функции, которая принимает массив по значению:

void foo(char* p); //cannot modify p

или по ссылке:

void foo(char** p); //can modify p, derefernce by *p[0] = 'f';

или по синтаксис массива:

void foo(char p[]); //same as char*
1
ответ дан 24 November 2019 в 03:41
поделиться

То, что вы говорите в своем посте, абсолютно правильно. Я бы сказал, что каждый разработчик C приходит к одному и тому же открытию и к точно такому же выводу, когда (если) они достигают определенного уровня владения языком C.

Когда специфика области вашего приложения требует массива конкретных фиксированного размера (размер массива - это константа времени компиляции), единственный правильный способ передать такой массив функции - использовать параметр указателя на массив

void foo(char (*p)[10]);

(на языке C ++ это также делается со ссылками

void foo(char (&p)[10]);

).

Это включит проверку типов на уровне языка, которая гарантирует, что массив точно правильного размера предоставляется в качестве аргумента. Фактически, во многих случаях люди используют эту технику неявно, даже не осознавая этого. скрытие типа массива за именем typedef

typedef int Vector3d[3];

void transform(Vector3d *vector);
/* equivalent to `void transform(int (*vector)[3])` */
...
Vector3d vec;
...
transform(&vec);

Обратите внимание, что приведенный выше код инвариантен по отношению к типу Vector3d , являющемуся массивом или структурой . Вы можете переключить определение Vector3d в любое время с массива на структуру struct и обратно, и вам не придется менять объявление функции. В любом случае функции получат агрегированный объект «по ссылке» (есть исключения из этого, но в контексте этого обсуждения это правда).

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

Но на самом деле использование указателя на первый элемент для передачи массива - это очень нишевый прием, уловка, которая служит очень конкретной цели: ее единственная цель - облегчить передачу массивов разного размера (т.е. размер времени выполнения). Если вам действительно нужно иметь возможность обрабатывать массивы размера во время выполнения, то правильный способ передать такой массив - указать указатель на его первый элемент с конкретным размером, предоставленным дополнительным параметром

void foo(char p[], unsigned plen);

На самом деле, во многих случаях очень полезно иметь возможность обрабатывать массивы размера во время выполнения, что также способствует популярности метода. Многие разработчики C просто никогда не сталкиваются (или никогда не осознают) необходимости обрабатывать массив фиксированного размера, таким образом, не обращая внимания на правильную технику фиксированного размера.

Тем не менее, если размер массива фиксирован, передача его в качестве указателя на элемент

void foo(char p[])

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

Другая причина, которая может помешать внедрению метода передачи массива фиксированного размера, - это преобладание наивного подхода к типированию динамически выделяемых массивов. Например, если программа вызывает фиксированные массивы типа char [10] (как в вашем примере), средний разработчик будет malloc такие массивы, как

char *p = malloc(10 * sizeof *p);

Этот массив не может быть передается в функцию, объявленную как

void foo(char (*p)[10]);

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

char (*p)[10] = malloc(sizeof *p);

Это, конечно, можно легко передать в объявленный выше foo

foo(p);

и компилятор выполнит правильную проверку типа. Но опять же, это слишком сбивает с толку неподготовленного разработчика C, поэтому вы не увидите это слишком часто в "типичном" среднем повседневном коде.

лучший способ malloc он будет выглядеть следующим образом

char (*p)[10] = malloc(sizeof *p);

Это, конечно, можно легко передать в объявленный выше foo

foo(p);

, и компилятор выполнит правильную проверку типов. Но опять же, это слишком сбивает с толку неподготовленного разработчика C, поэтому вы не увидите это слишком часто в "типичном" среднем повседневном коде.

лучший способ malloc он будет выглядеть следующим образом

char (*p)[10] = malloc(sizeof *p);

Это, конечно, можно легко передать в объявленный выше foo

foo(p);

, и компилятор выполнит правильную проверку типа. Но опять же, это слишком сбивает с толку неподготовленного разработчика C, поэтому вы не увидите это слишком часто в "типичном" среднем повседневном коде.

160
ответ дан 24 November 2019 в 03:41
поделиться

Я бы не рекомендовал это решение

typedef int Vector3d[3];

, поскольку оно скрывает тот факт, что Vector3D имеет тип, который вы должен знать о. Программисты обычно не ожидают переменных того же типа иметь разные размеры. Рассмотрим:

void foo(Vector3d a) {
   Vector3D b;
}

, где sizeof a! = Sizeof b

1
ответ дан 24 November 2019 в 03:41
поделиться

Может быть, m чего-то не хватает, но ... поскольку массивы являются постоянными указателями, в основном это означает, что нет смысла передавать им указатели.

Не могли бы вы просто использовать void foo (char p [10], int пленка); ?

-1
ответ дан 24 November 2019 в 03:41
поделиться
Другие вопросы по тегам:

Похожие вопросы: