2016-08-09 10 views
2

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

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

Просьба привести краткий пример того, как передать массив как указатель указателя и определить его размер в пределах функции, которой он передан.

Если массив изменен в функции, я хочу, чтобы источник массива был изменен. И я хочу свести к минимуму дополнительное распределение памяти. И, если это вообще возможно, я бы хотел, чтобы размер массива внутри функции был равен .

Этот код работает без проезда.

// this works 
j = sizeof(hourLongs)/sizeof(hourLongs[0]); 
i = 0; while (now > hourLongs[i] && i < j){i++;} 
hour = --i; 

Это работает, но не может определить размер массива внутри функции.

hour = compareToLongs(&now, hourLongs, (int)(sizeof(hourLongs)/sizeof(hourLongs[0]))); 

// long *, long * , int -> int 
// compare time to array of times. 
static int compareToLongs(long * time, long * timeList_pointer, int size){ 
    i = 0; while (*time> (timeList_pointer)[i] && i < size){i++;} 
    return --i; 
} 

Я хотел бы передать массив таким образом, чтобы он мог найти его размер внутри функции. Что-то вроде следующего, минус мои ошибки.

hour = compareToLongs(&now, &hourLongs); 

// long *, (long (*) [])* -> int 
// compare time to array of times. 
static int compareToLongs(long * time, long ** timeList_pointer){ 
    int size = (int)(sizeof(*timeList_pointer)/sizeof(*timeList_pointer[0])); 
    i = 0; while (*time> (i < size && *timeList_pointer)[i]){i++;} 
    free(size); 
    return --i; 
} 

Редактировать: hourLongs - это массив длинных целых чисел.

Редактировать: Что касается названия, я использовал слово «ссылка» в народном языке, чтобы другие варвары, подобные мне, могли найти вопрос.

Редактировать: Я действительно ищу способ задать массив целых чисел внутри функции.

sizeof(array) 

дает некоторый адрес sizeof(), который позволяет определить размер. Это тот адрес, который я хотел бы передать своей функции.

Есть ли причина, по которой я не могу передать переданное значение sizeof() моей функции?

Редактирование: поскольку операция sizeof() предполагает, что массив может передаваться без «разложения указателя». user529758 дает три примера в this discussion

in C99 there are three fundamental cases, namely: 
1. when it's the argument of the & (address-of) operator. 
2. when it's the argument of the sizeof operator. 
3. When it's a string literal of type char [N + 1] or a wide string literal of type wchar_t [N + 1] (N is the length of the string) which is used to initialize an array, as in char str[] = "foo"; or wchar_t wstr[] = L"foo";. 

Что я стремлюсь делать, если возможно с помощью & массива.

+0

Почему второй отрезанный провал снова? Это правильный способ сделать что-то. Единственное, что я не вижу смысла передавать указатель на «время», а не только его ценность. И .. форматирование. Не сохраняйте символы новой строки. –

+1

Вы не можете напрямую передать массив как аргумент функции. Обычный способ передачи массива косвенно состоит в том, чтобы передать два аргумента: адрес 0-го элемента и длину массива. (В некоторых случаях вы можете опустить аргумент размера, если размер может быть определен из содержимого массива, например, конец строки обозначается символом '' \ 0''.) Я не уверен почему вам нужен указатель на указатель. Я отмечаю, что вы не показали нам определения объекта массива, который хотите передать. –

+0

@KeithThompson Я ищу способ, который будет работать без символа, указывающего конец массива. – kjl

ответ

0

Когда вы объявляете массив, то, что c делает в фоновом режиме, просто выделяет достаточно памяти для нужного вам размера, а затем дает вам указатель. когда вы говорите

int arr[20]; 

что эффективно происходит, что с выделяет достаточно памяти для 20 Интс и дает указатель с именем обр (есть какая-то разница, но для простоты я объясняю это так), так что если сигнатура функции требует указателя на int, вы можете передать ему массив.

void foo(int *); 
foo(arr);  */ works */ 

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

arr[10] = somevalue; 
*(arr+10) = somevalue; 
// In general, arr[n] is equivalent to *(arr+n). 

надеюсь, что это поможет вам понять это немного лучше, даже если мое объяснение был немного упрощен.

+1

Просто nit, но два утверждения не эквивалентны. '* (arr + 9)' эквивалентно 'arr [9]'. Индексы основаны на нулевом значении. то есть '* (arr + 0)' такой же, как 'arr [0]'. – ryyker

+0

кричит и благодарит, отредактировал одобренный. – monkeyStix

3

В C вы не можете найти размер массива в вызываемой функции. Функция звонящего должна передать еще один аргумент с указанием размера массива.


Давайте рассмотрим некоторые примеры, чтобы понять, почему это не так.

Сначала вы попробуете передать массив в качестве аргумента при вызове функции. Однако обратите внимание, что при передаче массива в качестве аргумента он автоматически переходит к указателю на тип данных его элемента. И это предотвратит функцию called от вычисления размера массива с помощью оператора sizeof.

Например,

int main(void) 
{ 
    int arr_a[2] = {22, 33}; 
    int arr_b[5] = {6, 7, 8, 9, 10}; 

    foo(arr_a); // Here arr_a decays to an `int *` 
    foo(arr_b); // Here arr_b decays to an `int *` too 

    return 0; 
} 

void foo(int *arr) 
{ 
    sizeof(arr); 
    /* Here sizeof(arr) will always give the size of 
    * an `int *` which maybe 4 or 8 bytes depending 
    * on platform. It does not matter weather arr_a 
    * or arr_b was passed from main. 
    * And because sizeof(arr) always gives the sameresult, 
    * we cannot use sizeof(arr)/sizeof(arr[0]) to calculate 
    * the size of array that was passed. 
    */ 

    /* This value will always be the same, 
     * regardless of what was passed */ 
    sizeof(arr)/sizeof(arr[0]); 

} 

Кроме того, обратите внимание, что это:

void foo(int arr[]) { ... } 

эквивалентно:

void foo(int *arr) { ... } 

Компилятор просто изменит int arr[] в int *arr. Поэтому наличие int arr[] в качестве параметра не имеет никакого значения.

Следующий, вы можете подумать об отправке адреса массива (выполнив &arr_name). Однако учтите, что &arr_name является pointer to array (of some DEFINITE size), который составляет от pointer to pointer to underlying datatype. На этот раз вы сделаете что-то вроде этого.

void foo(void) { 
    int arr_a[2] = {22, 33}; 
    int arr_b[3] = {7, 8, 9}; 
    bar(&arr_a); // Note here that type of `&arr_a` is `int (*)[2]`, 
        // i.e. a `pointer to int array of 2 elements`, which is 
        // different from a `pionter to pointer to int` 

    bar(&arr_b); // Note here that type of `&arr_b` is `int (*)[3]`, 
        // i.e. a `pointer to int array of 3 elements`, which is 
        // different from a `int (*)[2]`, 
        // i.e a `pointer to int array of 2 elements` 
        // Note that this will give ERROR. See comments in bar() 
    return 0; 
} 

void bar(int (*arr)[2]) { 
    /* 
     * The caller of this function can ONLY pass int arrays with 
     * 2 elements. Caller CANNOT pass int array with 3 elemens, or 
     * 1 element, or 5 element. 
     * This means you ALWAYS KNOW the size of arrays being passed, 
     * and although you can calculate the size by doing 
     * sizeof(*arr)/sizeof(*arr[0]); 
     * There is no point in calculating it - you alreay know the size 
     */ 
} 

Таким образом, в основном вы не можете даже пройти pointer to the array пропусканием &array_name, чтобы решить эту проблему, потому что вы будете нуждаться различные функции для принятия массивов различных размеров. Например, void bar_2(int (*arr)[2]) {...} принять pointer to array of 2 integers и void bar_3(int (*arr)[3]) {...} принять pointer to array of 3 integers. Кроме того, нет смысла вычислять размер этих функций, как вы уже это знаете.

Последнее,, вы попробуете пройти мимо pointer to pointer to the underlying datatype.Таким образом, вы делаете что-то вроде:

void foo() { 
    int arr_a[2] = {22, 33}; 
    int arr_b[5] = {6, 7, 8, 9, 10}; 
    int *ptr; 
    ptr = &arr_a[0]; 
    bar(&ptr); // Passing pointer to pointer to int (int **) 
    ptr = &arr_b[0]; 
    bar(&ptr); // Passing pointer to pointer to int (int **) 
} 

void bar(int **pptr) { 
    sizeof(*pptr); 
    /* This will always be the same. 
    * i.e. the size of an integer pointer 
    * So here again you cannot use 
    * sizeof(*pptr)/sizeof((*pptr)[0]) to calculate the size 
    * as it will always give the same result */ 

    sizeof(*pptr)/sizeof((*pptr)[0]) // Always same, no matter what was 
             // passed by the caller 
} 

Вы видите, что прохождение pointer to pointer to underlying datatype также не решает эту проблему.

Итак, вы видите, что независимо от того, что вы делаете, вы НЕ МОЖЕТЕ найти размер массива, используя функцию sizeof() в вызываемой функции. Вызываемая функция может знать размер массива , только если абонент передает эту информацию.


В качестве дополнительного примечания в вашем коде есть проблема. Когда вы делаете

i = 0; while (now > hourLongs[i] && i < j){i++;} // AND 
i = 0; while (*time> (timeList_pointer)[i] && i < size){i++;} 

порядок ваших условий в while цикле должно быть наоборот. Он должен быть

i = 0; while (i < j && now > hourLongs[i]){i++;} // AND 
i = 0; while (i < size && *time> (timeList_pointer)[i]){i++;} 

Это потому, что вы должны сначала проверить, что i находится в пределах массива, а затем только оценить hourLongs[i] или (timeList_pointer)[i].

+0

Комментарии не предназначены для расширенного обсуждения; этот разговор был [перемещен в чат] (http://chat.stackoverflow.com/rooms/120553/discussion-on-answer-by-sps-how-to-pass-a-pointer-to-an-array- без-распад, и). – Flexo

+0

@sps Опять же, вам не нужно искать то, что вы уже знаете :)) – Michi

+0

@ Michi OP хочет найти его в функции. Вы все еще не поняли вопроса. OP хочет написать функцию, которая вычисляет '10' для' char arr [10]; ',' 15' для 'char arr [15];' и '20' для' char arr [20]; 'путем передачи onle Один аргумент этой функции. Ответьте, если вы пишете эту функцию. Более предпочтительный, пожалуйста, отправьте ответ своим решением для массива типа char. – sps

1

Как и другие, вы не можете передать массив функции и получить ее размер из-за того, как массивы распадаются на указатель на первый элемент при передаче функции. Поэтому вам нужно передать массив и его размер в вашу функцию.

Существует окольный способ передачи массива функции, поэтому вы можете получить его размер, однако он работает только для массивов фиксированного размера.

#include <stdio.h> 
#include <stdlib.h> 

void test1(int (*a)[10]) 
{ 
    int i; 
    printf("size=%zu\n",sizeof(*a)); 
    for (i=0;i<sizeof(*a)/sizeof((*a)[0]);i++) { 
     printf("%d\n",(*a)[i]); 
    } 
} 

int main() 
{ 
    int a[10] = {1,2,3,4,5,6,7,8,9,10}; 
    test1(&a); 
    return 0; 
} 

Вышеупомянутый код позволяет передавать указатель на массив фиксированного размера. Затем вы можете разыменовать этот указатель, чтобы получить количество элементов как sizeof(*a)/sizeof((*a)[0]).

Вы можете только передать массив int [10] к этой функции. Вы не можете передать массив любого другого размера. Таким образом, в этом случае вы можете просто заменить указанное выше выражение на 10, так как размер известен.