I want to call a function that will initialize an array and an integer variable and send them back from the function to the main program. I want to do that without even declaring those variables in the main program, but if I have to, then without initializing them in the main program. Is that even possible?
My C is rusty (haven't written any in ~17 years), but you'd probably do it with a struct (or a typedef'd struct) that the function returns:
struct foo {
int i;
int * a;
};
struct foo * myFunction() {
struct foo * pf;
pf = malloc(sizeof(*pf));
pf->i = 0; // Or whatever value it should have
pf->a = malloc(100 * sizeof(*pf->a)); // Or whatever size it should have
// ...fill in pf->a here...
return pf;
}
...or something like that. Usage:
struct foo * pf = myFunction();
You'd probably want a function to release it, too, e.g.:
struct foo * releaseFoo(struct foo * pf) {
if (pf != NULL) {
if (pf->a != NULL) {
free(pf->a);
pf->a = NULL;
}
free(pf);
}
return NULL;
}
Usage:
pf = releaseFoo(pf);
(You don't need the return type and such, but it's really handy to have it so you can assign to the pointer you're freeing, so you don't have dangling pointers to freed memory.)
Just a simple example for your requirement.
void func(int *a)
{
int i;
for(i=0;i<10;i++)
a[i] = i;
return;
}
int main()
{
int a[10],i;
func(a);
for(i=0;i<10;i++)
printf("%d",a[i]);
return 0;
}
Or
int *func()
{
int i;
int *p = malloc(sizeof(int) *10);
for(i=0;i<10;i++)
p[i] = i;
return p;
}
int main()
{
int i;
int *a = func();
for(i=0;i<10;i++)
printf("%d",a[i]);
return 0;
}
Related
i am trying to write a code in C but i am having some problems with realloc. I had to write a code that will create a stack, and will add to it (dodaj_do_stosu), reamove from it (usun_ze_stosu) and will look at the top thing that is on this stack. I have problem with compiling(it does work for first two words but then it returns (0xC0000374)).
I think i am usining the realloc wrong and the sizeof my structure. If someone could look at my code (especially at the function (dodaj_do_stosu) and tell me what am i doing wrong thx. My code look like this:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
typedef struct {
int n;
char *nazwa;
}element_t;
typedef struct {
int rozmiar;
element_t **tablica;
}stos_t;
void top_of_stack(stos_t *s){
printf("ostatni element stosu:rozmiar = %d nazwa=%s, n=%d\n", s->rozmiar, s->tablica[s->rozmiar]->nazwa, s->tablica[s->rozmiar]->n);
}
void init(stos_t *s)
{
s->rozmiar=0;
s->tablica=malloc(0);
}
void dodaj_do_stosu(stos_t *s, int n, char *name)
{
s->tablica = realloc(s->tablica, (s->rozmiar + 1) * sizeof(s->tablica));
s->tablica[s->rozmiar]->nazwa = name;
s->tablica[s->rozmiar]->n = n;
printf("rozmiar=%d, n=%d , nazwa=%s\n",s->rozmiar, s->tablica[s->rozmiar]->n, s->tablica[s->rozmiar]->nazwa);
s->rozmiar++;
}
void usun_ze_stosu(stos_t *s)
{
s->tablica = realloc(s->tablica, (s->rozmiar - 1) * sizeof(s->tablica[0]));
s->rozmiar--;
}
void rm(stos_t s)
{
free(s.tablica);
}
int main(int argc, char **argv)
{
stos_t s;
init(&s);
int i;
srand(time(0));
if (argc>1)
for(i=1;i<argc;i++){
printf("%s\n", argv[i]);
dodaj_do_stosu(&s, rand() % 10, argv[i]);
}
for(i=0;i<argc-1;i++){
//printf("i=%d, n=%d, nazwa=%s\n",i, s.tablica[i].n, s.tablica[i].nazwa);
}
//top_of_stack(&s);
//usun_ze_stosu(&s);
//top_of_stack(&s);
rm(s);
return 0;
}
A big part of your problem is that tablica is an array of pointers, but you never initialize the pointers themselves.
The dodaj_do_stosu function reallocates the array, but doesn't create the element_t objects. Therefore any dereference of e.g. s->tablica[s->rozmiar] will lead to undefined behavior.
There are two possible solutions:
Allocate a new element_t structure:
s->tablica[s->rozmiar] = malloc(sizeof(element_t));
before you initialize the element_t structure members.
Make tablica an array of structure objects instead of pointers:
element_t *tablica; // tablica is an array of objects, not an array of pointers
I recommend solution 2.
At least the function dodaj_do_stosu is wrong. The data member tablica is declared like
element_t **tablica;
So the expression s->tablica[s->rozmiar] has the type element_t * and an indeterminate value. Thus dereferencing the pointer expression for example like
s->tablica[s->rozmiar]->nazwa
invokes undefined behavior.
You have to allocate memory for objects of the structure type element_t not for pointers of the type element_t *.
So you need to declare the data member like
element_t *tablica;
and within the function to write
s->tablica = realloc(s->tablica, (s->rozmiar + 1) * sizeof( *s->tablica));
Also it is safer to use an intermediate pointer for calls of realloc.
The function can look the following way
int dodaj_do_stosu( stos_t *s, int n, char *name )
{
element_t *tmp = realloc( s->tablica, ( s->rozmiar + 1 ) * sizeof( *s->tablica ) );
int success = tmp != NULL;
if ( success )
{
s->tablica = tmp;
s->tablica[s->rozmiar]->nazwa = name;
s->tablica[s->rozmiar]->n = n;
printf("rozmiar=%d, n=%d , nazwa=%s\n", s->rozmiar, s->tablica[s->rozmiar]->n, s->tablica[s->rozmiar]->nazwa );
++s->rozmiar;
}
return success;
}
Consequently the function should be redefined at least the following way. As is it can for example invoke undefined behavior when s->rozmiar is equal to 0.
int usun_ze_stosu( stos_t *s )
{
int success = s->rozmiar != 0;
if ( success )
{
element_t *tmp = realloc( s->tablica, ( s->rozmiar - 1 ) * sizeof( *s->tablica ) );
success = tmp != NULL;
if ( success )
{
s->tablica = tmp;
--s->rozmiar;
}
}
return success;
}
Also within the function init it will be much better ro write
void init(stos_t *s)
{
s->rozmiar=0;
s->tablica = NULL;
}
Another problem is the function rm
void rm(stos_t s)
{
free(s.tablica);
}
You should pass the original object through a pointer to it and within the function to write
void rm(stos_t *s)
{
free( s->tablica );
s->tablica = NULL;
s->rozmiar = 0;
}
I was reading a page of "Understanding and Using C Pointers" when this function appeared:
void safeFree(void **pp) {
if (pp != NULL && *pp!= NULL) {
free(*pp);
*pp = NULL;
}
}
and an example code from it:
int main(int argc, char **argv) {
int* pi = (int*)malloc(sizeof(int));
*pi = 5;
safeFree((void**)&pi);
return EXIT_SUCCESS;
}
My point is, checking pp != NULL in the if condition in this scenario is useless, right? Because according to the way this code is written this condition will never be false. But there is a scenario in which this condition will be true, assuming **pp expects a memory address and (assumed by me) a memory address of a variable can never be NULL? Or did the writer did that checkup in case someone did something like this?
int main(int argc, char **argv) {
int **pi = NULL;
safeFree((void**)pi);
return EXIT_SUCCESS;
}
Thanks.
Having said that safeFree is just confusing and does not provide safety. Because the code assumes that the API user will always pass a particularly constructed pointer. Consider these:
tricky 0 (screws up a)
#include <stdio.h>
#include <stdlib.h>
void safeFree(void **pp) {
if (pp != NULL && *pp!= NULL) {
free(*pp);
*pp = NULL;
}
}
int main() {
int *a;
int **p;
a = malloc(5 * sizeof(int));
p = malloc(1 * sizeof(a));
a[0] = 10;
p[0] = a;
fprintf(stderr, "%d\n", a[0]);
safeFree((void **)p); /* grrrr */
fprintf(stderr, "%d\n", a[0]);
}
tricky 1 (crashes)
int main() {
int a[] = { };
int b[] = { 1 };
int c[] = { 2 };
int **p = malloc(3 * sizeof(int *));
p[0] = a, p[1] = b, p[2] = c;
safeFree((void **)p); /* grrrr */
}
The function checks for NULL mainly for cases like your second. If an actual variable address is passed that check will not fail but never trust your caller to be sane.
I have just started learning about pointers and how they can be passed to functions as arguments, and how they can have the same effects as arrays in functions.
And now I am curious how to instead, return pointers in a function, or if this is possible? That is my question. I would like to know how to return a general pointer.
yes it is possible to return pointer from functions.
int * FunctionReturningAnInteger()
{
// this function returns integer pointer;
int *integerPointer = malloc(sizeof *integerPointer); /* memory allocation */
*integerPointer = 12;
return integerPointer;
}
char * FunctionReturningACharacter()
{
// this function returns integer pointer;
char*charPointer = malloc(sizeof *charPointer ); /* memory allocation */
*charPointer = 'a';
return charPointer ;
}
hope it's clear now to you
prototype for returning pointer
int* func();
float* func();
char* func();
Just define them whatever you want.
As I can deduce from the question, you are trying to get a tutorial from here which is obviously not possible. You have to try yourself the examples and most importantly, you have to understand the concept of returning a pointer from a function.
You can start with these questions::
When is returning pointer from a function good?
What do these pointers actually return ?
How to collect the returned pointer from a function ?
For instance you can compile and debug this example,
/* function to generate and retrun random numbers. */
int * getRandom( )
{
static int r[10];
int i;
/* set the seed */
srand( (unsigned)time( NULL ) );
for ( i = 0; i < 10; ++i)
{
r[i] = rand();
printf("%d\n", r[i] );
}
return r;
}
/* main function to call above defined function */
int main ()
{
/* a pointer to an int */
int *p;
int i;
p = getRandom();
for ( i = 0; i < 10; i++ )
{
printf("*(p + [%d]) : %d\n", i, *(p + i) );
}
return 0;
}
int i;
/* returns a pointer to an int */
int *function1()
{
return &i;
}
char c;
/* returns a pointer to a char */
char *function2()
{
return &c;
}
I have a struct that contains an int pointer
struct mystruct {
int *myarray;
};
I want to make a function that mallocates for mystruct and also initializes myarray. But, when I try to access an element of myarray, I get a seg. fault
void myfunction(struct mystruct *s, int len) {
s = malloc(sizeof(mystruct));
s->myarray = malloc(sizeof(int) * len);
int i;
for (i=0; i<len; i++) {
s->myarray[i] = 1;
}
}
main() {
struct mystruct *m;
myfunction(m, 10);
printf("%d", m->myarray[2]); ////produces a segfault
}
However, mallocating m in main seemed to solve my problem.
Revised Code:
void myfunction(struct mystruct *s, int len) {
int i;
s->myarray = malloc(sizeof(int) * len);
for (i=0; i<len; i++) {
s->myarray[i] = 1;
}
}
main() {
struct mystruct *m = malloc(sizeof(mystruct)); //this was in myfunction
myfunction(m,10);
printf("%d", m->myarray[2]); ///Prints out 1 like I wanted
}
Why did the 2nd attempt work and why did the first attempt not work?
The problem is that the first version assigns the result of malloc to a parameter, which effectively a local variable; the assigned value vanishes when the function returns
So, an alternative is to pass to the function a pointer to the location where you want to store the result of malloc. This is named pps in the code below. At the beginning of the function we do the malloc and assign to a local variable s. Then we do things with s. Then, just before the function exits, we assign the local variable s to the location pointed to by the parameter pps. *pps = s;
void myfunction(struct mystruct **pps, int len) { // note double "**"
struct mystruct *s = malloc(sizeof(mystruct);
s->myarray = malloc(sizeof(int) * len);
int i;
for (i=0; i<len; i++) {
s->myarray[i] = 1;
}
*pps = s; // now pass the alloc'ed struct back to main through parameter pps
}
Now, back in main we pass &m to the function. This passes a pointer to m to the function. When the function returns, the local variable m holds the value returned by malloc and passed through the parameter pps.
main() {
struct mystruct *m;
myfunction(&m, 10); // PASS THE ADDRESS OF m, not m itself
printf("%d", m->myarray[2]); // this will work now
}
I know there are a lot of double pointer questions, but I couldn't find one that pertained to starting an array.
In the code below, I can set pointers in main by ptrs[0] = &array[0];, but the code halts when enqueue() calls *queue[i] = p;. Why is that? I don't know if it matters, but ptrs[] is not initialized.
#define QUEUE_LEN 5
int *ptrs[5];
int array[5] = {1,2,3,4,5};
void enqueue(int *p, int **queue) {
int i = 0;
int *tmp;
// Find correct slot
while (*queue && *queue[i] >= *p) {
i++;
}
// Error no free slots
if (i == QUEUE_LEN) {
printf("No free slots.\r\n");
return;
}
// Insert process
if (!*queue) {
*queue[i] = p;
return;
}
else {
tmp = *queue[i];
*queue[i] = p;
}
// Increment the other processes
return;
}
int main(int argc, char** argv) {
int i;
for (i=0; i<5; i++) {
enqueue(&array[i], ptrs);
}
for (i=0; i<QUEUE_LEN; i++)
printf("%d\n", *(ptrs[i]));
return 0;
}
After first loop, i will remain zero. Here:
if (!*queue) {
*queue[i] = p;
return;
}
You check, that *queue is 0 and dereference it as well. It is UB.
PS. Btw, this:
*queue[i] = p;
Will not compiles, since *queue[i] has type int, but p has type int*.
// Find correct slot
while (*queue && *queue[i] >= *p) {
i++;
}
This will access some random memory address taken from uninitialized ptrs value.
Your check for *queue != 0 is not enough, you need to initialize array with zeores as:
int *ptrs[5] = {0};
And you still need to allocate memory you are attempting to write later when inserting.