structure pointer

Thread Starter

Dadu@

Joined Feb 4, 2022
145
I am badely confused how pointer to struct pass to function including dynamic memory allocation in function

This is my program and I intentionally didn't created structured member and written function. I want some experience persome to create structured and function need to test two lines written releated function in main function.

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

struct point
{

};


int main ()
{
    struct point *P = NULL;
    
    fun1(P);  // passing pointer to structure by value
    fun2(&P); // passing pointer to structure by address

    return 0;
}
.
I know pointer, function, dynamic memory allocation, and structure. I am having hard time understanding how to pass pointer to struct to function.
 

Thread Starter

Dadu@

Joined Feb 4, 2022
145
What are you having trouble with? You seem to know how to pass it two ways. What is the problem?

Bob
I want to create structure and two functions for these two lines to understand concept of passing pointer to struct to function. I have a problem especially when dynamic memory is allocated in functions

C:
fun1(P);  // passing pointer to structure by value
fun2(&P); // passing pointer to structure by address
I hope you understand my question now
 

nsaspook

Joined Aug 27, 2009
10,698
I want to create structure and two functions for these two lines to understand concept of passing pointer to struct to function. I have a problem especially when dynamic memory is allocated in functions

C:
fun1(P);  // passing pointer to structure by value
fun2(&P); // passing pointer to structure by address
I hope you understand my question now
.
No, I still don't understand what's your problem with dynamic memory because you don't give an example. Most problems are from attempted uses with pointers after the lifetime/scope of the allocated memory outside of the function.
Pointers can be tricky so it's takes time to develop good intuition on what works and what crashes.

A embedded C example passing structures to functions that don't use dynamic memory allocation that must be tracked for proper program operation. It uses function local variables on the stack or passed pointers instead.
Here I create a device command structure (ticbuf_type) to properly format binary date to a TIC12400 I/O device and response binary structures (ticread_type) from the device.

C:
#ifndef TIC12400_H    /* Guard against multiple inclusion */
#define TIC12400_H

#include <stdlib.h>
#include <stdbool.h>
#include <stdint.h>

#define TIC12400_DRIVER "V0.5"

#define por_bit 0x01
/*
* switch bit masks in the raw 32-bit register from the TIC12400
*/
#define raw_mask_0 0b010
#define raw_mask_11 0b100000000000000

/*
* TIC12400 command structure
*/
typedef struct __attribute__((packed))
{
    uint32_t par : 1;
    uint32_t data : 24;
    uint32_t addr : 6;
    uint32_t wr : 1;
}
ticbuf_type;

/*
* TIC12400 response structure
*/
typedef struct __attribute__((packed))
{
    uint32_t par : 1;
    uint32_t data : 24;
    uint32_t oi : 1;
    uint32_t temp : 1;
    uint32_t vs_th : 1;
    uint32_t ssc : 1;
    uint32_t parity_fail : 1;
    uint32_t spi_fail : 1;
    uint32_t por : 1;
}
ticread_type;

void tic12400_version(void);
void tic12400_reset(void);
bool tic12400_init(void);
uint32_t tic12400_wr(const ticbuf_type *, uint16_t);
uint32_t tic12400_get_sw(void);
void tic12400_read_sw(uint32_t, uintptr_t);
bool tic12400_parity(uint32_t);

extern volatile uint32_t tic12400_status, tic12400_counts, tic12400_value_counts;
extern volatile uint32_t tic12400_value;
extern volatile bool tic12400_init_fail, tic12400_event;
extern volatile bool tic12400_parity_status;
extern volatile int32_t    tic12400_fail_value;

/* Provide C++ Compatibility */
#ifdef __cplusplus
extern "C" {
#endif


    /* Provide C++ Compatibility */
#ifdef __cplusplus
}
#endif

#endif /* TIC12400_H */

/* *****************************************************************************
End of File
*/
The ticbuf_type is used to define sets in memory of commands (like setup32) the software uses to communicate with the device.
Here we pass the memory address of the setup32 command to the tic12400_wr function.
tic12400_wr(&setup32, 0); //all set to compare mode, 0x32


C:
/*
* TC12400 driver for PIC32MK v0.1
* uses SPI5 mode1 at 4MHz no interrupts
* external interrupt 2 is used to detect chip switch events
*/

#include "tic12400.h"
#include "tictest.h"
#include "mcp2210.h"

/*
* command structure data
* the parity bit must be set correctly for the command to execute on the chip
*/
const ticbuf_type setup32 = {
    .wr = 1,
    .addr = 0x32,
    .data = 0,
    .par = 1,
};
const ticbuf_type setup21 = {
    .wr = 1,
    .addr = 0x21,
    .data = 0,
    .par = 0,
};
const ticbuf_type setup1c = {
    .wr = 1,
    .addr = 0x1c,
    .data = 0,
    .par = 1,
};
const ticbuf_type setup1b = {
    .wr = 1,
    .addr = 0x1b,
    .data = 0xffffff,
    .par = 0,
};
const ticbuf_type setup1a = {
    .wr = 1,
    .addr = 0x1a,
    .data = 0xc000,
    .par = 1,
};
const ticbuf_type setup1a_trigger = {
    .wr = 1,
    .addr = 0x1a,
    .data = 0x0a00, // trigger and do config register CRC
    .par = 1,
};
const ticbuf_type setup22 = {
    .wr = 1,
    .addr = 0x22,
    .data = 0xffffff,
    .par = 0,
};
const ticbuf_type setup23 = {
    .wr = 1,
    .addr = 0x23,
    .data = 0xffffff,
    .par = 1,
};
const ticbuf_type setup24 = {
    .wr = 1,
    .addr = 0x24,
    .data = 0xfff,
    .par = 0,
};
const ticbuf_type setup1d = {
    .wr = 1,
    .addr = 0x1d,
    .data = 011111111, // octal constant, all inputs 1mA wetting current
    .par = 0,
};
const ticbuf_type ticread05 = {
    .wr = 0,
    .addr = 0x05,
    .data = 0,
    .par = 1,
};
const ticbuf_type ticdevid01 = {
    .wr = 0,
    .addr = 0x01,
    .data = 0,
    .par = 0,
};
const ticbuf_type ticstat02 = {
    .wr = 0,
    .addr = 0x02,
    .data = 0,
    .par = 0,
};
const ticbuf_type ticreset1a = {
    .wr = 1,
    .addr = 0x1a,
    .data = 0x1,
    .par = 0,
};

/*
* global status and value registers
*/
volatile uint32_t tic12400_status = 0, tic12400_counts = 0, tic12400_value_counts = 0;
volatile uint32_t tic12400_value = 0;
volatile bool tic12400_init_fail = false, tic12400_event = false; // chip error detection flag
volatile bool tic12400_parity_status = false;
volatile int32_t tic12400_fail_value = 0;

static ticread_type *ticstatus = (ticread_type*) & tic12400_status;
static ticread_type *ticvalue = (ticread_type*) & tic12400_value;

static const char *build_date = __DATE__, *build_time = __TIME__;

void tic12400_version(void)
{
    printf("\r--- TIC12400 Driver Version %s %s %s ---\r\n", TIC12400_DRIVER, build_date, build_time);
}
/*
* software reset of the chip using SPI
* all registers set to their default values
*/
/*
* chip setup via SPI data transfers
*/
void tic12400_reset(void)
{
    tic12400_wr(&ticreset1a, 4);
    tic12400_wr(&ticreset1a, 4);
    tic12400_fail_value = 1;
}

/*
* chip detection and configuration for all inputs with interrupts for
* switch state changes with debounce
* returns false on configuration failure
*/

/*
* chip setup via SPI data transfers
*/
bool tic12400_init(void)
{
    tic12400_status = tic12400_wr(&ticstat02, 0); // get status to check for proper operation

    if ((ticstatus->data > por_bit) || !ticstatus->por) { // check for any high bits beyond POR bits set
        tic12400_init_fail = true;
        tic12400_fail_value = -1;
        goto fail;
    }

    tic12400_wr(&setup32, 0); //all set to compare mode, 0x32
    tic12400_wr(&setup21, 0); //Compare threshold all bits 2V, 0x21
    tic12400_wr(&setup1c, 0); //all set to GND switch type, 0x1c
    tic12400_wr(&setup1b, 0); //all channels are enabled, 0x1b
    tic12400_wr(&setup22, 0); //set switch interrupts, 0x22
    tic12400_wr(&setup23, 0); //set switch interrupts, 0x23
    tic12400_wr(&setup24, 0); // enable interrupts, 0x24
    tic12400_wr(&setup1d, 0); // set wetting currents, 0x1d
    tic12400_wr(&setup1a, 0); // set switch debounce to max 4 counts, 0x1a
    tic12400_status = tic12400_wr(&setup1a_trigger, 2); // trigger switch detections & CRC, 0x1a

    if (ticstatus->spi_fail) {
        tic12400_init_fail = true;
        tic12400_fail_value = -2;
        goto fail;
    }

    tic12400_status = tic12400_wr(&ticdevid01, 0); // get device id, 0x01

fail:
    return !tic12400_init_fail; // flip to return true if NO configuration failures
}

/*
* send tic12400 commands to SPI port 5 with possible delay after transfer
* returns 32-bit spi response from the tic12400
*/
uint32_t tic12400_wr(const ticbuf_type * buffer, uint16_t del)
{
    static uint32_t rbuffer = 0;

    SPI_MCP2210_WriteRead((void*) buffer, 4, (void*) &rbuffer, 4);

    if (ticvalue->parity_fail) { // check for command parity errors
        tic12400_parity_status = true;
    };

    if (del) {
        sleep_us(del * 1000);
    }

    return rbuffer;
}

/*
* switch data reading testing routine
* tic12400 value is updated in external interrupt #2 ISR
*/
uint32_t tic12400_get_sw(void)
{
    if (tic12400_init_fail) { // Trouble in River City
        return 0;
    }

    if (tic12400_value & (raw_mask_0)) {
        //        BSP_LED1_Clear();
    } else {
        //        BSP_LED1_Set();
    }

    if (tic12400_value & (raw_mask_11)) {
        //        BSP_LED2_Clear();
    } else {
        //        BSP_LED2_Set();
    }

    tic12400_event = false;
    return tic12400_value;
}

/*
* 32-bit 1's parity check
* https://graphics.stanford.edu/~seander/bithacks.html#ParityNaive
*/
bool tic12400_parity(uint32_t v)
{
    v ^= v >> 16;
    v ^= v >> 8;
    v ^= v >> 4;
    v &= 0xf;
    return(0x6996 >> v) & 1;
}

/*
* switch SPI status and switch data updates
* sets event flag for user application notification
*/
void tic12400_read_sw(uint32_t a, uintptr_t b)
{
    tic12400_value = tic12400_wr(&ticread05, 0); // read switch
    tic12400_status = tic12400_wr(&ticstat02, 0); // read status

    if (ticvalue->ssc && tic12400_parity(tic12400_value)) { // only trigger on switch state change
        tic12400_event = true;
        tic12400_value_counts++;
    }
    tic12400_counts++;
}
 
Last edited:

Thread Starter

Dadu@

Joined Feb 4, 2022
145
.No, I still don't understand what's your problem with dynamic memory because you don't give an example.
I didn't want to jump on linked list in c but I think it is neccessary now

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

struct node
{
    int data;
    struct node* next;
};   

int main ()
{
    struct node * head = NULL;
    
    return 0;
}
I saw many sample codes but I am very confused when I try to make function to add new node in the list.

first of all I am trying to understand what i need to pass from main function before creating function and why it need to pass to function.
 

Thread Starter

Dadu@

Joined Feb 4, 2022
145
'node' is just a variable that stores data (info) and an address data (link to another 'node').
View attachment 262527
Look at my code, function create one node, that is head node of list. I don't understand what to do in function when second node will create ?
list has only single node. How to modify function to add second node in list ?
C:
#include <stdio.h>
#include <stdlib.h>

struct node
{
    int data;
    struct node* next;
};  

void Add ( struct node * head, int value )
{
    struct node * new = malloc(sizeof(*new));
    if ( new != NULL)
    {
       
        if ( head == NULL) // list is empty
        {
            new -> data = value ;
            new -> next = NULL ;
        }
    }
}
int main ()
{
    struct node * head = NULL;
   
    return 0;
}
 

xox

Joined Sep 8, 2017
794
A pointer is simply a variable which stores the address of ANOTHER variable. We use the `*` symbol to "dereference" the pointer in order to access whatever data it "points" to.

Code:
void foo(void) {
  int i = 1024;
  int* p = &i;
  printf("p = %d \n", *p);
}
In the above code, the pointer is first attached to a local variable. At the end of that function's execution, the variable will "go out of scope" (ie: die) and cannot be safely referenced by a pointer. The only way to do that is via heap allocation (eg: malloc, calloc, etc). Which is why linked lists typically use these functions to build their data structures. (You can of course construct them from non-heap data, it's just not as straightforward).

Pointers should ALWAYS be initialized. Otherwise you are just asking for trouble.

Code:
  int* p = NULL;
  printf("p = %d \n", *p); // CRASH!!!
The fact that the above program segfaults (crashes) is a GOOD thing. If you comment out the "= NULL" part, the result would be "undefined behavior". The program might crash or it may not. It just depends on the direction that the wind is blowing! So don't forget to initialize.

As far as linked lists go, you just need to start with a set of functions to allocate and add items to the list. There are numerous tutorials online with code snippets, if you care to search for them...
 

BobTPH

Joined Jun 5, 2013
6,080
Draw a picture of the list before and after adding the second node, then figure out what code it would take to go from the first picture to the second.

Bob
 

click_here

Joined Sep 22, 2020
545
With your adding function -

'malloc' a new node. If successful (not null), give it it's int value. (Later, you want to return a failure code on fail so the code can try and recover, but hold back for now)

If the head node is empty, put the new node as the head.

If the head is not empty, start at head and iterate through the list until you find the last node. (i.e. make a temp node pointer called "current", point it to the head, and while current->next != NULL, current = current->next)

Once you are at the last node, pointed to by current, set current->next to your new node, and then make the ->next = NULL

Hope this helps :)
 

Thread Starter

Dadu@

Joined Feb 4, 2022
145
I want to modify ptr ( from other function ). I need to write function for this.
How to do this ?
C:
#include<stdio.h>
#include<stdlib.h>

struct node
{
    int x;
    int y;
};

int main()
{
    struct node *ptr = NULL;
    
    return 0;
}
 

click_here

Joined Sep 22, 2020
545
If you wanted to modify a pointer's value in a function, you create a pointer to that pointer.

Code:
void apple(int **banana)
{
  ... // do something with *banana - That is "banana" dereferenced
}

int main(void)
{
  int *cherry;
  ...
  apple(&cherry);

  ...
  return 0;
}
For a struct you would usually need to dereference the struct first like this (*someStruct).someMember = ...

However, this can get confusing with things like linked lists when members are also pointers to structs, so there is another way to dereference structs: it's using the '->' notation, which you have probably seen at this point in your class :)
 

click_here

Joined Sep 22, 2020
545
Here is a small example that might help...
Code:
#include <stdio.h>

struct node
{
    int value;
};

void changeStructPointer(struct node **pea, struct node *carrot)
{
    *pea = carrot;
}

int main(void) 
{
    struct node apple, banana, *grape;
    
    // Set things up...  
    apple.value = 1;
    banana.value = 2;
    
    grape = &apple;
    
    printf("Before: %d\n", grape->value);
       
    changeStructPointer(&grape, &banana);      
       
    printf("After: %d\n", grape->value);
             
    return 0;  
}
 

click_here

Joined Sep 22, 2020
545
Just for some more options with structs...
Code:
#include <stdio.h>

struct node
{
    int value;
    struct node *otherNode;
};

void changeStructPointer(struct node **pea, struct node *carrot)
{
    *pea = carrot;
}

int main(void) 
{
    struct node apple, banana, mango, *grape;
    
    // Set things up...  
    apple.value = 1;
    banana.value = 2;
    mango.value = 3;
    
    apple.otherNode = &banana;
    banana.otherNode = &apple;
    mango.otherNode = &banana;
    
    grape = &apple;
    
    printf("Before: %d\n", grape->value);
       
    changeStructPointer(&grape, &banana);      
       
    printf("After: %d\n", grape->value);
       
       
    printf("Other node: %d\n", grape->otherNode->value);
       
    changeStructPointer(&grape->otherNode, &mango);
    
    printf("New node: %d\n", grape->otherNode->value);
    
    printf("Just for fun: %d\n", grape->otherNode->otherNode->value);

    return 0;  
}
 

Thread Starter

Dadu@

Joined Feb 4, 2022
145
When I run the code I get the output 1

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

struct node
{
    int data;
};

void foo (struct node **current )
{
   
}

int main()
{
    struct node *head = malloc(sizeof(*head));
    head -> data = 1;
   
    foo(&head);
   
    printf(" data in main = %d \n", head -> data);
   
    return 0;
}
data in main = 1
I want that my print statement should give output 2 . so what should I write in the function for this ?
 

Thread Starter

Dadu@

Joined Feb 4, 2022
145
You don't need that level of indirection here. A plain pointer will do.

Code:
void setNode(node* element, int value) {
  // ...update node data here...
}
Done
C:
#include<stdio.h>
#include<stdlib.h>

struct node
{
    int data;
};

void foo (struct node *current )
{
    current -> data = 2;
}

int main()
{
    struct node *head = malloc(sizeof(*head));
    head -> data = 1;

    foo(head);

    printf(" data in main = %d \n", head -> data);

    return 0;
}
How to modify head pointer in function ?

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

struct node
{
    struct node * next;
};

void foo (struct node **current )
{
   
}

int main()
{
    struct node *head = malloc(sizeof(*head));
    head -> next = NULL;
    printf("%p \n", head -> next);
    foo(&head);
  
    printf("%p \n", head -> next);
  
    return 0;
}
00000000
00000000
 

click_here

Joined Sep 22, 2020
545
How to modify head pointer in function ?
Have a look at "changeStructPointer()" in the code from the other day...
Just for some more options with structs...
Code:
#include <stdio.h>

struct node
{
    int value;
    struct node *otherNode;
};

void changeStructPointer(struct node **pea, struct node *carrot)
{
    *pea = carrot;
}

int main(void)
{
    struct node apple, banana, mango, *grape;
   
    // Set things up... 
    apple.value = 1;
    banana.value = 2;
    mango.value = 3;
   
    apple.otherNode = &banana;
    banana.otherNode = &apple;
    mango.otherNode = &banana;
   
    grape = &apple;
   
    printf("Before: %d\n", grape->value);
      
    changeStructPointer(&grape, &banana);     
      
    printf("After: %d\n", grape->value);
      
      
    printf("Other node: %d\n", grape->otherNode->value);
      
    changeStructPointer(&grape->otherNode, &mango);
   
    printf("New node: %d\n", grape->otherNode->value);
   
    printf("Just for fun: %d\n", grape->otherNode->otherNode->value);

    return 0; 
}
...Just dereference the pointer like any other.

In the example given I changed the value "at the address" given by the value of "pea"
 

Thread Starter

Dadu@

Joined Feb 4, 2022
145
...Just dereference the pointer like any other.
Thank you so much

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

struct node
{
    struct node * next;
};

void foo (struct node **current )
{
    struct node *new = malloc(sizeof(*new));
    if( new != NULL )
    {
        (*current) -> next = new;
    }
}

int main()
{
    struct node *head = malloc(sizeof(*head));
    head -> next = NULL;
    printf("%p \n", head -> next);
    foo(&head);
  
    printf("%p \n", head -> next);
  
    return 0;
}
00000000
00BC0D48
 

Thread Starter

Dadu@

Joined Feb 4, 2022
145
I have program that print three node in list

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

struct node
{
    int data;
    struct node * next;
};

void ADD (struct node **current, int value )
{
    struct node *new = malloc(sizeof(*new));
    if( new != NULL )
    {
        new -> data = value;
        new -> next = *current;
        *current  = new;
    }
}

int main()
{
    struct node *head = NULL;

    ADD(&head, 1);
    printf("%d \n", head -> data);
    printf("%p \n", head -> next);
    printf("head hold memory %p \n", head);
   
    ADD(&head, 2);
    printf("%d \n", head -> data);
    printf("%p \n", head -> next);
    printf("head hold memory %p \n", head);

    ADD(&head, 3);
    printf("%d \n", head -> data);
    printf("%p \n", head -> next);
    printf("head hold memory %p \n", head);
   
    return 0;
}
1
00000000
head hold memory 006F0D18
2
006F0D18
head hold memory 006F0D48
3
006F0D48
head hold memory 006F0D58

I figured out my list works like Head <- Node 1 - Node 2 <- Node 3

pointer of current node point to previous node but I want pointer of current node point to next node Node 1 -> Node 2 -> Node 3

Any idea how to point to next node not previous node ?
 
Top