Указатель строк и целых чисел - PullRequest
1 голос
/ 13 февраля 2020

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

 void swapping(int *a,int *b){
    int temp=0;
    temp= *a;
    *a=*b;
    *b=temp;

}

int main(){
    int a=1,b=2;
    swapping(&a,&b);
    printf("%d\n%d\n",a,b );
    return 0;
}

Однако, когда я продолжаю передавать строки (массивы символов), такие операции возможны:

void split(char take1[],char take2[], char str[]){
    int i=0,j=0,yes=0;
    while(str[i]!='\0'){
        if(str[i]=='*'){
            yes=1;
            i++;
        }
        if(yes==0){
            take1[i]=str[i];
        }
        else if (yes!=0){
            take2[j]=str[i];
            j++;
        }
        i++;
    }
}
int main(){
    char taker1[30],taker2[30];
    char str[30]="Hello*world";
    split(taker1,taker2,str);
    printf("%s\n%s\n",taker1,taker2) ;
    return 0;
}

Мое поверхностное понимание состоит в том, что вызываемые функции временно сохраняются в ОЗУ, поэтому значение переназначается в функции будут удалены после завершения вызова функции. Таким образом, нам нужно изменить значение указателя в памяти.

Но я не понял, почему нет необходимости передавать указатель массивов символов, как во втором примере, в функцию (split()) для изменения их значений. Может кто-нибудь, пожалуйста, помогите понять, почему? Спасибо!

Ответы [ 3 ]

2 голосов
/ 13 февраля 2020

(OP) Но я не понял, почему нет необходимости передавать указатель массивов символов, как во втором примере, в функцию (split ()) для изменения их значений.

При многих операциях 1 массивы преобразуются в указатель первого элемента. Это случилось с

split(taker1,taker2,str);

Давайте копать глубже.


Стандартная библиотека C определяет string

A строка - это непрерывная последовательность символов, оканчивающаяся и включающая первый нулевой символ. C17dr § 7.1.1 1

char массив str ниже содержит строку .

char str[30]="Hello*world";

char массивы taker1, taker2 являются инициализирован. Они не обязательно содержат строку .

char taker1[30],taker2[30];

(OP). Я продолжаю передавать строки (массивы символов),

Не совсем , Ниже char массив taker1 преобразуется в адрес первого элемента при передаче в функцию. Аналогично для taker2, str

split(taker1, taker2, str);

split() получает 3 указателя, даже если он может выглядеть как массив.

void split(char take1[],char take2[], char str[]){
// same as 
void split(char *take1, char *take2, char *str) {

Тело split() затем использует эти указатели для манипулирования данными. Напомним, эти указатели указывают на main str[], taker1[], taker2[]. Когда splt() сделано, printf("%s\n%s\n", taker1, taker2) ; показывает эффект.


1 За исключением случаев, когда это операнд оператора sizeof или унарный * Оператор 1063 * или строковый литерал, используемый для инициализации массива, выражение с типом «массив тип » преобразуется в выражение с типом «указатель на тип », которое указывает на начальный элемент объекта массива и не является lvalue. C17dr

0 голосов
/ 13 февраля 2020

ОБЪЯСНЕНИЕ

Это потому, что в C объявление массива внутри указателя затухает (см. Цитату в конце для деталей). Когда вы объявляете char a[], это аналогично объявлению char* a. В обоих этих случаях a хранит адрес памяти первого элемента массива. Но в случае таких переменных, как простые целые числа или символы, такие как int x = 10;, переменная x будет фактически хранить значение 10.

Когда вы объявляете массив, такой как

char a[10];

объект, обозначенный выражением a, представляет собой массив (т. Е. Непрерывный блок памяти, достаточно большой, чтобы вместить 10 символьных значений, или string ), и тип выражения a - это «массив из 10 символьных элементов», или char[10]. Выражение a неявно преобразуется в char *, и его значением является адрес первого элемента.

Таким образом, когда вы передаете переменную массива в функцию, вы фактически передаете адрес памяти ( или базовый адрес) массива. И так как вы написали объявление своей функции как:

void split(char take1[],char take2[], char str[])

Это то же самое, что и запись:

void split(char *take1,char *take2, char *str)

И, в вашем вызове функции, который:

split(taker1,taker2,str);

taker1, taker2 и str фактически содержат базовые адреса соответствующих символьных массивов (т. Е. Строки). Таким образом, вам не нужно явно упоминать оператор address_of (&) вместе с переменными массива в вызове функции.

Отправленный вами код также может быть записан следующим образом :

void split(char *take1,char *take2, char *str){
    int i=0,j=0,yes=0;
    while(*(str+i) != '\0'){
        if(*(str+i) == '*'){
            yes=1;
            i++;
        }
        if(yes==0){
            *(take1+i) = *(str+i);
        }
        else if (yes!=0){
            *(take2+i) = *(str+i);
            j++;
        }
        i++;
    }
}
int main(){
    char taker1[30], taker2[30];
    char str[30] = "Hello*world";
    split(taker1, taker2, str);
    printf("%s\n%s\n", taker1, taker2) ;
    return 0;
}

Обратите внимание на оператор взаимозаменяемого массива ([]) и оператор разыменования (*). Подсказка: Запись arr[5] совпадает с *(arr + 5).

КОРОТКО ДОЛГОЙ ИСТОРИИ:

  • В C массивы передаются по ссылке. Нормальные переменные передаются по значению.
  • Переменные массива можно рассматривать как указатели.
  • Обычно при вызове функций следует пропустить & с переменными массива.

БОНУС

Вышеупомянутая причина также заключается в том, что мы не используем & в scanf() для строковых переменных (с %s спецификатор формата), т. Е.

char str[10];
scanf("%s", str);

Но в случае целых чисел или других основных чисел:

int num;
scanf("%d", &num);

Кроме того, вы получите лучшее понимание задействованных понятий после того, как Dynami c Распределение памяти в C.

CITATION

Вот точный язык из C стандарт (n1256):

6.3.2.1 L Значения, массивы и указатели функций ... 3 За исключением случаев, когда это операнд оператора sizeof или унарный оператор & или строка литерал, используемый для инициализации массива, выражение с типом «массив типа» преобразуется в e xpression с типом '' указатель на тип '', который указывает на начальный элемент объекта массива и не является lvalue. Если объект массива имеет класс хранения регистров, поведение не определено.

0 голосов
/ 13 февраля 2020

char take[] по существу совпадает с char *take. Таким образом, вы фактически передаете указатель.

В случае char taker[30], например taker сам по себе является указателем, а taker[n] эквивалентно *(taker + n).

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