Nozioni di base sulle strutture a C

Nozioni di base sulle strutture a C

Gli array forniscono la funzione per raggruppare elementi di dati correlati dello stesso tipo in un unico oggetto. Tuttavia, a volte è necessario raggruppare elementi di dati correlati di tipo diverso. Un esempio è il record di inventario di un articolo in stock che raggruppa il numero dell'articolo, il prezzo, la quantità in magazzino, il livello di riordino ecc. Per gestire tali situazioni, C fornisce un tipo di dati, chiamato strutture, che consente un numero fisso di dati oggetti, eventualmente di diverso tipo da trattare come un unico oggetto. Viene utilizzato per raggruppare tutte le informazioni correlate in un'unica variabile.

Nozioni di base sulle strutture

La struttura è una raccolta di elementi di dati logicamente correlati raggruppati sotto un unico nome, chiamato tag di struttura. Gli elementi di dati che compongono una struttura sono chiamati membri o campi e possono essere di diversi tipi.

Il formato generale per definire una struttura è:

struct tag_name 
{ 
   data_type member1; 
   data_type member2; 
   ... 
};

dove,
struttura :una parola chiave che introduce una definizione di struttura.
Tag_name :il nome della struttura
membro1, membro2 :Insieme del tipo di dichiarazioni per i dati dei membri che compongono la struttura.

Ad esempio, la struttura per il record di inventario di un articolo in stock può essere definita come:

struct item 
{ 
   int itemno; 
   float price; 
   float quantity; 
   int reorderlevel; 
}; 

Si consideri un altro esempio, di un database di libri composto da nome del libro, autore, numero di pagine e prezzo. Per contenere le informazioni del libro, la struttura può essere definita come segue:

struct book_bank 
{ 
   char title[15]; 
   char author[10]; 
   int pages; 
   float price; 
}; 

La dichiarazione precedente non dichiara alcuna variabile. Descrive semplicemente un formato chiamato modello per rappresentare le informazioni come mostrato di seguito:

struct book_bank 
title       array of 15 characters 
author      array of 10 characters 
pages       integer 
price       float

La figura seguente illustra schematicamente la composizione di questo database di libri.

Tutti i membri di una struttura possono essere dello stesso tipo, come nella seguente definizione della data della struttura.

struct date 
{ 
   int day,month,year; 
};

Dichiarazione dei singoli membri di una struttura

I singoli membri di una struttura possono essere qualsiasi tipo di dati (come int, float, ecc.), puntatori, array o anche altre strutture. I singoli membri di una struttura possono essere qualsiasi tipo di dati (come int, float, ecc.), puntatori, array o anche altre strutture.

I singoli membri non possono essere inizializzati all'interno della dichiarazione della struttura.

Variabili di struttura

Una definizione di struttura definisce un nuovo tipo e le variabili di questo tipo possono essere dichiarate nei seguenti modi:
Nella dichiarazione della struttura:includendo un elenco di nomi di variabili tra la parentesi graffa destra e il punto e virgola di terminazione nella definizione della struttura.

Ad esempio, la dichiarazione:

struct student 
{ 
   int rollno; 
   char subject[10]; 
   float marks; 
} student1, student2; 

dichiara student1, student2 variabili di tipo struct student. Se non sono richieste altre variabili della struttura, il tag nome studente può essere omesso come mostrato di seguito:

struct 
{ 
   int rollno; 
   char name[10]; 
   float marks; 
} student1, student2;

Utilizzo del tag struttura

Il tag di struttura può essere pensato come il nome del tipo introdotto dalla definizione della struttura e le variabili possono anche essere dichiarate di un particolare tipo di struttura mediante una dichiarazione della forma:

struct tag variable-list; 

Ad esempio,

struct student student1,student2; 

dichiara student1 e student2 variabili di tipo struct student.

Inizializzazione struttura

Una variabile di un particolare tipo di struttura può essere inizializzata seguendo la sua definizione con un inizializzatore per il tipo di struttura corrispondente. L'inizializzatore contiene i valori iniziali per i componenti della struttura, inseriti tra parentesi graffe e separati da virgole. Quindi, la dichiarazione:

struct date 
{ 
   int day,month,year; 
}independence={15,8,1947}; 

inizializza le variabili membro giorno, mese e anno dell'indipendenza della variabile di struttura rispettivamente a 15, 8 e 1947.

La dichiarazione:

struct date republic ={26,1,1950};

inizializza le variabili membro giorno, mese e anno della variabile di struttura repubblica rispettivamente a 26, 1 e 1950. Considerando la definizione della struttura studente (definita in 8.1.2), la dichiarazione

struct student student1={1,”Ashwini”,98.5};

Inizializza le variabili membro rollno, name e mark della variabile di struttura student1 su 1, rispettivamente “Ashwini” e 98.5. Se nella struttura sono presenti un numero di inizializzatori inferiore a quello delle variabili membro, le restanti variabili membro vengono inizializzate su zero.

Così l'inizializzazione:

struct date newyear={1,1};

è uguale a:

struct date newyear={1,1,0}; 

Accesso ai membri della struttura

Con l'aiuto dell'operatore punto(.), è possibile accedere ai singoli elementi di una struttura e la sintassi è della forma:

structure-variable.member-name; 

Quindi per fare riferimento al nome della struttura studente, possiamo usare:

 student1.name; 

Le dichiarazioni,

struct date emp;
emp.day=28;
emp.month=7; 
emp.year=1969;

impostare i valori delle variabili membro giorno, mese e anno all'interno della variabile emp rispettivamente a 28, 7 e 1969 e la dichiarazione.

struct date today; 
if(today.day==1&&today.month==1) 
    printf(“Happy New Year”);

verifica i valori di giorno e mese per verificare se entrambi sono 1 e, in tal caso, stampa il messaggio. Gli elementi di una struttura sono sempre archiviati in locazioni di memoria contigue. È mostrato di seguito:

Di seguito sono riportati alcuni esempi forniti utilizzando le strutture:

/* Program to print the date using structure variable */
# include<stdio.h>
void main(void) 
{ 
struct date 
{ 
    char month[15]; 
    int day,year; 
}; 
struct date today; 
today.day=11; 

printf(“Enter Month : ”); 
scanf(“%[^\n]”,today.month); 
today.year=1998; 
printf(“\nToday’s date is %d-%s-%d \n”, today.day,today.month,today.year); 
} 
*** str.h *** 
struct date 
{ 
int month,day,year; 
};
/* Program to print the date using structure variable */
#include<stdio.h>
 # include “str.h” 
 void main(void) 
 { 
    struct date today; 
    struct date tomorrow; 
    static int day_month[12]= {31,28,31,30,31,30,31,31,30,31,30,31}; 
    printf(“Enter Today’s date (dd:mm:yy): ”); 
    scanf(“%d%d%d”,&today.day,&today.month,&today.year); 
    if(today.day > day_month[today.month-1]) 
    { 
        printf(“\n Invalid Date \n”); 
        exit(0); 
    } 
    if(today.day!=day_month[today.month-1]) 
    { 
        tomorrow.day=today.day+1; 
        tomorrow.month=today.month; 
        tomorrow.year=today.year; 
    } 
    else if(today.month==12) 
    { 
        tomorrow.day=1; 
        tomorrow.month=1; 
        tomorrow.year=today.year+1; 
    } 
    else 
    { 
        tomorrow.day=1; 
        tomorrow.month= today.month+1; 
        tomorrow.year=today.year; 
    } 
    printf(“\n Tomorrow’s date is %d-%d-%d \n”, tomorrow.day,tomorrow.month,tomorrow.year); 
}

Una struttura può essere copiata in un'altra struttura dello stesso tipo direttamente utilizzando l'operatore di assegnazione nonché elemento per elemento come gli array.

In questo caso, i valori dei membri di una variabile di struttura vengono assegnati ai membri di un'altra variabile di struttura dello stesso tipo. È illustrato nell'esempio seguente.

*** strdef.h *** 
 struct date 
 { 
   char month[5]; 
   int day,year; 
 };
/* Example - To copy a structure to another structure */
# include <stdio.h>
# include <string.h>
# include "strdef.h"
void main(void) 
{ 
   struct date today={“March”,1,98}; 
   struct date day1,day2; 
   
   /* copying element by element basis */ 
   strcpy(day1.month,today.month); 
   day1.day=today.day; 
   day1.year=today.year; 
   
   /* copying entire structure to another structure */ 
   day2=day1; 
   printf(“\n Date is %d %s %d \n”, today.day,today.month,today.year); 
   printf(“\nDate is %d %s %d \n”, day1.day,day1.month,day1.year); 
   printf(“\n Date is %d %s %d \n”, day2.day,day2.month,day2.year); 
}

Funzioni e strutture

Possiamo passare strutture come argomenti a funzioni. A differenza dei nomi di array, tuttavia, che puntano sempre all'inizio dell'array, i nomi di struttura non sono puntatori. Di conseguenza, quando cambiamo un parametro di struttura all'interno di una funzione, non influiamo sul suo argomento corrispondente.

Passare la struttura agli elementi alle funzioni:

Una struttura può essere passata a una funzione come membro singolo o come variabile separata. Di seguito è riportato un esempio di programma per visualizzare il contenuto di una struttura che passa i singoli elementi ad una funzione.

# include < stdio.h >
void main() 
{ 
    int emp_id; 
    char name[25]; 
    char department[10]; 
    float salary; 
}; 
static struct emp1={125,”sampath”,”operator”,7500.00}; 

/* pass only emp_id and name to display function*/ 
display(emp1.emp_id,emp1.name); 
} 

/* function to display structure variables*/ 
display(int e_no,char *e_name) 
{ 
printf(“%d%s”,e_no,e_name); 
} 

Nella dichiarazione del tipo di struttura, emp_id e name sono stati dichiarati come intero e array di caratteri. Quando chiamiamo la funzione display() usando display(emp1.emp_id,emp1.name); stiamo inviando emp_id e il nome alla funzione display(). Si può immediatamente capire che passare singoli elementi diventerebbe più noioso man mano che il numero di elementi della struttura continua ad aumentare, un modo migliore sarebbe passare l'intera variabile della struttura alla volta.

Passare l'intera struttura alle funzioni:

Nel caso in cui le strutture debbano avere numerosi elementi strutturali, il passaggio di questi singoli elementi sarebbe un compito noioso. In questi casi possiamo passare l'intera struttura a una funzione come mostrato di seguito:

# include <stdio.h>
{ 
   int emp_id; 
   char name[25]; 
   char department[10]; 
   float salary; 
}; 
void main() 
{ 
   static struct employee emp1= {12, “sadanand”, “computer”, 7500.00}; 
   display(emp1); /*sending entire employee structure*/ 
}

/*function to pass entire structure variable*/ 
display(struct employee empf) 
{ 
   printf(“%d%s,%s,%f”, empf.empid,empf.name,empf.department,empf.salary); 
}

Strutture e array

Gli array e le strutture possono essere liberamente mescolati per creare array di strutture, strutture che contengono array.

Matrici di strutture

Nell'array di strutture l'array contiene singole strutture come suoi elementi. Questi sono comunemente usati quando è necessario elaborare insieme un numero elevato di record simili.

Ad esempio, i dati di un motore contenente 1000 parti possono essere organizzati in una matrice di struttura come

struct item motor[1000]; 

Questa istruzione dichiara che il motore è un array contenente 1000 elementi del tipo struct item.

Un array di strutture può essere dichiarato in due modi, come illustrato di seguito. Il primo modo è dichiarare:

struct person 
{ 
   char name[10]; 
   struct date birthday; 
   float salary; 
}emprec[15]; 

In questo caso, emprec è un array di 15 strutture di persone. Ogni elemento dell'array emprec conterrà la struttura di tipo person. La struttura delle persone è composta da 3 singoli membri:un nome di matrice, lo stipendio e un'altra data di struttura. La data della struttura incorporata deve essere dichiarata prima del suo utilizzo all'interno della struttura contenitore. Il secondo approccio allo stesso problema prevede l'uso del tag di struttura come di seguito.

struct person 
{ 
   char name[10]; 
   struct date birthday; 
   float salary; 
}; 
struct person emprec[15]; 

Il programma seguente spiega come utilizzare una matrice di strutture.

/* Example- An array of structures */ 
 # include<stdio.h>
 void main(void) 
 { 
   struct book 
   { 
       char name[15]; 
       int pages; 
       float price; 
   }; 
   struct book b[10]; 
   int i; 
   printf(“\n Enter name, pages and price of the book\n”); 
   
   /* accessing elements of array of structures */ 
   for(i=0;i<9;i++) 
   { 
       scanf(“%s%d%f”,b[i].name,&b[i].pages,&b[i].price); 
       printf(“\n”); 
   } 
   printf(“\n Name, Pages and Price of the book :\n”); 
   for(i=0;i<=9;i++) 
   { 
       printf(“%s %d %f”,b[i].name,b[i].pages,b[i].price); 
   } 
 }

Array all'interno delle strutture

Una struttura può contenere array come membri. Questa funzione viene utilizzata frequentemente quando una stringa deve essere inclusa in una struttura. Ad esempio, la struttura della data può essere espansa per includere anche i nomi del giorno della settimana e del mese come:

 struct date 
 { 
    char weekday[10]; 
    int day; 
    int month; 
    char monthname[10]; 
    int year; 
 };

Una variabile di struttura ndate può essere dichiarata e inizializzata come –

struct date ndate={”Sunday”,21,11,”November”,2004};

È possibile accedere a un elemento di un array contenuto in una struttura utilizzando gli operatori punto e indice di array. Così la dichiarazione,

printf(“%c”,ndate.monthname[2]); 

stampe v.

Strutture e indicatori

Indicatori alle strutture

L'indirizzo iniziale di una struttura è accessibile allo stesso modo di qualsiasi altro indirizzo, tramite l'utilizzo dell'indirizzo dell'operatore (&). Pertanto, se variabile rappresenta una variabile di tipo struttura, allora:

&variable

rappresenta l'indirizzo iniziale di quella variabile. Inoltre, possiamo dichiarare una variabile puntatore per una struttura scrivendo:

type *ptvar; 

dove,
digita :un tipo di dati che identifica la composizione della struttura
ptvar :il nome della variabile puntatore

La variabile del puntatore che contiene l'indirizzo della struttura è chiamata Puntatori della struttura. Ad esempio, la dichiarazione:

struct date ndate,*ptrndate;

dichiara che ndate è una variabile di tipo struct date e la variabile ptrndate è un puntatore a una variabile di data struct. Considera il seguente esempio:

typedef struct 
{ 
   int acct_no; 
   char acct_type; 
   char name[20]; 
   float balance; 
   date lastpayment; 
}account; 
account customer,*pc; 

In questo esempio, customer è una variabile di struttura di tipo account e pc è una variabile puntatore il cui oggetto è una struttura di tipo account. L'operatore indirizzo (&) viene applicato a una variabile di struttura per ottenere l'indirizzo iniziale del cliente. Può essere assegnato al pc scrivendo.

pc=&customer; 

Le dichiarazioni di variabile e puntatore possono essere combinate con la dichiarazione di struttura scrivendo

struct 
{ 
    member 1; 
    member 2; 
    ... 
    member n; 
  }variable,*ptvar;

Dove,
variabile :una variabile di tipo struttura
ptvar :il nome di una variabile puntatore

La seguente singola dichiarazione equivale alle due dichiarazioni presentate nell'esempio precedente.

struct 
{ 
    int acct_no; 
    char acct_type; 
    char name[20]; 
    float balance; 
    date lastpayment; 
}customer,*pc; 

La variabile puntatore pc può ora essere utilizzata per accedere alle variabili membro del cliente utilizzando l'operatore punto come:

(*pc).acct_no; 
(*pc).acct_type; 
(*pc).name;

Le parentesi sono necessarie perché l'operatore punto(.) ha una precedenza maggiore rispetto a quella dell'operatore di dereferenziazione(*). È possibile accedere ai membri anche utilizzando un operatore speciale chiamato puntatore struttura o operatore freccia (->).

Il modulo generale per l'utilizzo dell'operatore -> è

printer_name->member_name;

Quindi,

if pc=&customer 
     pc->balance=(*pc).balance=customer.balance

dove, saldo è membro della struttura cliente.

È possibile prendere gli indirizzi delle variabili membro di una variabile di struttura. Ad esempio, l'affermazione

float *ptrbal=&customer.balance;

definisce ptrbal come un puntatore a virgola mobile e lo inizializza in modo che punti al saldo della variabile membro all'interno della variabile di struttura customer. L'espressione del puntatore &customer.balance viene interpretata come &(customer.balance) poiché la precedenza dell'operatore punto è maggiore di quella dell'operatore indirizzo.

/* Example- structure pointers */ 
 # include <stdio.h>
 # include "str.h" 
 struct 
 { 
    int acct_no; 
    char acct_type; 
    char *name; 
    float balance; 
    struct date *lastpayment; 
   }customer, *pc = &customer; 
 struct date PaymentDate ; 
 void main(void) 
 { 
    PaymentDate.day = 26 ; 
    PaymentDate.month = 1 ; 
    PaymentDate.year = 1999 ; 
    customer.acct_no=55; 
    customer.acct_type='A'; 
    customer.name="Ashwini"; 
    customer.balance=99.99; 
    customer.lastpayment = &PaymentDate ; 
    printf("Account:%d\n",pc->acct_no); printf("Acc_Type : %c \n",pc->acct_type); 
    printf("Name : %s \n",pc->name); 
    printf("Balance : %.2f \n",pc->balance); 
    printf("LastPayment : %2d-%2d-%4d \n", 
        pc->lastpayment->day,pc->lastpayment->month, 
        pc->lastpayment->year); 
 }

All'interno della seconda struttura, i membri acct_no, acct_type, nome e saldo vengono scritti come puntatori. Pertanto, il valore a cui acct_no points è accessibile scrivendo *customer.acct_no o *p->acct_no. Lo stesso in caso di acct_type e saldo. Una stringa può essere assegnata direttamente a un puntatore del tipo di carattere. Pertanto, se il nome punta all'inizio di una stringa, è possibile accedere alla stringa scrivendo nome.cliente o pc->nome.

Assegnazione della memoria per il puntatore a una struttura

La memoria dall'heap deve essere allocata per un puntatore a una struttura se si desidera archiviare alcuni dati, questo viene fatto utilizzando maloc() funzione.

Esempio:

typedef struct 
{ 
   char name[20]; 
   char address[20]; 
   int empid; 
}emp,*empptr; 

La memoria per memorizzare informazioni su 10 dipendenti può essere allocata dalla dichiarazione:

empptr=(emp*)malloc(10*sizeof(emp));

Dopo che la memoria è stata allocata, puoi usare il puntatore per ottenere le informazioni come segue

for(i=0;i<10;i++) 
{ 
      scanf(“%s%s%d”,empptr[i].name,empptr[i].address, & empptr[i].empid); 
}

Strutture contenenti puntatori

Una struttura può contenere puntatori come variabili membro. Ad esempio, la definizione della struttura,

 struct location 
 { 
    char *name; 
    char *addr; 
 }; 

definisce una posizione della struttura che contiene due puntatori di carattere, name e addr come variabili membro. Le variabili di tipo struct location possono ora essere definite e manipolate come in:

struct location att={“Ashwini”,”Boston’s Computer Institute”}; 
struct location ibm; 
ibm.name=”R&D”; 
ibm.addr=”Bell Labs,California”;

data della struttura di accesso definita in str.h:

     *** str1.h *** 
# include “str.h” 
struct person 
{ 
    char name[20]; 
    char *lastname; 
    struct date birthday; 
    float *salary; 
}emprec; 

*** strptr.c***:

/* Example- structure containing pointers */ 
# include<stdio.h> 
# include “str1.h” 
void main(void) 
{ 
    float x; 
    struct person *ptr = &emprec; 
    struct date *birth = &emprec.birthday; 
    strcpy(emprec.name,”Ashwini”); 
    emprec.lastname = ”A.”; 
    ptr->birthday.day = 28; 
    emprec.birthday.month = 7; 
    birth->year = 97; 
    x=5000; 
    ptr->salary = &x; 
    printf(“ *** Employee Details *** \n”); 
    printf(“Name :%s %s \n”,ptr->name,ptr->lastname); 
    printf(“Birthdate: %d:%d:%d \n”,(*ptr).birthday.day, 
        birth->month,emprec.birthday.year); 
    printf(“Salary :%6.2f”,emprec.salary); 
}

Uscita:

*** Employee Details *** 
Name: Ashwini A. 
Birthday: 28:7:97 
Salary: 5000.00

Assegnazione della memoria per la struttura contenente il puntatore

Quando c'è un membro di una struttura, che è un puntatore a una struttura, non è sufficiente allocare memoria per il puntatore alla struttura, ma devi allocare memoria anche per il puntatore del membro.

Example: 
typedef struct 
{ 
   char* name; 
   char* address; 
   int empid; 
}emp,*empptr;

Il programma seguente illustra l'allocazione della memoria del puntatore all'interno della struttura. Il programma consente all'utente di inserire il numero totale di dipendenti e la dimensione del nome in fase di esecuzione.

#include <stdio.h>
#include <alloc.h>
#include <string.h>
void main(void) 
{ 
 int n,i,j; 
 typedef struct 
 { 
    int empno; 
    char *name; 
 }emp; 
   emp *empptr; 
   char name[80] ; 
   printf("Enter total no. of employees:"); 
   scanf("%d",&n); 
   fflush(stdin); 
   empptr = (emp *) malloc(n * sizeof(emp)); 
   for(i = 0 ; i < n ; i++) 
   { 
       printf("\n Enter empno of employee (%d) :",i+1); 
       scanf("%d",&empptr[i].empno); 
       fflush(stdin); 
       printf("\n Enter name :"); 
       scanf("%[^\n]",name); 
       fflush(stdin); 
       empptr[i].name = (char *) malloc(strlen(name) * sizeof(char) + 1 ); 
       strcpy(empptr[i].name, name) ; 
   } 
   for(i=0;i < n ; i++) 
   { 
       printf("\nno-%d \tname-%s",empptr[i].empno, 
       empptr[i].name); 
    } 
}