Passing struct to function call doesn't work - c

Since C does not support pass by reference, and I'm developing something that cannot use heap memory, how can I make this work? I want the function call set_var_name to actually change the variables global_log instead of just a local copy. Thanks
#include <stdio.h>
struct Record
{
char type[1];
char var_name[1014];
void* var_address;
char is_out_dated[1];
};
struct Global_Log
{
struct Record records[1024];
int next_slot;
};
void set_var_name(struct Global_Log global_log, int next_slot, char* data, int size)
{
for(int i = 0 ; i < size; i++)
global_log.records[0].var_name[i] = data[i];
printf("%s\n",global_log.records[0].var_name);//here prints out "hello"
}
int main()
{
struct Global_Log global_log;
char a[6] = "hello";
set_var_name(global_log, 0, a, 6);
printf("%s\n",global_log.records[0].var_name); // here prints out nothing
return 0;
}

It seems that you are working with a copy of the struct instance, instead of a reference. Try passing a pointer of a struct as a parameter, so you can work with a reference of the instance:
void set_var_name(struct Global_Log* global_log, int next_slot, char* data, int size)
Another alternative is using a global variable, since it sounds like there won't be another instance of it.

C is a call-by-value language -- when you call a function, all arguments are passed by value (that is, a copy is made into the callee's scope) and not by reference. So any changes to the arguments in the function only affect the copy in the called function.
If you want to call "by reference", you need to do it explicitly by passing a pointer and dereferencing it in the called function.

Related

Can I pass parameters into a function if I only have a pointer to a function in C?

I have a program, what it does isn't too important, I am mostly curious of the following:
If I have a struct that has pointers to a function, can I pass parameters into the function using that pointer? Here is part of my code
edit: I realized I was a little vague:
So is there anyway to use the variable 'x' of type funcs, to pass parameters into the my_closeit and my_openit using the pointer's initialized by x = {&openit, &closeit}; in the main function? By doing x -> or x. ?
Another Edit:
Would it be x.openit(some pointer, some int); ?
#include<stdio.h>
int my_openit(char* name, int prot);
void my_closeit(void);
typedef struct funcs
{
int (*openit)(char *name, int prot);
void (*closeit)(void);
}funcs;
//I know the first 'funcs' is unnecessary
int main()
{
funcs x = {&my_openit, &my_closeit};
return 0;
}
int my_openit(char* name, int prot)
{
return 0;
}
void my_closeit(void)
{
}
can I pass parameters into the function using that pointer?
Yes, obviously, or it wouldn't be of any use. In your case:
int result = x.openit("something", 123);
Yes, just use function call expression through the pointers:
int r = x.openit("myfile",0);
x.closeit();

C - warning: unused variable

I have the following code below in a function.
char * stringFiveds = strtok(stringFive[3], "ds");
When I compile i get the warning unused variable.
I don't plan on using srtingFiveds in this function. I want to use it in main(). I have two parts to this question.
How to solve this warning if I don't want to use the stringFiveds in this function.
How do I make it accessible in other functions so i can use it in other function i will create.
I'm new to this, can you please be as detailed as possible.
If you don't want to use stringFiveds in the function, you can delete that variable declaration because you don't need it.
If you want to make it accessible to other functions, you can declare it as a global variable, or pass it as an argument to your other functions.
So instead of
char * stringFiveds = strtok(stringFive[3], "ds");
you can have just
strtok(stringFive[3], "ds");
If you want to declare stringFiveds as a global variable, just declare it outside of a function:
#include <stdio.h>
char * stringFiveds; // declare outside of function
void foo() {
// you can access stringFiveds here
}
int main() {
// you can also access stringFiveds here
}
If you want to pass stringFiveds as a function argument:
#include <stdio.h>
// declare outside of function
void foo(char * stringFiveds) {
}
int main() {
char * stringFiveds;
foo(stringFiveds);
}
If you do not plan to use a variable in a function, do not make a variable. If you make a variable simply for the side effects of calling a function, you could drop the assignment: C lets you call a function that returns a value as if it were a "procedure" - i.e. a void function.
Another alternative is declaring the variable in the global scope. If you choose this route, consider making the variable static to keep it within the scope of its translation unit. You could also make the variable global, but that is usually not a good option, because it exposes your data beyond the bounds where it is useful.
If you plan to pass it to another function, that would count as "using the variable", resolving the "unused variable" warning.
Note: in case you are curious on how to silence this warning anyway, a common trick is to cast your variable to void.
Well, you could do the gross thing and make it a global variable (i.e. declare is outside of your function).
But that really isn't a great solution. That breaks data encapsulation by giving everything in your .c file access to that variable, whether they need to know about it or not.
A better solution would be to pass in to your functions as a parameter where you need it.
For example:
function foo(char* stringFiveDs) { // use stringFiveDs here }
Or, you could pass in stringFive and declare stringFiveDs in the functions that you need it. So something like:
function bar(const char* stringFive) {
char* stringFiveDs = strtok(stringFive[3], "ds");
...
}
sample code
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char **func(const char *str, const char *delim){
char *strwk = strdup(str);
char **strs = malloc(sizeof(char*));
int count = 0;
char *p;
for(p=strtok(strwk, delim); p != NULL ; p=strtok(NULL, delim)){
strs[count++] = strdup(p);//cutting string copy into
strs = realloc(strs, (count+1)*sizeof(char*));//+1 : Also, reserved for NULL
}
strs[count] = NULL;//end mark
free(strwk);
return strs;
}
void func_d(char **ss){
char **sp = ss;
while(*sp)
free(*sp++);
free(ss);
}
int main(void){
char *stringFive[5] = {
"", "16X16", "1,2,3", "123d45s678", "last,,end"
};
char **stringFiveds = func(stringFive[3], "ds");
int i;
for(i=0; stringFiveds[i] != NULL; ++i)
printf("%s\n", stringFiveds[i]);
func_d(stringFiveds);
return 0;
}

Passing pointers to arrays to functions

I am storing my information in an array of pointers to structs. In other words, each element of the array is a pointer to a linked list.
I don't know how long the array should be, so instead of initializing the array in my main() function, I instead intialize the double pointer
struct graph** graph_array;
Then once I obtain the length of the array, I try to initialize each element of graph_array using a function GraphInitialize:
int GraphInitialize(struct graph* *graph_array,int vertices)
{
struct graph* graph_array2[vertices+1];
graph_array = graph_array2;
int i;
for (i=0;i<vertices+1;i++)
{
graph_array[i] = NULL;
}
return 0;
}
But for some reason this is not returning the updated graph_array to main(). Basically, this function is updating graph_array locally, and no change is being made. As a result, any time I try to access an element of graph_array it seg faults because it is not initialized. What am I doing wrong?
Edit: Following the convo with Tom Ahh I should add something else that makes this more confusing.
I don't call GraphIntialize directly from main(). Instead, I call getdata() from main, and pass a pointer to graph_array to getdata as shown below.
getdata(argc, argv, vertpt, edgept, &graph_array)
int getdata(int argc, char *argv[], int *verts, int *edges, struct graph* **graph_array)
Then getdata gets the number of vertices from my input file, and uses that to call GraphInitialize:
if ((GraphInitialize(&graph_array, *verts)) == -1)
{
printf("GraphCreate failed");
return 0;
}
This results in an error: "expected 'struct graph 3ASTERISKS' but argument is of type 'struct graph 4ASTERISKS'.
When you assign something to graph_array, you simply assign it to its local copy. The changes made to it in the function will not be see-able by the caller. You need to pass it by pointer value to be able to change its value. Change your function prototype to int GraphInitialize(struct graph ***graph_array,int vertices) and when you call it, use GraphInitialize(&graph_array, 42).
Second problem in your code is when you create graph_array2, you declare it to be local to your GraphInitialize() function. Thus, when exiting your function, graph_array2 is destroyed, even if you assigned it to *graph_array. (the star dereferences the pointer to assign it to the value it points to).
change your assignation to *graph_array = malloc(sizeof(*graph_array) * vertices); and you should be fine.
Memory is divided into two parts, the stack and the heap. Malloc will give you back a chunk of memory from the heap, which lives on between functions, but must be freed. Thus your program must be careful to keep track of the malloced() memory and call free() on it.
Declaring a variable graph_array2[vertices+1] allocates a local variable on the stack. When the function returns the stack pointer is popped "freeing" the memory allocated in the function call. You don't have to manage the memory manually, but when the function call is over it no longer exists.
See here for some discussion of the two allocation styles:
http://www.ucosoft.com/stack-vs-heap.html
You're using C99-style local array allocation. The array disappears when the function returns. Instead you need to use malloc() to allocate memory that will persist after the function. You can use typedefs to make your code more readable:
typedef struct graph_node_s { // linked list nodes
struct graph_node_s *next;
...
} GRAPH_NODE;
typedef GRAPH_NODE *NODE_REF; // reference to node
typedef NODE_REF *GRAPH; // var length array of reference to node
GRAPH AllocateGraph(int n_vertices)
{
int i;
GRAPH g;
g = malloc(n_vertices * sizeof(NODE_REF));
if (!g)
return NULL;
for (i = 0; i < n_vertices; i++)
g[i] = NULL;
return g;
}
You have two problems.
First, graph_array2 has auto extent, meaning that it only exists within its enclosing scope, which is the body of the GraphInitialize function; once the function exits, that memory is released, and graph_array is no longer pointing anywhere meaningful.
Second, any changes to the parameter graph_array are local to the function; the changes won't be reflected in the caller. Remember, all parameters are passed by value; if you pass a pointer to a function, and you want the value of the pointer to be modified by the function, you must pass a pointer to the pointer, like so:
void foo(int **p)
{
*p = some_new_pointer_value();
return;
}
int main(void)
{
int *ptr = NULL;
foo(&ptr);
...
}
If you intend for InitializeGraph to allocate the memory for your array, you'll need to do something like this:
int InitializeGraph(struct graph ***graph_array, int vertices)
{
*graph_array = malloc(sizeof **graph_array * vertices);
if (*graph_array)
{
int i;
for (i = 0; i < vertices; i++)
{
(*graph_array}[i] = NULL; // parentheses matter here!
}
}
else
{
return -1;
}
return 0;
}
int main(void)
{
int v;
struct graph **arr;
...
if (GraphInitialize(&arr, v) == 0)
{
// array has been allocated and initialized.
}
...
}
Postfix operators like [] have higher precedence than unary operators like *, so the expression *arr[i] is interpreted as *(arr[i]); we're dereferencing the i'th element of the array. In GraphInitialize, we need to dereference graph_array before subscripting (graph_array isn't an array, it points to an array), so we need to write (*graph_array)[i].

C Function implementation - with Pointer vs without Pointer

I've just started to work with C, and never had to deal with pointers in previous languages I used, so I was wondering what method is better if just modifying a string.
pointerstring vs normal.
Also if you want to provide more information about when to use pointers that would be great. I was shocked when I found out that the function "normal" would even modify the string passed, and update in the main function without a return value.
#include <stdio.h>
void pointerstring(char *s);
void normal(char s[]);
int main() {
char string[20];
pointerstring(string);
printf("\nPointer: %s\n",string);
normal(string);
printf("Normal: %s\n",string);
}
void pointerstring(char *s) {
sprintf(s,"Hello");
}
void normal(char s[]) {
sprintf(s,"World");
}
Output:
Pointer: Hello
Normal: World
In a function declaration, char [] and char * are equivalent. Function parameters with outer-level array type are transformed to the equivalent pointer type; this affects calling code and the function body itself.
Because of this, it's better to use the char * syntax as otherwise you could be confused and attempt e.g. to take the sizeof of an outer-level fixed-length array type parameter:
void foo(char s[10]) {
printf("%z\n", sizeof(s)); // prints 4 (or 8), not 10
}
When you pass a parameter declared as a pointer to a function (and the pointer parameter is not declared const), you are explicitly giving the function permission to modify the object or array the pointer points to.
One of the problems in C is that arrays are second-class citizens. In almost all useful circumstances, among them when passing them to a function, arrays decay to pointers (thereby losing their size information).
Therefore, it makes no difference whether you take an array as T* arg or T arg[] — the latter is a mere synonym for the former. Both are pointers to the first character of the string variable defined in main(), so both have access to the original data and can modify it.
Note: C always passes arguments per copy. This is also true in this case. However, when you pass a pointer (or an array decaying to a pointer), what is copied is the address, so that the object referred to is accessible through two different copies of its address.
With pointer Vs Without pointer
1) We can directly pass a local variable reference(address) to the new function to process and update the values, instead of sending the values to the function and returning the values from the function.
With pointers
...
int a = 10;
func(&a);
...
void func(int *x);
{
//do something with the value *x(10)
*x = 5;
}
Without pointers
...
int a = 10;
a = func(a);
...
int func(int x);
{
//do something with the value x(10)
x = 5;
return x;
}
2) Global or static variable has life time scope and local variable has scope only to a function. If we want to create a user defined scope variable means pointer is requried. That means if we want to create a variable which should have scope in some n number of functions means, create a dynamic memory for that variable in first function and pass it to all the function, finally free the memory in nth function.
3) If we want to keep member function also in sturucture along with member variables then we can go for function pointers.
struct data;
struct data
{
int no1, no2, ans;
void (*pfAdd)(struct data*);
void (*pfSub)(struct data*);
void (*pfMul)(struct data*);
void (*pfDiv)(struct data*);
};
void add(struct data* x)
{
x.ans = x.no1, x.no2;
}
...
struct data a;
a.no1 = 10;
a.no1 = 5;
a.pfAdd = add;
...
a.pfAdd(&a);
printf("Addition is %d\n", a.ans);
...
4) Consider a structure data which size s is very big. If we want to send a variable of this structure to another function better to send as reference. Because this will reduce the activation record(in stack) size created for the new function.
With Pointers - It will requires only 4bytes (in 32 bit m/c) or 8 bytes (in 64 bit m/c) in activation record(in stack) of function func
...
struct data a;
func(&a);
...
Without Pointers - It will requires s bytes in activation record(in stack) of function func. Conside the s is sizeof(struct data) which is very big value.
...
struct data a;
func(a);
...
5) We can change a value of a constant variable with pointers.
...
const int a = 10;
int *p = NULL;
p = (int *)&a;
*p = 5;
printf("%d", a); //This will print 5
...
in addition to the other answers, my comment about "string"-manipulating functions (string = zero terminated char array): always return the string parameter as a return value.
So you can use the function procedural or functional, like in printf("Dear %s, ", normal(buf));

Getting error when modifying MyType constructed using typedef in C

I create a type and try to change the int value in it.
But it keeps printing 240.
I don't know why, can anyone help me?
Here is my code:
typedef struct{
int i;
}MyType;
do(MyType mt, int ii){
mt.i = ii;
}
int main(int argc, char ** argv){
MyType mt;
do(mt, 5);
print("%d\n", mt.i);
}
Passing mt by value to function do(). Any changes made will be local to the function. Pass the address of mt:
void do_func(MtType* mt, int ii){
mt->i = ii;
}
MyType mt;
do_func(&mt, 5);
So first, your do function has some problems. You have failed to specify a return type, so int is assumed (pre-C99), but I see no reason to not just specify it. Second, do is a reserved keyword in C.
You are passing your struct by value, so a copy is made, passed to your do function, and that is modified. Everything is passed by value in C, period. Your mt variable declared in main is never touched.
Take a MyType* in your code if you need to modify one or more of its member variables, take a MyType** if you need to allocate memory for the structure itself (i.e., initialize a pointer).
// pass a pointer to the function to allow
// for changes to the member variables to be
// visible to callers of your code.
void init_mytype(MyType *mt, int ii){
if(mt)
mt->i = ii;
}
MyType mt;
init_mytype(&mt, 1);
// pass a pointer to pointer to initialize memory
// for the structure and return a valid pointer.
// remember, everything is passed by value (copy)
void init_mytype(MyType **mt, int ii) {
if(mt) {
*mt = malloc(sizeof(MyType));
if(*mt)
(*mt)->i = ii;
}
}
MyType *pmt;
init_mytype(&pmt, 1);

Resources