1

I have a simple structure.

struct grades
{
 int lowest;
 int highest;
};

Then I am to create a function that returns a pointer which initializes the structure.

struct *grades setGrades(int low, int high)
{
  struct *ptr = malloc(sizeof(struct grades));
  ptr->lowest = low;
  ptr->highest = high;
  return ptr;
}

Now I am supposed to make a function with definition struct **grades random(int size); I am supposed to allocate space for an array of pointers to grade structures with the number of elements equal to size. When the array of pointers is created, I want to set each pointer in the array to a newly created data structure that has the low variable equal to 10 and high variable equal to 100 and then return pointer.

I am really lost at this point as I looked up double pointers to structures online but did not find any examples that can help me clear my understanding. I was wondering if someone can perhaps explain me how double pointers to structures work it would give me a Great start in the right directions.

11
  • 7
    struct *grades and struct *ptr ??? Commented Oct 2, 2014 at 14:42
  • 1
    a better function name would be createGradeSet because you are returning a new struct each time that is called. Commented Oct 2, 2014 at 14:45
  • 4
    no, but surely you mean struct grades* and struct grades* ptr, no? ;) Commented Oct 2, 2014 at 14:47
  • 1
    I'm still at a loss to understand why the pointer is needed at all. If ever there was born a structure than can easily copy by-value, that's it. Commented Oct 2, 2014 at 14:49
  • 1
    "double pointer" is not likely to give you a lot of relevant hits. There is a numeric type double for a "double precision floating point number" (so like float, but "bigger"). You might find more relevant reading with "pointer to a pointer". If you think of a pointer as being a data type like any other, just realize that *pp will give you a pointer if pp is a pointer-to-pointer. Commented Oct 2, 2014 at 14:49

3 Answers 3

2

A "double pointer" as you called it is simply a pointer to a pointer. That is, struct grade example is a variable that contains a lowest and a highest as you've defined. A pointer to that, struct grade *example is a variable that stores the memory address of the same structure. A pointer to a pointer, struct grade **example, is a variable that stores the memory address of a variable that stores the memory address of your structure. A more detailed explanation can be found here. Anyways, to answer your specific question, a function would be:

struct grades** random(int size) {
    struct grades** result = malloc(sizeof(struct grades*) * size); //here you are
                                                    //allocating enough space for an
                                                    //array of pointers
    int i;
    for(i = 0; i < size; i++) {
        result[i] = setGrades(10, 100); //here you are setting each pointer to one
                                        //grade through the function you've already
                                        //defined
    }

    return result;
}
Sign up to request clarification or add additional context in comments.

2 Comments

how would you print the values set by doule pointer just to check if it is set?
For a single pointer, you would print result->lowest, correct? For a pointer to a pointer, you need to use result[i]->lowest. Here, result[i] is the i-th pointer in your array of pointers to grades.
2
struct grades { int lowest; int highest; };

struct grades * createGradeSet(int low, int high) //careful: return type is struct grades *
{
  // variable name: ptr, type: struct grades *
  struct grades * ptr = malloc(sizeof(struct grades)); 
  ptr->lowest = low;
  ptr->highest = high;
  return ptr;
}

struct grades ** random(int size)
{
  // Create a pointer to an array of struct grades pointers
  // the size of the array is `size` x the size of a struct grades pointer
  struct grades ** ptr_arr = malloc(sizeof(struct grades *) * size); 
  for (unsigned int i = 0; i < size; i++)
     ptr_arr[i] = createGradeSet(10, 100);  // assign a newly created Gradeset to every cell
  return ptr_arr;
}

Comments

1

Try the following

struct grades ** random( size_t size )
{
    if ( size == 0 ) return NULL:

    struct grades **p = malloc( size * sizeof( struct grades * ) );

    if ( p != NULL )
    {
        size_t i = 0;
        do
        {
            p[i] = malloc( sizeof( struct grades ) );
            if ( p[i] != NULL )
            {
                p[i]->lowest = 10;
                p[i]->highest = 100;
            }
        } while ( p[i] != NULL && ++i < size );

        if ( i != size )
        {
            for ( size_t j = 0; j < i; j++ ) free( p[i] );
        }
        free( p );
        p = NULL;    
    }

    return p;
}      

Function setGrades should be written as

struct *grades setGrades( int low, int high )
{
    struct *p = malloc( sizeof( struct grades ) );

    if ( p != NULL )
    {
        p->lowest = low;
        p->highest = high;
    }

    return p;
}

In this case the do while loop in the above function can be written as

        do
        {
            p[i] = setGrades( 10, 100 );
        } while ( p[i] != NULL && ++i < size );

4 Comments

Please be aware that checking the return value of malloc() cannot save your program from crashing anymore: modern kernels ovecommit their memory, so malloc() doesn't return NULL under normal circumstances. The program will neither crash nor get a chance to realize that there is no memory to back its allocations, it will be shot when the kernel realizes that it's out of memory. Consequently, checking the return value of malloc() is by far not as advisable any more as it used to be. Especially considering how it clutters your code.
Nah, I don't think so: It's basically impossible for the kernel to know when it overcommits memory, and if it ran a conservative policy, it would be neigh impossible to actually use all the memory available. Just think about the effect of a fork: Theoretically, the new process requires as much memory as the old one required. Thus, under conservative policy, you wouldn't be able to fork if your process already held half the memory. But in a fork due to a system() call, the fork will immediately release the inherited memory. So the kernel shouldn't stop your process from forking.
@cmaster I am sorry but I am not interesting this stupidy. I advice to think about that all prohrams in this case have undefined behavious.:)
Undefined behavior that is segfaulting on all sane systems... yes, technically, the language standard allows anything to happen, but dereferencing a NULL pointer is such a common thing that all systems that I know of have safeguards built in to securely sefault any program that does it.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.