Определить палиндром - как работает оператор *? - PullRequest
0 голосов
/ 22 октября 2011

Эта программа должна взять трехзначное число и изменить его на свой палиндром. 123 станет 321.

Логика верна, и программа компилируется правильно. :) Однако логика этого не дается легко.

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

#include <stdio.h>

void reverse_number(int in_val, int *out_val) {
    int ones, tens, hundreds;

    ones = in_val % 10;
    tens = (in_val % 100 - ones) / 10;
    hundreds = (in_val - (ones + tens)) / 100;

    *out_val = (ones * 100) + (tens * 10) + hundreds;
}

int main() {
    int in_val;
    int out_val;

    printf("Give a three digit num to reverse: \n");
    scanf("%d", &in_val);

    reverse_number(in_val, &out_val);
    printf("New number is: %d \n", out_val);

    return 0;
}

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

Например, я знаю, что m = &q; дает переменной m адрес другой переменной q, и я знаю, что m = *g; будет означать, что значение по адресу g войдет в m, но Я действительно не знаком с тем, как они работают в контексте функции и основного файла.

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

Ответы [ 2 ]

5 голосов
/ 22 октября 2011

Когда я запускаю его, он компилируется и даже работает.Смотрите: http://ideone.com/RHWwI

Так что, должно быть, именно так вы его компилируете.В чем ошибка вашего компилятора?

2 голосов
/ 22 октября 2011

Ну, так как вы прекрасно поняли операторы & и *, остальное очень очень просто.

Допустим, у вас есть:

int q;
int *m;
m = &q;

Тогда, если вы скажете:

int *m2;
m2 = m;

m2 будет содержать то же значение, что и m, то есть будет иметь адрес q. Следовательно, *m и *m2 приведут вас к одному и тому же значению (которое является значением q) (вы делаете понимаете, что * является обратным оператором &, верно? *(&q) = q и &(*m) = m (в последнем случае m должен быть указателем для *, чтобы быть применимым.))

Итак, как это работает с функциями? Просто! Когда вы передаете аргументы функциям, вы передаете их по значению. Когда вы передаете указатель, вы фактически передаете значение, указатель на переменную.

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

reverse_number(in_orig, &out_orig);

Я переименовал ваши in_val и out_val в основном в in_orig и out_orig, чтобы они не смешивались с reverse_number.

Теперь &out_orig - это адрес out_orig. При передаче в качестве аргументов это копируется в out_val аргумент reverse_number. Это в точности как запись:

int *out_val = &out_orig;

Теперь, если бы у вас была указанная выше строка в вашем main, вы могли бы просто написать *out_val = something;, и это изменит out_orig, верно? Ну, так как у вас есть адрес out_orig в out_val, то кого волнует, установлен ли *out_val в main или reverse_number?

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

Редактировать : * в определении указателя

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

Это просто определение, поэтому вы должны изучить его:

Если у вас есть значение типа type (например, int), то адрес этой переменной (с использованием operator &) имеет тип type * (в этом примере int *). Поскольку указатель принимает этот адрес, тип указателя type *.

Напротив, если указатель имеет тип type * (например, int *), то получение значения, на которое указывает указатель (используя operator *), имеет тип type (в этом примере int ).

Таким образом, вы можете сказать что-то вроде этого:

operator &, adds one * to the type of the variable
operator *, removes one * from the type of the expression

Итак, давайте посмотрим несколько примеров:

int x;
x has type int
&x has type int *

float *y;
y has type float *
&y has type float **
*y has type float

struct Data ***d;
d has type struct Data ***
&d has type struct Data ****
*d has type struct Data **
*(*d) has type struct Data *
*(*(*d)) has type struct Data

Если вы заметили, я сказал, что & добавляет один * к типу переменной , но * удаляет один * из типа выражения, Это почему? Потому что & дает адрес переменной. Конечно, потому что ничто другое не имеет адреса. Например, a+b (возможно) не имеет какого-либо адреса в памяти, а если он есть, он просто временный и бесполезный.

operator * однако, работает по адресам. Независимо от того, как вы вычисляете адрес, operator * работает на нем. Примеры:

*(0x12345678) -> Note that even if the compiler let's you do this,
                 your program will most likely crash

*d -> like we saw before

*(d+4) -> This is the same as writing d[4]
          And now you know why arrays and pointers are treated as one

В случае динамического 2d-массива:

*(*(d+4)+6) -> This is the same as writing d[4][6]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...