C programming… Linked List Pointer Iteration - c

Hello I have the following functions defined:
head();
traverse(struct *);
I'm concerned that when iterating through the list it is being modified.
void tail()
{
n3.next = (struct entry*) 0xff;
}
void traverse(struct entry *listPt)
{
while(listPt != (struct entry *) 0xff)
{
printf("%i\n", listPt->value);
listPt = listPt->next;
}
}
Should I use a different algorithm to iterate the list? Is it more beneficial to copy the list?
Is the following expression from the while loop overwritten existing (values) memory?
listPt = listPt->next;

The statement overrides only local variable listPt declared as a function parameter
struct entry *listPt
It does not modify the list itself.
Function parameters are its local variables. The function deals with copies of its arguments. Any changing of a parameter does not influence on the corresponding argument.
Consider
#include <stdio.h>
void func( int *p )
{
int y = 20;
p = &y;
printf( "%d\n", *p ); // prints 20
}
int main( void )
{
int x = 10;
int *px = &x;
printf( "%d\n", *px ); // prints 10;
func( px );
printf( "%d\n", *px ); // prints 10;
}

No this algorithm is ok, you wont modify the list.
If you want to modify you have to set the function header like this void traverse(struct entry * & listPt)

Related

Table of structures (realloc in C)

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;
}

Swapping 2 void pointers addresses

I need to create a swap function that takes 2 addresses as input and swaps them regardless what type they point to. Here's my swap function:
void swap(void* x,void* y){
void* temp=x;
x=y;
y=temp;
}
When I use it with integers it works fine and swaps them properly, but using strings the addresses seems to swap inside the function but when I try to call them from outside the function I notice they didn't change at all.
Here's my full code and the resulting output.
printf("before %s %s\n",(char*)array[i],(char*)array[j] );
swap(array[i], array[j]);
printf("after %s %s\n",(char*)array[i],(char*)array[j] );
I casted everything to string to understand what was wrong with them
void swap(void* x,void* y){
printf(" after IN %s %s\n",(char*)x,(char*)y );
void* temp=x;
x=y;
y=temp;
printf(" after IN %s %s\n",(char*)x,(char*)y );
}
OUTPUT
before fannullone falafel
after IN fannullone falafel
after IN falafel fannullone
after fannullone falafel
To swap two objects in a function you need to pass them to the function by reference.
In C passing by reference means passing objects indirectly through pointers to them. So dereferencing the pointers the function gets a direct access to the original objects and can change them.
So for objects of the type void * the function parameters will have the type void **. The function will look like
void swap( void **x, void **y )
{
void *temp = *x;
*x = *y;
*y = temp;
}
Here is a demonstration program.
#include <stdio.h>
void swap( void **x, void **y )
{
void *temp = *x;
*x = *y;
*y = temp;
}
int main( void )
{
void *s1 = "Hello";
void *s2 = "World";
printf( "s1 = %s, s2 = %s\n", ( char * )s1, ( char * )s2 );
swap( &s1, &s2 );
printf( "s1 = %s, s2 = %s\n", ( char * )s1, ( char * )s2 );
}
The program output is
s1 = Hello, s2 = World
s1 = World, s2 = Hello
It cannot be done with a function because there is no generic pointer to pointer in C. For example the type void** is not compatible with char**. Technically, those pointers could have different representation what would disallow dereferencing after casting or using memcpy().
Therefore, it is better to use a macro:
#define SWAP(a, b) \
do { \
void *tmp = *(a); \
*(a) = *(b); \
*(b) = tmp; \
} while (0)

Why should we use a double pointer when we pass a dynamic array as a parameter to a function?

I am relatively new to programming, and im trying to understand some concepts with pointers. I got it for the most part, and i was looking in dinamic memory allocation, and i understood i need to create a pointer and the malloc function will return the first adress of the allocated space, which we put in the pointer created. That make a lot of sense because thats makes the dinamic vector just like a regular vector, right? Because a static vector also has the name of the vector a pointer to the first element. But why when i try to for example change the size of the vector with realloc in a function i understand i need to use a double pointer as a parameter. Something like this:
void function(int **vector){
*vector=(*int)realloc(*vector, sizeof(int)*n);
}
Can someone explain, thanks!
When a function declared as void function(int *vector) is called, it is passed only the value of an int *—just a pointer to the first element of a vector (an array). If this function is called with function(MyVector), then, inside the function, vector refers only to the copy of the value that is passed. It does not refer to MyVector, and changing vector will not change MyVector.
When a function declared as void function(int **vector) is called, it is passed the value of an int **—a pointer to a pointer to the first element of a vector. If this function is called with function(&MyVector), then, inside the function, vector refers to the copy of the pointer to the pointer. However, since it is a pointer to a pointer, then *vector refers to the pointer to the first element of the array. That is, *vector is not just a copy of the pointer, it is the actual pointer, the MyVector in the caller.
So, in the first function vector = realloc(…); does not change MyVector in the caller. In the second function, *vector = realloc(…); does change MyVector in the caller.
If you have a function like this
void f( T item );
where T is some type specifier and call it like
T object;
f( object );
then the function gets a copy of its argument. You can imagine this the following way
T object;
f( object );
//....
void f( /* T item */ )
{
T item = object;
// ...
}
So changes of the copy within the function dos not influence on the original object passed to the function as an argument.
To change the original object you have to pass it by reference. For example
void f( T *item )
{
*item = new_value;
//...
}
//...
T object;
f( &object );
If you have an object of the type int that you want to change within a function then just substitute the type specifier T for the type int and you will get.
void f( int *item )
{
*item = new_value;
//...
}
//...
int object;
f( &object );
If the object has the type int * then substitute T for int * and you will get
void f( int **item )
{
*item = new_value;
//...
}
//...
int *object;
f( &object );
Here is a demonstrative program.
#include <stdio.h>
#include <stdlib.h>
void f( int *x )
{
*x = 20;
}
void g( int **p )
{
*p = malloc( sizeof( int ) );
**p = 30;
}
int main(void)
{
int x = 10;
printf( "x = %d\n", x );
f( &x );
printf( "x = %d\n", x );
int *px = &x;
printf( "*px = %d\n", *px );
g( &px );
printf( "*px = %d\n", *px );
free( px );
return 0;
}
Its output is
x = 10
x = 20
*px = 20
*px = 30

Set structure pointer to NULL in function in C

I try to free structure pointer using function and then check for NULL. It doesn't work!
typedef struct{
int * num;
} D;
void freeD(D * a){
free(a->num);
free(a);
a=NULL;
}
int main(){
D * smth = malloc(sizeof(D));
smth->num = malloc(sizeof(int)*2);
freeD(smth);
if(smth==NULL){
printf("It's NULL");
}
}
You have to pass the pointer by reference that is by using pointer to the pointer.
For example
void freeD(D ** a){
free( ( *a )->num);
free(*a);
*a=NULL;
}
//...
freeD( &smth );
Here you have passed the parameter by value instead of passing the parameter by reference.
What have you done
Let us assume smth=0x0030;
where address(smth) = 0x0100 && value(smth) = 0x0030.
So when you do freeD(smth), you are actually passing value(smth) which is 0x0030. Meanwhile, in the function freeD():-
address(a) = 0x0200 && value(a) = 0x0030
So when you do set
a = NULL
you are actually setting the value(a) = NULL where address(a)=0x0200; instead of doing it at the address=0x0100;
What you should have done
void freeD(D ** a){
free((*a)->num);
free(*a);
*a=NULL;
}
int main(){
//...
freeD(&smth);
//...
}

Local pointer to a global function

I want to use a local pointer to point to a global string. The pointer is a local pointer and the string is global. When I run this code passing the local pointer to the function "myfun" the pointer is not changed, i.e., its pointing address does not change. The values printed are "NULL".
Can someone tell me why this does not work on gcc?
#include <stdio.h>
char *str[] = { "String #1", "Another string" };
void myfun( void * p, int i )
{
p = ( void * ) &str[ i ][ 0 ];
}
int main( void )
{
void * ptr1, * ptr2;
myfun( ptr1, 0 );
myfun( ptr2, 1 );
printf( "%s\n%s\n", ptr1, ptr2 );
}
You are passing a pointer, by value, to myfun. The value you assign to p in myfun is therefore not returned to the caller. You need to pass a pointer to the pointer:
void myfun( void ** p, int i )
{
*p = ( void * ) &str[ i ][ 0 ];
}
And call it like this:
myfun( &ptr1, 0 );
In fact you can write myfun like this:
void myfun( void ** p, int i )
{
*p = str[i];
}
And in fact it would be simplest just to return the void* as the functions return value:
void *myfun( int i )
{
return str[i];
}
Fundamentally, your question isn't any different from -
void func(int i)
{
i = 2;
}
int main()
{
int i = 0;
printf("i = %d\n", i);
func(i);
printf("i = %d\n", i); /* Wonder why it doesn't output i = 2? */
}
In your code, you pass ptr1 (and ptr2) arguments by value, change the value of the parameter p that you receive, and expect this change to be reflected on the argument that you passed. That, that ptr1 and ptr2 are pointers doesn't change the fact that you are still passing by value.
Also, IANAL (i.e., I hope a language lawyer corrects me if I am wrong), but I think you are potentially headed for trouble by sending pointer to void variables as arguments to printf.

Resources