0

I have a program (part of an example I am trying to work out), that reads a value from a text file (bus.txt), and then for these number of seats initializes the values of a structure which is a linked list. All of this is done inside a function, and I want the linked list to be available outside of the function. Then I want to print out the results, but can't seem to manage to find a solution.

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

int i, j, numberofseats, temp;
char platenr[8], selection;
char firstname[20], lastname[20];
char phone[11];
char* p;

typedef struct psg
{
    char fullname[40];
    unsigned short phonenr[10];
    unsigned int seatnr;
    struct psg* next;
} PASSENGERS;


void readfile(char* platenr, int* seatnr, PASSENGERS* passenger, PASSENGERS* tmp, PASSENGERS* start)
{
    char buff[60];
    FILE* businfo;
    businfo = fopen ("bus.txt", "r");

    if (businfo == NULL)
    {
        printf("Error Opening File, check if file bus.txt is present");
        exit(1);
    }
    else
    {
        fscanf(businfo, "%s %d", platenr, seatnr);
        printf("Bus Licence plate Nr is: %s, and Number of Seats is: %d", platenr, *seatnr);

        for (i = 0; i < numberofseats; i++)
        {
            passenger  = (PASSENGERS*) malloc (sizeof(PASSENGERS));
            if (passenger == NULL)
            {
                puts("Unable to allocate memory");
                exit(1);
            }

            passenger->next = NULL;
            strcpy (passenger->fullname, "A");    
            passenger->seatnr = i + 1;

            for (j = 0; j < 10; j++)
            {
                passenger->phonenr[j] = 0;
            }

            if (start == NULL)
            {
                start = passenger;
            }
            else
            {
                tmp = start;

                while (tmp->next != NULL)
                {
                    tmp = tmp->next;
                }

                tmp->next = passenger;
            }
        }
    }
}


int main()
{
    PASSENGERS* passenger, *tmp, *start = NULL;
    readfile(platenr, &numberofseats, passenger, tmp, start);

    PASSENGERS* current = passenger;

    while (current != NULL)
    {
        printf("%s", current->fullname);
        printf("\n");
        current = current->next;
    }
}
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
baskon1
  • 330
  • 1
  • 3
  • 15
  • 1
    Please improve the indentation. – Rishikesh Raje Dec 20 '16 at 06:29
  • 1
    Hint: returning values from functions might be connected with the `return` keyword. Hint 2: before reading the file there is NO passenger information, so it makes little sense for `readfile` to receive a pointer to `PASSENGER`, much less three of them. They cannot possibly point to anything legal. – n. m. could be an AI Dec 20 '16 at 06:34
  • Essentially all those global variables should be made into local variables in the appropriate functions. You should close the file you opened. You need to consider how the data gets accessed after `readfile()` has finished. It isn't via any of the `PASSENGERS *` arguments. – Jonathan Leffler Dec 20 '16 at 06:58

3 Answers3

1

The pointer start is changed inside the function readfile. Outside the function the pointer will still maintain the value NULL.

To solve this, you can use a pointer to pointer or return the start value from the readfile function.

PASSENGERS* readfile(char *platenr, int *seatnr, PASSENGERS *passenger, PASSENGERS *tmp, PASSENGERS *start) 
{
  ...

  return start;
}

// in main
start = readfile(platenr, &numberofseats, passenger, tmp, start);

Additionally, you do not need to pass the variables platenr, tmp, passenger as parameters to the readfile function. They can be internal variables of the function.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
Rishikesh Raje
  • 8,556
  • 2
  • 16
  • 31
1

There are 3 ways (that I can think of) to get the list between readfile and main:

  1. Use a global variable (I wouldn't have used it in this case)

You can read about global variables here https://www.tutorialspoint.com/cprogramming/c_scope_rules.htm and here you can find a discussion on whether or not you should minimize the use of global variables: Why are global variables bad, in a single threaded, non-os, embedded application

  1. Send the memory address to be updated - I would use it if I had to return more than one parameter from the function.

    void readfile(char* platenr, int* seatnr, PASSENGERS* passenger, PASSENGERS* tmp, PASSENGERS* start)

and in the function change the value of passenger by (for example)

*passenger  = (PASSENGERS*) malloc (sizeof(PASSENGERS));
*passenger->next = NULL;
strcpy (*passenger->fullname, "A");    
*passenger->seatnr = i + 1;

Just make sure you verify passenger is not null before attempting to dereference it. (you should also check malloc succeeded before attempting *passenger->fullname).

  1. Use the return value - which is what I would have used here. My function declaration would be

    PASSENGERS* readfile(char* platenr, int seatnr)

and I would return start

return start;

The call to the function from main will be

PASSENGERS* current = readfile(platenr, numberofseats);

I think this kind of solution is easier to read.

Community
  • 1
  • 1
Shay Gold
  • 403
  • 4
  • 14
0

You can do it via double pointer, we can passing an address of a pointer and dereference it in our function and put newly allocated block inside it

void allocate_space(char ** ptr, int size){
    *ptr = malloc(size);
}

char * pointer = NULL;

allocate_space(&pointer, 100); // now pointer points to block allocated inside allocate_space function
e.jahandar
  • 1,715
  • 12
  • 30