UNIT – 7

STRUCTURES

What is a Structure?
  • Structure is a method of packing the data of different types.
  • When we require using a collection of different data items of different data types in that situation we can use a structure.
  • A structure is used as a method of handling a group of related data items of different data types.
A structure is a collection of variables under a single name. These variables can be of different types, and each has a name which is used to select it from the structure. A structure is a convenient way of grouping several pieces of related information together.
A structure can be defined as a new named type, thus extending the number of available types. It can use other structures, arrays or pointers as some of its members, though this can get complicated unless you are careful.

Defining a Structure

A structure type is usually defined near to the start of a file using a typedef statement. typedef defines and names a new type, allowing its use throughout the program. typedefs usually occur just after the #define and #include statements in a file.
Here is an example structure definition.
type def structure {
char name[64];
char course[128];
int age;
int year;
} student;
This defines a new type student variables of type student can be declared as follows.
student st_rec;
Notice how similar this is to declaring an int or float.
The variable name is st_rec, it has members called name, course, age and year.

Accessing Members of a Structure

Each member of a structure can be used just like a normal variable, but its name will be a bit longer. To return to the examples above, member name of structure st_rec will behave just like a normal array of char, however we refer to it by the name .
st_rec.name
Here the dot is an operator which selects a member from a structure.
Where we have a pointer to a structure we could deference the pointer and then use dot as a member selector. This method is a little clumsy to type. Since selecting a member from a structure pointer happens frequently, it has its own operator -> which acts as follows. Assume that st_ptr is a pointer to a structure of type student We would refer to the name member as.
st_ptr -> name
/* Example program for using a structure*/
#include< stdio.h >
void main()
{
int id_no;
char name[20];
char address[20];
char combination[3];
int age;
}new student;
printf(”Enter the student information”);
printf(”Now Enter the student id_no”);
scanf(“%d”,&new student.id_no);
printf(“Enter the name of the student”);
scanf(“%s”,&new student.name);
printf(“Enter the address of the student”);
scanf(“%s”,&new student.address);printf(“Enter the combination of the student”);
scanf(“%d”,&new student.combination);printf(Enter the age of the student”);
scanf(“%d”,&new student.age);
printf(“Student informationn”);
printf(“student id_number=%dn”,new student.id_no);
printf(“student name=%sn”,new student.name);
printf(“student Address=%sn”,new student.address);
printf(“students combination=%sn”,new student.combination);
printf(“Age of student=%dn”,new student.age);
}
Arrays of structure:
It is possible to define a array of structures for example if we are maintaining information of all the students in the college and if 100 students are studying in the college. We need to use an array than single variables. We can define an array of structures as shown in the following example:

structure information
{
int id_no;
char name[20];
char address[20];
char combination[3];
int age;
}
student[100];

An array of structures can be assigned initial values just as any other array can. Remember that each element is a structure that must be assigned corresponding initial values as illustrated below.

#include< stdio.h >
{
structure info
{
int id_no;
char name[20];
char address[20];
char combination[3];
int age;
}
structure info std[100];
int I,n;
printf(“Enter the number of students”);
sca
nf(“%d”,&n);
printf(“ Enter Id_no,name address combination agem”);
for(I=0;I < n;I++)
scanf(“%d%s%s%s%d”,&std[I].id_no,std[I].name,std[I].address,std[I].combination,&std[I].age);
printf(“n Student information”);
for (I=0;I< n;I++)
printf(“%d%s%s%s%dn”, ”,std[I].id_no,std[I].name,std[I].address,std[I].combination,std[I].age);
}
Structure within a structure:
A structure may be defined as a member of another structure. In such structures the declaration of the embedded structure must appear before the declarations of other structures.

structure date
{
int day;
int month;
int year;
};
structure student
{
int id_no;
char name[20];
char address[20];
char combination[3];
int age;
structure date def;
structure date doa;
}oldstudent, newstudent;
the sturucture student constains another structure date as its one of its members.
UNIT- 8
Union:
Unions like structure contain members whose individual data types may differ from one another. However the members that compose a union all share the same storage area within the computers memory where as each member within a structure is assigned its own unique storage area. Thus unions are used to observe memory. They are useful for application involving multiple members. Where values need not be assigned to all the members at any one time. Like structures union can be declared using the keyword union as follows:
union item
{
int m;
float p;
char c;
}
code;
this declares a variable code of type union item. The union contains three members each with a different data type. However we can use only one of them at a time. This is because if only one location is allocated for union variable irrespective of size. The compiler allocates a piece of storage that is large enough to access a union member we can use the same syntax that we use to access structure members. That is
code.m
code.p
code.c
are all valid member variables. During accessing we should make sure that we are accessing the member whose value is currently stored.
For example a statement such as –
code.m=456;
code.p=456.78;
printf(“%d”,code.m);
Would produce erroneous result..

Enum declarations

There are two kinds of enum type declarations. One kind creates a named type, as in
enum MyEnumType { ALPHA, BETA, GAMMA };
If you give an enum type a name, you can use that type for variables, function arguments and return values, and so on:
enum MyEnumType x; /* legal in both C and C++ */
MyEnumType y; // legal only in C++
The other kind creates an unnamed type. This is used when you want names for constants but don’t plan to use the type to declare variables, function arguments, etc. For example, you can write
enum { HOMER, MARGE, BART, LISA, MAGGIE };

Values of enum constants

If you don’t specify values for enum constants, the values start at zero and increase by one with each move down the list. For example, given
enum MyEnumType { ALPHA, BETA, GAMMA };
ALPHA has a value of 0, BETA has a value of 1, and GAMMA has a value of 2.
If you want, you may provide explicit values for enum constants, as in enum Foo Size { SMALL = 10, MEDIUM = 100, LARGE = 1000 };
There is an implicit conversion from any enum type to int. Suppose this type exists:
enum MyEnumType { ALPHA, BETA, GAMMA };
Then the following lines are legal:
int i = BETA; // give i a value of 1
int j = 3 + GAMMA; // give j a value of 5
On the other hand, there is not an implicit conversion from int to an enum type:
MyEnumType x = 2; // should NOT be allowed by compiler
MyEnumType y = 123; // should NOT be allowed by compiler
Note that it doesn’t matter whether the int matches one of the constants of the enum type; the type conversion is always illegal

Typedefs

A type def in C is a declaration. Its purpose is to create new types from existing types; whereas a variable declaration creates new memory locations. Since a type def is a declaration, it can be intermingled with variable declarations, although common practice would be to state typedefs first, then variable declarations. A nice programming convention is to capitalize the first letter of a user-defined type to distinguish it from the built-in types, which all have lower-case names. Also, typedefs are usually global declarations.

Example: Use a Type def To Create A Synonym for a Type Name

type def int Integer; //Integer can now be used in place of int

int a,b,c,d; //4 variables of type int

Integer e,f,g,h; //the same thing

In general, a type def should never be used to assign a different name to a built-in type name; it just confuses the reader. Usually, a type def associates a type name with a more complicated type specification, such as an array. A type def should always be used in situations where the same type definition is used more than once for the same purpose. For example, a vector of 20 elements might represent different aspects of a scientific measurement.

Example: Use a Type def To Create A Synonym for an Array Type

type def int Vector[20]; //20 integers

Vector a,b;

int a[20], b[20]; //the same thing, but a type def is preferred

Typedefs for Enumerated Types

Every type has constants. For the “int” type, the constants are 1,2,3,4,5; for “char”, ‘a’,’b’,’c’. When a type has constants that have names, like the colors of the rainbow, that type is called an enumerated type. Use an enumerated type for computer representation of common objects that have names like Colors, Playing Cards, Animals, Birds, Fish etc. Enumerated type constants (since they are names) make a program easy to read and understand.
We know that all names in a computer usually are associated with a number. Thus, all of the names (RED, BLUE, GREEN) for an enumerated type are “encoded” with numbers. In eC, if you define an enumerated type, like Color, you cannot add it to an integer; it is not type compatible. In standard C++, anything goes. Also, in eC an enumerated type must always be declared in a typedef before use (in fact, all new types must be declared before use).

Example: Use a Typedef To Create An Enumerated Type

typedef enum {RED, BLUE, GREEN} Color;

Color a,b;

a = RED;
a = RED+BLUE; //NOT ALLOWED in eC

if ((a == BLUE) || (a==b)) cout<<"great";

Notice that an enumerated type is a code that associates symbols and numbers. The char type can be thought of as an enumeration of character codes. The default code for an enumerated type assigns the first name to the value 0 (RED), second name 1 (BLUE), third 2 (GREEN) etc. The user can, however, override any, or all, of the default codes by specifying alternative values.
UNIT 9

LINKED LIST
linked list is a chain of structure or records called nodes. Each node has at least two members, one of which points to the next item or node in the list! These are defined as Single Linked Lists because they only point to the next item, and not the previous. Those that do point to both are called Doubly Linked Lists or Circular Linked Lists. Please note that there is a distinct difference between Double Linked lists and Circular Linked lists. I won’t go into any depth on it because it doesn’t concern this tutorial. According to this definition, we could have our record hold anything we wanted! The only drawback is that each record must be an instance of the same structure. This means that we couldn’t have a record with a char pointing to another structure holding a short, a char array, and a long. Again, they have to be instances of the same structure for this to work. Another cool aspect is that each structure can be located anywhere in memory, each node doesn’t have to be linear in memory!
Linked lists are among the simplest and most common data structures, and are used to implement many important abstract data structures, such as stacks, queues, hash tables, symbolic expressions, skip lists, and many more.
What Linked Lists Look Like
An array allocates memory for all its elements lumped together as one block of memory.
In contrast, a linked list allocates space for each element separately in its own block of memory called a “linked list element” or “node”. The list gets is overall structure by using pointers to connect all its nodes together like the links in a chain.
Each node contains two fields: a “data” field to store whatever element type the list holds for its client, and a “next” field which is a pointer used to link one node to the next node.
Each node is allocated in the heap with a call to mallow(), so the node memory continues to exist until it is explicitly deal-located with a call to free(). The front of the list is a 5
pointer to the first node. Here is what a list containing the numbers 1, 2, and 3 might look
like…
Build One,Two,Three()
This drawing shows the list built in memory by the function BuildOneTwoThree() (the full source code for this function is below). The beginning of the linked list is stored in a “head” pointer which points to the first node. The first node contains a pointer to the second node. The second node contains a pointer to the third node, … and so on. The last node in the list has its .next field set to NULL to mark the end of the list. Code can access any node in the list by starting at the head and following the .next pointers. Operations towards the front of the list are fast while operations which access node farther down the list take longer the further they are from the front. This “linear” cost to access a node is fundamentally more costly then the constant time [ ] access provided by arrays. In this respect, linked lists are definitely less efficient than arrays.
Drawings such as above are important for thinking about pointer code, so most of the examples in this article will associate code with its memory drawing to emphasize the habit. In this case the head pointer is an ordinary local pointer variable, so it is drawn separately on the left to show that it is in the stack. The list nodes are drawn on the right to show that they are allocated in the heap.
The Empty List — NULL
The above is a list pointed to by head is described as being of “length three” since it is made of three nodes with the .next field of the last node set to NULL. There needs to be some representation of the empty list — the list with zero nodes. The most common representation chosen for the empty list is a NULL head pointer. The empty list case is the one common weird “boundary case” for linked list code. All of the code presented in this article works correctly for the empty list case, but that was not without some effort.
When working on linked list code, it’s a good habit to remember to check the empty list case to verify that it works too. Sometimes the empty list case works the same as all the cases, but sometimes it requires some special case code. No matter what, it’s a good case to at least think about.
Linked List Types: Node and Pointer
Before writing the code to build the above list, we need two data types…
• Node The type for the nodes which will make up the body of the list.
These are allocated in the heap. Each node contains a single client data
element and a pointer to the next node in the list. Type: struct node
struct node {
int data;
structure node* next;
};
• Node Pointer The type for pointers to nodes. This will be the type of the
head pointer and the .next fields inside each node. In C and C++, no
separate type declaration is required since the pointer type is just the node
type followed by a ‘*’. Type: structure node*
BuildOneTwoThree() Function
Here is simple function which uses pointer operations to build the list {1, 2, 3}. The
memory drawing above corresponds to the state of memory at the end of this function.
This function demonstrates how calls to mallow() and pointer assignments (=) work to
build a pointer structure in the heap.
/*
Build the list {1, 2, 3} in the heap and store
its head pointer in a local stack variable.
Returns the head pointer to the caller.
*/
struct node* BuildOneTwoThree() {
struct node* head = NULL;
struct node* second = NULL;
struct node* third = NULL;
head = malloc(sizeof(struct node)); // allocate 3 nodes in the heap
second = malloc(sizeof(struct node));
third = malloc(sizeof(struct node));
head->data = 1; // setup first node
head->next = second; // note: pointer assignment rule
second->data = 2; // setup second node
second->next = third;
third->data = 3; // setup third link
third->next = NULL;
// At this point, the linked list referenced by “head”
// matches the list in the drawing.
return head;
}

Basic concepts and nomenclature

Each record of a linked list is often called an element or node.
The field of each node that contains address of the next node is usually called the next link or next pointer. The remaining fields may be called the data, information, value, or payload fields.
The head of a list is its first node, and the tail is the list minus that node (or a pointer thereto). In Lisp and some derived languages, the tail may be called the CDR (pronounced could-R) of the list, while the payload of the head node may be called the

Linear and circular lists

In the last node of a list, the link field often contains a null reference, a special value that is interpreted by programs as meaning “there is no such node”. A less common convention is to make it point to the first node of the list; in that case the list is said to be circular or circularly linked otherwise it is said to be open or linear.

Simply-, doubly-, and multiply-linked lists


A doubly-linked list whose nodes contain three fields: an integer value, the link forward to the next node, and the link backward to the previous node
In a multiply-linked list, each node contains two or more link fields, each field being used to connect the same set of data records in a different order (e.g., by name, by department, by date of birth, etc.). (While doubly-linked lists can be seen as special cases of multiply-linked list, the fact that the two orders are opposite to each other leads to simpler and more efficient algorithms, so they are usually treated as a separate case.)

Linked lists vs. arrays

Array
Linked list
Indexing
Θ(1)
Θ(n)
Inserting / Deleting at end
Θ(1)
Θ(1) or Θ(n)
Inserting / Deleting in middle (with iterator)
Θ(n)
Θ(1)
No
Singly yes
Great
Poor
Moreover, arbitrarily many elements may be inserted into a linked list, limited only by the total memory available; while an array will eventually fill up, and then have to be resized — an expensive operation, that may not even be possible if memory is fragmented. Similarly, an array from which many elements are removed may have to be resized in order to avoid wasting too much space.
Another disadvantage of linked lists is the extra storage needed for references, which often makes them impractical for lists of small data items such as characters or Boolean values. It can also be slow, and with a naive allocator, wasteful, to allocate memory separately for each new element, a problem generally solved using memory pools.
A good example that highlights the pros and cons of using arrays vs. linked lists is by implementing a program that resolves the Josephus problem. The Josephus problem is an election method that works by having a group of people stand in a circle. Starting at a predetermined person, you count around the circle n times. Once you reach the nth person, take them out of the circle and have the members close the circle. Then count around the circle the same n times and repeat the process, until only one person is left. That person wins the election. This shows the strengths and weaknesses of a linked list vs. an array, because if you view the people as connected nodes in a circular linked list then it shows how easily the linked list is able to delete nodes (as it only has to rearrange the links to the different nodes). However, the linked list will be poor at finding the next person to remove and will need to recurse through the list until it finds that person. An array, on the other hand, will be poor at deleting nodes (or elements) as it cannot remove one node without individually shifting all the elements up the list by one. However, it is exceptionally easy to find the nth person in the circle by directly referencing them by their position in the array.

Simply-linked linear lists vs. other lists

While doubly-linked and/or circular lists have advantages over simply-linked linear lists, linear lists offer some advantages that make them preferable in some situations.
In particular, end-sentinel nodes can be shared among simply-linked non-circular lists. One may even use the same end-sentinel node for every such list. In Lisp, for example, every proper list ends with a link to a special node, denoted by nil or (), whose CAR and CDR links point to itself. Thus a Lisp procedure can safely take the CAR or CDR of any list.
Indeed, the advantages of the fancy variants are often limited to the complexity of the algorithms, not in their efficiency. A circular list, in particular, can usually be emulated by a linear list together with two variables that point to the first and last nodes, at no extra cost.

Doubly-linked vs. singly-linked

Circularly-linked vs. linearly-linked

With a circular list, a pointer to the last node gives easy access also to the first node, by following one link. Thus, in applications that require access to both ends of the list (e.g., in the implementation of a queue), a circular structure allows one to handle the structure by a single pointer, instead of two.
A circular list can be split into two circular lists, in constant time, by giving the addresses of the last node of each piece. The operation consists in swapping the contents of the link fields of those two nodes. Applying the same operation to any two nodes nodes in two distinct lists joins the two list into one. This property greatly simplifies some algorithms and data structures, such as the quad-edge and face-edge.
The simplest representation for an empty circular list (when such thing makes sense) has no nodes, and is represented by a null pointer. With this choice, many algorithms have to test for this special case, and handle it separately. By contrast, the use of null to denote an empty linear list is more natural and often creates fewer special cases.

Using sentinel nodes

Sentinel node may simplify certain list operations, by ensuring that the next and/or previous nodes exist for every element, and that even empty lists have at least one node. One may also use a sentinel node at the end of the list, with an appropriate data field, to eliminate some end-of-list tests. For example, when scanning the list looking for a node with a given value x, setting the sentinel’s data field to x makes it u
nnecessary to test for end-of-list inside the loop. Another example is the merging two sorted lists: if their sentinels have data fields set to +∞, the choice of the next output node does not need special handling for empty lists.
However, sentinel nodes use up extra space (especially in applications that use many short lists), and they may complicate other operations (such as the creation of a new empty list).
However, if the circular list is used merely to simulate a linear list, one may avoid some of this complexity by adding a single sentinel node to every list, between the last and the first data nodes. With this convention, an empty list consists of the sentinel node alone, pointing to itself via the next-node link. The list handle should then be a pointer to the last data node, before the sentinel, if the list is not empty; or to the sentinel itself, if the list is empty.
The same trick can be used to simplify the handling of a doubly-linked linear list, by turning it into a circular doubly-linked list with a single sentinel node. However, in this case, the handle should be a single pointer to the dummy node itself.

Linked list operations

When manipulating linked lists in-place, care must be taken to not use values that you have invalidated in previous assignments. This makes algorithms for inserting or deleting linked list nodes somewhat subtle. This section gives pseudo code for adding or removing nodes from singly, doubly, and circularly linked lists in-place. Throughout we will use null to refer to an end-of-list marker or sentinel, which may be implemented in a number of ways.

Linearly-linked lists

Singly-linked lists

Our node data structure will have two fields. We also keep a variable first Node which always points to the first node in the list, or is null for an empty list.
record Node {
data // The data being stored in the node
}
record List {
Node first Node // points to first node of list; null for empty list
}
Traversal of a singly-linked list is simple, beginning at the first node and following each next link until we come to the end:
node := list.first Node
while node not null {
(do something with node.data)
node := node.next
}
The following code inserts a node after an existing node in a singly linked list. The diagram shows how it works. Inserting a node before an existing one cannot be done; instead, you have to locate it while keeping track of the previous node.

function insert After(Node node, Node new Node) { // insert new Node after node
newNode.next := node.next
node.next := newNode
}
Inserting at the beginning of the list requires a separate function. This requires updating first Node.
function insert Beginning(List list, Node newNode) { // insert node before current first node
newNode.next := list.first Node
list.first Node := newNode
}
Similarly, we have functions for removing the node after a given node, and for removing a node from the beginning of the list. The diagram demonstrates the former. To find and remove a particular node, one must again keep track of the previous element.
function remove After(node node) { // remove node past this one
obsolete Node := node.next
node.next := node.next.next
destroy obsolete Node
}
function remove Beginning(List list) { // remove first node
obsolete Node := list.first Node
list.first Node := list.first Node.next // point past deleted node
destroy obsolete Node
}
Notice that remove Beginning() sets list.first Node to null when removing the last node in the list.
Since we can’t iterate backwards, efficient “insertBefore” or “removeBefore” operations are not possible.
Appending one linked list to another can be inefficient unless a reference to the tail is kept as part of the List structure, because we must traverse the entire first list in order to find the tail, and then append the second list to this. Thus, if two linearly-linked lists are each of length n, list appending has asymptotic time complexity of O(n). In the Lisp family of languages, list appending is provided by the append procedure.
Many of the special cases of linked list operations can be eliminated by including a dummy element at the front of the list. This ensures that there are no special cases for the beginning of the list and renders both insertBeginning() and removeBeginning() unnecessary. In this case, the first useful data in the list will be found at list.firstNode.next.

Circularly-linked list

In a circularly linked list, all nodes are linked in a continuous circle, without using null. For lists with a front and a back (such as a queue), one stores a reference to the last node in the list. The next node after the last node is the first node. Elements can be added to the back of the list and removed from the front in constant time.
Circularly-linked lists can be either singly or doubly linked.
Both types of circularly-linked lists benefit from the ability to traverse the full list beginning at any given node. This often allows us to avoid storing firstNode and lastNode, although if the list may be empty we need a special representation for the empty list, such as a lastNode variable which points to some node in the list or is null if it’s empty; we use such a lastNode here. This representation significantly simplifies adding and removing nodes with a non-empty list, but empty lis
ts are then a special case.

circularly-linked lists

Assuming that someNode is some node in a non-empty circular simply-linked list, this code iterates through that list starting with someNode:
function iterate(someNode)
if someNode ≠ null
node := someNode
do
do something with node.value
node := node.next
while node ≠ someNode
Notice that the test “while node ≠ someNode” must be at the end of the loop. If it were replaced by the test “” at the beginning of the loop, the procedure would fail whenever the list had only one node.
This function inserts a node “newNode” into a circular linked list after a given node “node”. If “node” is null, it assumes that the list is empty.
function insertAfter(Node node, Node newNode)
if node = null
newNode.next := newNode
else
newNode.next := node.next
node.next := newNode
Suppose that “L” is a variable pointing to the last node of a circular linked list (or null if the list is empty). To append “newNode” to the end of the list, one may do
insertAfter(L, newNode)
L = newNode
To insert “newNode” at the beginning of the list, one may do
insertAfter(L, newNode)
if L = null
L = newNode

Linked lists using arrays of nodes

As an example, consider the following linked list record that uses arrays instead of pointers:
record Entry {
integer next; // index of next entry in array
integer prev; // previous entry (if double-linked)
string name;
real balance;
}
By creating an array of these structures, and an integer variable to store the index of the first element, a linked list can be built:
integer listHead;
Entry Records[1000];
Links between elements are formed by placing the array index of the next (or previous) cell into the Next or Prev field within a given element. For example:
Index
Next
Prev
Name
Balance
0
1
4
Jones, John
123.45
1
-1
0
Smith, Joseph
234.56
2 (listHead)
4
-1
Adams, Adam
0.00
3
Ignore, Ignatius
999.99
4
0
2
Another, Anita
876.54
5
6
7

In the above example, ListHead would be set to 2, the location of the first entry in the list. Notice that entry 3 and 5 through 7 are not part of the list. These cells are available for any additions to the list. By creating a ListFree integer variable, a free list could be created to keep track of what cells are available. If all entries are in use, the size of the array would have to be increased or some elements would have to be deleted before new entries could be stored in the list.
The following code would traverse the list and display names and account balance:
i := listHead;
while i >= 0 { ‘// loop through the list
print i, Records[i].name, Records[i].balance // print entry
i = Records[i].next;
}
When faced with a choice, the advantages of this approach include:
This approach has one main disadvantage, however: it creates and manages a private memory space for its nodes. This leads to the following issues:
  • It increase complexity of the implementation.
  • Growing a large array when it is full may be difficult or impossible, whereas finding space for a new linked list node in a large, general memory pool may be easier.
  • Adding elements to a dynamic array will occasionally (when it is full) unexpectedly take linear (O (n)) instead of constant time (although it’s still an amortized constant).
  • Using a general memory pool leaves more memory for other data if the list is smaller than expected or if many nodes are freed.
For these reasons, this approach is mainly used for languages that do not support dynamic memory allocation. These disadvantages are also mitigated if the maximum size of the list is known at the time the array is created.

Language support

#include /* for printf */
#include /* for malloc */
struct node
{
int data;
struct node *next; /* pointer to next element in list */
}
struct node *list_add(struct node **p, int i)
{
struct node *n = malloc(sizeof(struct node))
if (n == NULL)
return NULL
n->next = *p; /* the previous element (*p) now becomes the “next” element */
*p = n; /* add new empty element to the front (head) of the list */
n->data = i;
return *p;
}
void list_remove(struct node **p) /* remove head */
{
if (*p != NULL)
{
struct node *n = *p;
*p = (*p)->next;
free(n)
}
}
struct node **list_search(struct node **n, int i)
{
while (*n != NULL)
{
if ((*n)->data == i)
{
return n;
}
n = &(*n)->next;
}
return NULL
}
void list_print(struct node *n)
{
if (n == NULL)
{
printf(“list is emptyn)
}
while (n != NULL)
{
printf(“print %p %p %dn, n, n->next, n->data)
n = n->next;
}
}
int main(void)
{
struct node *n = NULL
list_add(&n, 0) /* list: 0 */
list_add(&n, 1) /* list: 1 0 */
list_add(&n, 2) /* list: 2 1 0 */
list_add(&n, 3) /* list: 3 2 1 0 */
list_add(&n, 4) /* list: 4 3 2 1 0 */
list_print(n)
list_remove(&n) /* remove first (4) */
list_remove(&n->next) /* remove new second (2) */
list_remove(list_search(&n, 1)) /* remove cell containing 1 (first) */
list_remove(&n->next) /* remove second to last node (0) */
list_remove(&n) /* remove last (3) */
list_print(n)
return 0




');}
Bc0138c3d2dab0944d91d638547c2715

subscriber

Leave a Reply

Your email address will not be published. Required fields are marked *

Accept Our Privacy Terms.*