Reputation: 11
I am creating a function for a code and the code uses the function that outputs to a file pointer like for example,
number *base6 = intToNumber(50, 6);
Here is the code I have so far:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef struct {
int iNum;
int base;
char* sNum;
} number;
number * intToNumber(int nnum, int nbase) {
number * theNumbers;
//theNumbers= (number*)malloc(10*sizeof(number));
if (theNumbers = NULL) {
printf("\n\nNo\n\n");
exit(1);
}
theNumbers->iNum = nnum;
theNumbers->base = nbase;
}
Upvotes: 1
Views: 60
Reputation: 84561
You are beginning to think along the correct lines, but your handling of allocation for your theNumbers
(you have commented) is just step one. When you allocate theNumbers
, the pointer theNumbers->sNum
is created -- but it is an Uninitialized Pointer that holds an indeterminate address as its value. (e.g. it points nowhere you have any ability to make use of). Think about your struct (typedef
)
typedef struct {
int iNum; /* automatic storage types */
int base;
char *sNum; /* a pointer - hold address to something else */
} number; /* must point to valid memory addr */
When you allocate for one of those, you allocate 2 integer values and one character pointer that have automatic storage type and can be assigned values. While iNum
and base
are integer values and can be assigned immediate values like 50
and 6
, sNum
by contrast is a pointer and can only be assigned a valid memory address where something else is stored.
Normally, to make use of a pointer, you allocate a new block of memory, fill that memory with whatever is needed for the type, and then assign the starting address for that new block of memory to your pointer (sNum
here). So now your pointer will hold the address of (e.g. point to) a valid block of memory containing values usable by that object type. (char*
, a pointer to a char, here)
Your intToNumber
function takes only int nnum
and int nbase
as parameters, so after allocating for your struct
, you can only initialize theNumbers->iNum = nnum;
and theNumbers->base = nbase;
, but have nothing to size or initialize sNum
with (it should therefore be set to NULL
).
So you are close on your intToNumber
, and all you need to do is return the pointer intToNumber
after you have allocated storage for it (because following allocation it has allocated storage type which survives for the life of the program -- or until it is freed), e.g.
number *intToNumber (int nnum, int nbase) {
number *theNumbers;
theNumbers= malloc (sizeof *theNumbers); /* allocate */
if (theNumbers == NULL) { /* validate */
perror ("malloc-theNumbers");
return NULL;
}
theNumbers->iNum = nnum; /* initialize values */
theNumbers->base = nbase;
theNumbers->sNum = NULL;
return theNumbers; /* return pointer */
}
Now what to do about sNum
? Well, it's up to you, but for example, you could create a separate function that takes your allocated struct
and a character string as parameters, allocate for length + 1
bytes to hold the string (plus the nul-terminating character) assigning the starting address for the new bock to sNum
, and then copying the string to the new block of memory, e.g.
/* allocate/set sNum member of n to s */
char *setsNum (number *n, const char *s)
{
if (!n) { /* validate n not NULL, return NULL on failure */
fputs ("error: struct parameter 'n' NULL.\n", stderr);
return NULL;
}
size_t len = strlen (s); /* get length */
n->sNum = malloc (len + 1); /* allocate storage (+1 byte) */
if (!n->sNum) { /* validate allocation */
perror ("malloc-sNum");
return NULL;
}
memcpy (n->sNum, s, len + 1); /* copy s to new block of memory */
return n->sNum; /* return pointer (convenience) */
}
(I suspect you will be filling it with your base6 conversion -- but that is left to you)
Other than freeing the memory when you are done with it, all that remains is a short example showing how to put it altogether. That you can do with something simple like:
int main (void) {
number *mynum = intToNumber (50, 6); /* declare/initialize mynum */
if (!mynum) /* validate succeeded */
return 1;
/* allocate/validate mynum->sNum, copy string */
if (!setsNum (mynum, "created with intToNumber (50, 6)")) {
free (mynum);
return 1;
}
/* output values held in mynum */
printf ("succeeded:\n iNum: %d\n base: %d\n str : %s\n",
mynum->iNum, mynum->base, mynum->sNum);
free (mynum->sNum); /* free allocated string */
free (mynum); /* free struct */
}
Example Use/Output
If you put the example together, you would get:
$ ./bin/struct_alloc_member
succeeded:
iNum: 50
base: 6
str : created with intToNumber (50, 6)
Memory Use/Error Check
In any code you write that dynamically allocates memory, you have 2 responsibilities regarding any block of memory allocated: (1) always preserve a pointer to the starting address for the block of memory so, (2) it can be freed when it is no longer needed.
It is imperative that you use a memory error checking program to insure you do not attempt to access memory or write beyond/outside the bounds of your allocated block, attempt to read or base a conditional jump on an uninitialized value, and finally, to confirm that you free all the memory you have allocated.
For Linux valgrind
is the normal choice. There are similar memory checkers for every platform. They are all simple to use, just run your program through it.
$ valgrind ./bin/struct_alloc_member
==15553== Memcheck, a memory error detector
==15553== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==15553== Using Valgrind-3.12.0 and LibVEX; rerun with -h for copyright info
==15553== Command: ./bin/struct_alloc_member
==15553==
succeeded:
iNum: 50
base: 6
str : created with intToNumber (50, 6)
==15553==
==15553== HEAP SUMMARY:
==15553== in use at exit: 0 bytes in 0 blocks
==15553== total heap usage: 2 allocs, 2 frees, 49 bytes allocated
==15553==
==15553== All heap blocks were freed -- no leaks are possible
==15553==
==15553== For counts of detected and suppressed errors, rerun with: -v
==15553== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
Always confirm that you have freed all memory you have allocated and that there are no memory errors.
The full example used was:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef struct {
int iNum; /* automatic storage types */
int base;
char *sNum; /* a pointer - hold address to something else */
} number; /* must point to valid memory addr */
number *intToNumber (int nnum, int nbase) {
number *theNumbers;
theNumbers= malloc (sizeof *theNumbers); /* allocate */
if (theNumbers == NULL) { /* validate */
perror ("malloc-theNumbers");
return NULL;
}
theNumbers->iNum = nnum; /* initialize values */
theNumbers->base = nbase;
theNumbers->sNum = NULL;
return theNumbers; /* return pointer */
}
/* allocate/set sNum member of n to s */
char *setsNum (number *n, const char *s)
{
if (!n) { /* validate n not NULL, return NULL on failure */
fputs ("error: struct parameter 'n' NULL.\n", stderr);
return NULL;
}
size_t len = strlen (s); /* get length */
n->sNum = malloc (len + 1); /* allocate storage (+1 byte) */
if (!n->sNum) { /* validate allocation */
perror ("malloc-sNum");
return NULL;
}
memcpy (n->sNum, s, len + 1); /* copy s to new block of memory */
return n->sNum; /* return pointer (convenience) */
}
int main (void) {
number *mynum = intToNumber (50, 6); /* declare/initialize mynum */
if (!mynum) /* validate succeeded */
return 1;
/* allocate/validate mynum->sNum, copy string */
if (!setsNum (mynum, "created with intToNumber (50, 6)")) {
free (mynum);
return 1;
}
/* output values held in mynum */
printf ("succeeded:\n iNum: %d\n base: %d\n str : %s\n",
mynum->iNum, mynum->base, mynum->sNum);
free (mynum->sNum); /* free allocated string */
free (mynum); /* free struct */
}
Upvotes: 1
Reputation: 590
Why don't you pass in a pointer to the structure in the function such that the signature looks like void intToNumber(number *n)
? And then you would have the implementation look something like
int main ()
{
number Numbers = {.sNum = malloc (25) };
// Do stuff here...
intToNumber(&Numbers);
// Do some more stuff...
}
Since you are pointing to the variable Numbers
on the stack, you can manipulate those variable in the function intToNumber
and have them available in the rest of the main
function (or in whatever scope you decide to call it).
Upvotes: 0
Reputation: 180201
Supposing that the actual question is exactly what is presented in the title:
How do I return a struct from a function to a struct pointer?
The answer is that although a function can return a struct, it cannot do so to a struct pointer. Under no circumstance can you assign a struct to an object of of any pointer type. You can have a pointer to a struct, and you can have a struct that contains a pointer, but no struct is itself a pointer.
If, on the other hand, the question were about how to return a struct pointer then the answer would be "by using a return
statement", the same way you return a value of any other type. For that to be useful, the pointer you return ought to be a valid one, but that's a separate question.
Upvotes: 0