Можно ли определить указатель без переменной temp / aux?(Или это будет плохое C-кодирование?) - PullRequest
0 голосов
/ 14 февраля 2019

Я пытаюсь понять C-указатели.В качестве фона я привык к кодированию в C# и Python3.

Я понимаю, что указатели могут использоваться для сохранения адресов переменной (запись чего-то вроде type* ptr = &var;), и что увеличение указателей эквивалентно увеличению индекса массива объектов этого типа объекта type,Но я не понимаю, можете ли вы использовать указатели и защищенные объекты type (например, int) без указания на уже определенную переменную.

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

Например, чтобы прояснить мою путаницу, , если нет способа использовать указатели без использования предопределенных жестко закодированных переменных, зачем вообще использовать указатели вместо основного объекта,или массивы объектов?

Ниже приведен небольшой фрагмент кода для формального описания моего вопроса.

Большое спасибо за любые советы!

// Learning about pointers and C-coding techniques.

#include <stdio.h>

/* Is there a way to define the int-pointer age WITHOUT the int variable auxAge? */

int main()  // no command-line params being passed
{
    int auxAge = 12345;
    int* age = &auxAge;
    // *age is an int, and age is an int* (i.e. age is a pointer-to-an-int, just an address to somewhere in memory where data defining some int is expected)
    // do stuff with my *age int e.g. "(*age)++;" or "*age = 37;"
    return 0;
}

Ответы [ 5 ]

0 голосов
/ 14 февраля 2019

Но я не понимаю, можете ли вы использовать указатели и объекты со ссылками типа (например, int) без ссылки на уже определенную переменную.

Да,Есть два случая, когда это возможно.

Первый случай происходит с динамическим выделением памяти.Вы используете функции malloc, calloc или realloc для выделения памяти из динамического пула памяти («куча»):

int *ptr = malloc( sizeof *ptr ); // allocate enough memory for a single `int` object
*ptr = some_value; 

Второй случай, когда у вас есть фиксированный,четко определенный адрес для канала ввода-вывода или порта или чего-то еще:

char *port = (char *) OxDEADBEEF;

, хотя это чаще встречается во встроенных системах, чем при программировании общих приложений.

РЕДАКТИРОВАТЬ

Относительно второго случая, глава и стих :

6.3.2.3 Указатели

...

5 Целое число может быть преобразовано в любой тип указателя.За исключением случаев, указанных ранее, результат определяется реализацией, может быть неправильно выровнен, может не указывать на объект ссылочного типа и может быть представлением прерывания. 67)

67) Функции отображения для преобразования указателя в целое число или целое число в указатель должны соответствовать структуре адресации среды выполнения.
0 голосов
/ 14 февраля 2019

Наиболее распространенная причина: потому что вы хотите изменить содержимое, не передавая его.

Аналогия:
Если вы хотите, чтобы ваша гостиная была окрашена, вы не хотите помещать свой дом на грузовиктрейлер, переместите его к художнику, позвольте ему сделать работу и затем возьмите его обратно.Это будет дорого и отнимает много времени.И если ваш дом слишком широк, чтобы его можно было тащить по улицам, грузовик может разбиться.Вы бы предпочли сообщить художнику, по какому адресу вы живете, попросить его пойти и сделать работу.

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

// BAD CODE, DONT DO THIS
typedef struct { ... } really_big;
really_big rb;
rb = do_stuff(rb);

...    

rb do_stuff (really_big thing) // pass by value, return by value
{
  thing->something = ...;
  ...
  return thing;  
}

Это делает копию rb с именем thing.Он помещается в стек, тратя много памяти и без необходимости увеличивая используемое пространство стека, увеличивая вероятность переполнения стека.А копирование содержимого из rb в thing занимает много времени выполнения.Затем, когда он возвращается, вы делаете еще одну копию, от thing обратно до rb.

Передав указатель на структуру, копирование не выполняется, но конечный результат оченьто же самое:

void do_stuff (really_big* thing)
{
  thing->something = ...;
}
0 голосов
/ 14 февраля 2019

Да, вы можете использовать динамическое выделение памяти (также известное как «куча»):

#include <stdlib.h>

int * const integer = malloc(sizeof *integer);
if (integer != NULL)
{
  *integer = 4711;
  printf("forty seven eleven is %d\n", *integer);
  free(integer);
  // At this point we can no longer use the pointer, the memory is not ours any more.
}

Это просит библиотеку C выделить часть памяти из операционной системы и вернуть указатель на нее.Выделение sizeof *integer байтов делает распределение подходящим для целого числа, и тогда мы можем использовать *integer для разыменования указателя, что будет работать почти так же, как прямая ссылка на целое число.

0 голосов
/ 14 февраля 2019

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

struct very_large_structure {
    uint8_t kilobyte[1024];
}

А теперь предположим функцию, которая должна использовать эту структуру:

bool has_zero(struct very_large_structure structure) {
    for (int i = 0; i < sizeof(structure); i++) {
        if (0 == structure.kilobyte[i]) {
            return true;
        }
    }

    return false;
}

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

Если вы передадите структуру через указатель, вы копируете в стек только указательсамо по себе, как правило, 32-битное число:

bool has_zero(struct very_large_structure *structure) {
    for (int i = 0; i < sizeof(*structure); i++) {
        if (0 == structure->kilobyte[i]) {
            return true;
        }
    }

    return false;
}

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

0 голосов
/ 14 февраля 2019

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

void clear(int *x)
{
    *x = 0;
}

int main()
{
    int a = 4;
    printf("a=%d\n", a);   //  prints 4
    clear(&a);
    printf("a=%d\n", a);   //  prints 0
    return 0;
}

Вы также можете использовать указатели для указания динамически выделяемой памяти:

int *getarray(int size)
{
    int *array = malloc(size * sizeof *array);
    if (!array) {
        perror("malloc failed"); 
        exit(1);
    }
    return array;
}

Это всего лишь несколько примеров.

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