LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Linux - Newbie (https://www.linuxquestions.org/questions/linux-newbie-8/)
-   -   Problem with a C program (https://www.linuxquestions.org/questions/linux-newbie-8/problem-with-a-c-program-764372/)

vasmakk 10-25-2009 02:32 PM

Problem with a C program
 
Hello!

I understand that this question is probably for another topic or thread but I have this little problem trying to understand memory allocation in C. I want to allocate memory from inside a function A() and use this memory from another function B(). The whole process should be controlled from main...

To help you understand on what I mean, I wrote this simple program. But after a successful compilation It gives me many memory allocation errors when run. And memory segmentation errors if I move the definition struct apoint *p outside the main(). How can I correct this to have a successful run?

Please someone with great experience in C could help me?

Regards
Vas




Code:

#include <stdio.h>
#include <stdlib.h>

struct apoint {
      int x ,y; };


void allocate (struct apoint *);
void printpnt (struct apoint *);


int main(void) {

struct apoint *p;

        allocate (p);
        printpnt (p);
        free (p);
        return 0;
}


void allocate (struct apoint *pnt) {

        pnt = (struct apoint *) malloc (sizeof (struct apoint));
        pnt->x = 10;
        pnt->y = 35;
}


void printpnt (struct apoint *pnt) {
        printf ("(x , y) = (%d , %d)\n", pnt->x , pnt->y);

}


smeezekitty 10-25-2009 02:48 PM

tried your code in windows and it crashed, dont know why.

vasmakk 10-25-2009 02:54 PM

Quote:

Originally Posted by smeezekitty (Post 3732072)
tried your code in windows and it crashed, dont know why.

this is because of Segment Violation
But I don't know what causes it ...
In linux also crashes ...

Unfortunately all malloc() examples I have seen so far use it inside main(). But the application I write ( a small database) Is very big to fit in main() so I have to split it in functions ... Any Ideas?

Vas

paulsm4 10-25-2009 02:55 PM

Hi -

I'm a huge fan of C ... but frankly, this kind of design cries out for a C++ class (instead of a C struct with a C malloc in a C "initial()" function).

Anyway:
Code:

#include <stdio.h>
#include <stdlib.h>

/*
 * Global typedefs and definitions
 */
struct apoint
{
  int x ,y;
};


/*
 * Function prototypes
 */
void allocate (struct apoint **point_pp);
void init2 (struct apoint *point_p);
void printpnt (struct apoint *point_p);

/*
 * allocate: Allocate space for, and initialize an "apoint" structure
 */
void allocate (struct apoint **point_pp) {
        *point_pp = (struct apoint *) malloc (sizeof (struct apoint));

        *point_pp->x = 10;
        *point_pp->y = 35;
}

/*
 * init2: Assume memory is allocated - just initialize the struct
 */
void init2 (struct apoint *point_p) {
        point->x = 10;
        point->y = 35;
}


/*
 * printpnt: Dump the value of "point"
 */
void printpnt (struct apoint *point_p) {
        printf ("(x , y) = (%d , %d)\n", point_p->x , point_p->y);

}

/*
 * program root
 */
int main(void) {
  struct apoint *point1_p = NULL;
  struct apoint point2;

  allocate (&point1_p);
  printpnt (point1_p);

  init2 (&point2);
  printpnt (&point2);

  return 0;
}


smeezekitty 10-25-2009 02:55 PM

got it:
Code:

#include <stdio.h>
#include <stdlib.h>

struct apoint {
      int x ,y; };


void allocate (struct apoint **);
void printpnt (struct apoint **);


int main(void) {

struct apoint *p;

        allocate (&p);
        printpnt (&p);
        free (p);
        return 0;
}


void allocate (struct apoint **pnt) {

        (*pnt) = (struct apoint *) malloc (sizeof (struct apoint));
        (*pnt)->x = 10;
        (*pnt)->y = 35;
}


void printpnt (struct apoint **pnt) {
        printf ("(x , y) = (%d , %d)\n", (*pnt)->x , (*pnt)->y);

}

you need a double pointer because its actually a pointer to a pointers
so you get the real thing not a copy of it

vasmakk 10-25-2009 03:05 PM

Thank you guys!
I'm very obliged to you

Vas

johnsfine 10-25-2009 03:30 PM

Quote:

Originally Posted by paulsm4 (Post 3732077)
I'm a huge fan of C ... but frankly, this kind of design cries out for a C++ class

But the problem in the original code just calls out for the C++ feature of pass by reference.

In C you can get the semantic equivalent of pass by reference (using uglier syntax) with the method you showed: Add an extra level of indirection.

But in this example in C, that obscures the function and there was a simpler solution.

The apoint* is conceptually the return value of the allocate function. There are many times in C where it is appropriate to implement a conceptual return value by passing a pointer in rather than passing the value out. But in simple cases like this one, a conceptual return value is best implemented as an actual return value.

Instead of
Code:

void allocate (struct apoint **point_pp);
use
Code:

struct apoint *allocate (void);
then
Code:

struct apoint *allocate (void) {
    struct apoint *result = (struct apoint *) malloc (sizeof (struct apoint));
    result->x = 10;
    result->y = 35;
    return result;
}

Instead of
Code:

  allocate (&point1_p);
use
Code:

  point1_p = allocate();
Quote:

Originally Posted by smeezekitty (Post 3732078)
got it:
Code:

void printpnt (struct apoint **);
you need a double pointer because its actually a pointer to a pointers
so you get the real thing not a copy of it

No! There is no reason to add the extra level of indirection for printpnt.

The extra level of indirection was needed for allocate() when a value that is effectively an output from allocate() was declared as an input.

If you have a good reason to pass a function output as an input to that function (there are often such good reasons) then the way to deal with that in C is to add a level of indirection.

But the apoint* is just an input to printpnt(). Adding an extra level of indirection there just confuses things.

smeezekitty 10-25-2009 03:39 PM

Quote:

Originally Posted by johnsfine (Post 3732108)
But the problem in the original code just calls out for the C++ feature of pass by reference.

In C you can get the semantic equivalent of pass by reference (using uglier syntax) with the method you showed: Add an extra level of indirection.
k
But in this example in C, that obscures the function and there was a simpler solution.

The apoint* is conceptually the return value of the allocate function. There are many times in C where it is appropriate to implement a conceptual return value by passing a pointer in rather than passing the value out. But in simple cases like this one, a conceptual return value is best implemented as an actual return value.

Instead of
Code:

void allocate (struct apoint **point_pp);
use
Code:

struct apoint *allocate (void);
then
Code:

struct apoint *allocate (void) {
    struct apoint *result = (struct apoint *) malloc (sizeof (struct apoint));
    result->x = 10;
    result->y = 35;
    return result;
}

Instead of
Code:

  allocate (&point1_p);
use
Code:

  point1_p = allocate();


No! There is no reason to add the extra level of indirection for printpnt.

The extra level of indirection was needed for allocate() when a value that is effectively an output from allocate() was declared as an input.

If you have a good reason to pass a function output as an input to that function (there are often such good reasons) then the way to deal with that in C is to add a level of indirection.

But the apoint* is just an input to printpnt(). Adding an extra level of indirection there just confuses things.

LOL i think you got me and the OP confused.

johnsfine 10-25-2009 03:43 PM

Quote:

Originally Posted by smeezekitty (Post 3732118)
LOL i think you got me and the OP confused.

No, not this time. I do make such mistakes (focus on the content of a post when I should have paid more attention to who posted it). But this time I did notice who posted it.

I posted a correction to your code mainly to keep the OP from being confused by your suggestion. But maybe you can also learn something here.

vasmakk 10-25-2009 03:46 PM

Quote:

Originally Posted by smeezekitty (Post 3732118)
LOL i think you got me and the OP confused.

Hi! not confused, on the contrary ...
I prefer smeezekitty's solution.
the struct apoint* allocate() solution applies in this simple example but not in the application I write, where functions have to return multiple pointer values...

Vas

johnsfine 10-25-2009 03:57 PM

Quote:

Originally Posted by vasmakk (Post 3732128)
I prefer smeezekitty's solution.
the struct apoint* allocate() solution applies in this simple example but not in the application I write, where functions have to return multiple pointer values.

Notice I qualified my comments on Paulsm4's suggestion twice with statements like
Quote:

There are many times in C where it is appropriate to implement a conceptual return value by passing a pointer in rather than passing the value out.
I anticipated that the solution I suggested for this simple case could not replace Paulsm4's suggestion in more complicated cases.

I still think it is better to use straight forward code in the simple case and save the more complicated solutions for more complicated problems. But if you want to practice the complicated solution on a simple problem, that's your choice.

I hope you understand that there is an additional flaw in Smeezkitty's expansion of Paulsm4's solution. If a value is just an input, not one of multiple return values, not even a single return value, adding the extra layer of indirection just adds overhead and confusion.

paulsm4 10-25-2009 07:42 PM

Hi, vasmakk -

Gentle suggestion - when you hear people babbling subjective nonsense about "straight forward code" and "uglier syntax" - run!:)

But to go back to your original question:
Quote:

I want to allocate memory from inside a function A() and use this memory from another function B(). The whole process should be controlled from main...

Unfortunately all malloc() examples I have seen so far use it inside main()
The answer to this question (all irrelevant issues of "style" aside) is simply:
Quote:

you need to use a pointer to a pointer (**p)
Q: Do you understand why?

Q: Why does passing "**p" as an argument (my reply) do the same thing as returning "*p" as a "return" value (johnsfine's suggestion)?

Q: What would happen if you wanted to allocate memory for TWO (or three, or more) structs, instead of just one?

I think the main point is to understand "pointer", "address", and "pointer to pointer".

And again, if this were C++ ... then your "struct" would be a "class", your "allocate()" would be a "constructor" ... and we probably wouldn't even be having this conversation :)

Anyway - I hope this discussion was useful for you.

IMHO .. PSM


All times are GMT -5. The time now is 04:17 AM.