Gregory Fenn
Gregory Fenn

Reputation: 488

Is it possible to define a pointer without a temp/aux variable? (Or would this be bad C-coding?)

I'm trying to understand C-pointers. As background, I'm used to coding in both C# and Python3.

I understand that pointers can be used to save the addresses of a variable (writing something like type* ptr = &var;) and that incrementing pointers is equivalent to incrementing the index of an array of objects of that object type type. But what I don't understand is whether or not you can use pointers and deferenced objects of the type (e.g. int) without referencing an already-defined variable.

I couldn't think of a way to do this, and most of the examples of C/C++ pointers all seem to use them to reference a variable. So it might be that what I'm asking is either impossible and/or bad coding practice. If so, it would be helpful to understand why.

For example, to clarify my confusion, if there is no way to use pointers without using predefined hard-coded variables, why would you use pointers at all instead of the basic object directly, or arrays of objects?

There is a short piece of code below to describe my question formally.

Many thanks for any advice!

// 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;
}

Upvotes: 4

Views: 1880

Answers (5)

dbush
dbush

Reputation: 224457

Parameters to a function in C are always pass by value, so changing a parameter value in a function isn't reflected in the caller. You can however use pointers to emulate pass by reference. For example:

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;
}

You can also use pointers to point to dynamically allocated memory:

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

These are just a few examples.

Upvotes: 1

John Bode
John Bode

Reputation: 123558

But what I don't understand is whether or not you can use pointers and deferenced objects of the type (e.g. int) without referencing an already-defined variable.

Yes, there are two cases where this is possible.

The first case occurs with dynamic memory allocation. You use the malloc, calloc, or realloc functions to allocate memory from a dynamic memory pool (the "heap"):

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

The second case occurs where you have a fixed, well-defined address for an I/O channel or port or something:

char *port = (char *) OxDEADBEEF;

although this is more common in embedded systems than general applications programming.

EDIT

Regarding the second case, chapter and verse:

6.3.2.3 Pointers

...
5 An integer may be converted to any pointer type. Except as previously specified, the result is implementation-defined, might not be correctly aligned, might not point to an entity of the referenced type, and might be a trap representation.67)

67) The mapping functions for converting a pointer to an integer or an integer to a pointer are intended to be consistent with the addressing structure of the execution environment.

Upvotes: 1

Lundin
Lundin

Reputation: 214525

Most common reason: because you wish to modify the contents without passing them around.

Analogy:
If you want your living room painted, you don't want to place your house on a truck trailer, move it to the painter, let him do the job and then haul it back. It would be expensive and time consuming. And if your house is to wide to get hauled around on the streets, the truck might crash. You would rather tell the painter which address you live on, have him go there and do the job.

In C terms, if you have a big struct or similar, you'll want a function to access this struct without making a copy of it, passing a copy to the function, then copy back the modified contents back into the original variable.

// 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;  
}

This makes a copy of rb called thing. It is placed on the stack, wasting lots of memory and needlessly increasing the stack space used, increasing the possibility of stack overflow. And copying the contents from rb to thing takes lots of execution time. Then when it is returned, you make yet another copy, from thing back to rb.

By passing a pointer to the struct, none of the copying takes place, but the end result is the very same:

void do_stuff (really_big* thing)
{
  thing->something = ...;
}

Upvotes: 0

Petr
Petr

Reputation: 508

There are many good reasons to use pointers in C, and one of them is, that you can only pass by value in C - you cannot pass by reference. Therefore passing pointer to an existing variable saves you the overhead of copying it to stack. As an example, let's assume this very large structure:

struct very_large_structure {
    uint8_t kilobyte[1024];
}

And now assume a function which needs to use this structure:

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;
}

So for this function to be called, you need to copy the whole structure to stack, and that can be especially on embedded platforms where C is widely used an unacceptable requirement.

If you will pass the structure via pointer, you are only copying to the stack the pointer itself, typically a 32-bit number:

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;
}

This is by no mean the only and most important use of pointers, but it clearly shows the reasoning why pointers are important in C.

Upvotes: 1

unwind
unwind

Reputation: 400019

Yes, you can use dynamic memory (also known as "heap") allocation:

#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.
}

This asks the C library to allocate some memory from the operating system and return a pointer to it. Allocating sizeof *integer bytes makes the allocation fit an integer exactly, and we can then use *integer to dereference the pointer, that will work pretty much exactly like referencing an integer directly.

Upvotes: 8

Related Questions