Вопрос

В программе C ниже я не понимаю, почему Buf [0] = 'a' после того, как я звоню foo. Разве FOO не делает пропускной стоимость?

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

    void foo(char buf[])
    {
      buf[0] = 'A';
    }

    int main(int argc, char *argv[])
    {
      char buf[10];

      buf[0] = 'B';
      printf("before foo | buf[0] = %c\n", buf[0]);
      foo(buf);
      printf("after foo | buf[0] = %c\n", buf[0]);

      system("PAUSE"); 
      return 0;
      }

выход:

before foo | buf[0] = 'B' 
after foo | buf[0] = 'A'
Это было полезно?

Решение

void foo(char buf[])

такой же как

void foo(char* buf)

Когда вы называете это, foo(buf), Вы передаете указатель по значению, поэтому копия указателя сделана.

Копия указателя указывает на тот же объект, что и оригинальный указатель (или в этом случае, к начальному элементу массива).

C не имеет прохождения по ссылке семантики в том смысле, что C ++ проходит по ссылке семантики. Все в C передается по значению. Указатели используются для пропуска по ссылкой семантики.

Другие советы

Массив - это просто модный способ использовать указатель. Когда вы проходите buf к функции, вы проходите указатель По значению, но когда вы разымеваете указатель, вы все еще ссылаетесь на строку, которые он указывает.

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

void foo( char buf[] );

такой же как

void foo( char* buf );

Аргумент массива тогда распадается указателю на свой первый элемент.

Массивы обрабатываются по-разному, чем другие типы; Вы не можете пройти массив «по значению» в C.

Онлайн стандарт C99 (проект N1256), Раздел 6.3.2.1, "Lvalues, массивы и дизайн функции", пункт 3:

За исключением случаев, когда он является операндом оператора SIZEOF или NANY & OPERAL OPERANCE, или является строковым литералом, используемым для инициализации массива, выражение, которое имеет тип «массив типа», преобразуется в выражение с помощью указателя типа Тип «», который указывает на начальный элемент объекта массива и не является Lvalue. Если объект Array имеет класс хранения регистрации, поведение не определено.

В вызове

foo(buf);

выражение массива buf не оперен sizeof или &, и не является строковым буквальным, не используемым для инициализации массива, поэтому оно неявно преобразовано («распады») от типа «10-элементный массив CHAR», чтобы «Указатель на Char» и адрес первого элемента передается Foo. Поэтому все, что вы делаете, чтобы buf в foo() будет отражен в buf массив внутри main(). Отказ Из-за того, как определяется подписка массива, вы можете использовать оператор подплиги на типе указателя, так что это выглядит Как вы работаете с типом массива, но вы нет.

В контексте объявления параметров функции, T a[] а также T a[N] являются синонимом T *a, но это Только случай, когда это правда.

* Char Buf [] на самом деле означает Char **, так что вы проходите по указателю / ссылке. Это дает вам, что Buf является указателем, как в основной() а также фюра() Функция.

Потому что вы передаете указатель на buf (по стоимости). Так что контент указан buf изменился.

С указателями это другое; Вы проходите по значению, но то, что вы проходите, - это значение указателя, которое не совпадает с значением массива.

Итак, значение указателя не меняется, но вы изменяете то, на что он указывает.

Массивы и указатели (почти) то же самое.

int* foo = malloc(...)

foo[2] такой же как *(foo+2*sizeof(int))

Anecdote: Вы написали

int main(int argc, char *argv[])

Это также законно (будет сознавать и работать так же), чтобы написать

int main(int argc, char **argv)

а также

int main(int argc, char argv[][])

Они эффективно одинаковы. Его чуть сложнее, потому что массив знает, сколько элементов у него есть, и указатель не. Но они используются то же самое.

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

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

Если вы хотите сохранить содержимое исходного массива, вы можете скопировать строку на временное хранилище в функции.

Редактировать: Что произойдет, если вы завернули массив Char в структуре и передали структуру? Я верю, что это может работать тоже, хотя я не знаю, какого рода накладных расходов может создать на уровне компилятора.

Пожалуйста, обратите внимание на одну вещь,

декларация

void foo(char buf[])

Говорит, что будет использование [] обозначения. Не какой элемент массива вы будете использовать.

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

void foo(char buf[X]); //where X would be a constant.

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

voi foo(char value);

так...

void foo(char buf[])

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

Более того ... Что бы вы ожидали ... вы отправили на функцию Foo имя массива

foo(buf);

который эквивалентен и Buf [0]. Итак ... это указатель.

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

Использование массивов в параметрах функций - это хороший способ сигнализировать для своих пользователей API, что эта штука должна быть блоком памяти, сегментированной в N-байтовые куски размером, но не ожидайте, что компиляторы заботы, если вы хотите записать char *foo char foo[] или char foo[12] в функциональных параметрах. Они не будут.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top