I updated my linked list development, and committed it to the Subversion repository.
There is an
lab46:~/src/data$ svn commit -m "Updated linkedLinst1-jr.c to include delete node, append, ans insert. Thes functions need work as they do not handle the end node or the next to end node correctly -jr" Sending data/linkedList1-jr.c Transmitting file data . Committed revision 10.
After verifying my linked list library, I then added the linkedListLibrary directory and its files to the Subversion repository.
lab46:~/src/data$ svn add linkedListLibrary A linkedListLibrary A linkedListLibrary/linkedListLib.c A linkedListLibrary/linkedList-jr.c A linkedListLibrary/linkedListLib.h A linkedListLibrary/linkedListTest.c A (bin) linkedListLibrary/linkedListTest lab46:~/src/data$
After adding the linked list library files to the Subversion repository, I committed them as well.
lab46:~/src/data$ svn commit -m "linked list library, linkedListLib.a, contains the following functions: createList, destroyListHead, destroyListTail, listSizeHead, listSizeTail, printIntDataHead, insert, append, deleteNode, void loadListData, loadNode, createNode, copyList, findData, which have all been verified -John Rine" Sending data/linkedList1-jr.c Adding data/linkedListLibrary Adding data/linkedListLibrary/linkedList-jr.c Adding data/linkedListLibrary/linkedListLib.c Adding data/linkedListLibrary/linkedListLib.h Adding (bin) data/linkedListLibrary/linkedListTest Adding data/linkedListLibrary/linkedListTest.c Transmitting file data ...... Committed revision 11. lab46:~/src/data$
I am now finalizing my linked list project page which is at:
http://lab46.corning-cc.edu/user/jr018429/portfolio/libdll .
I learned to use a single .h file to prototye all of my functions and the node structure for all of my library files. Below is a record of the steps I went through to get there.
I successfully created and used a static linked list library, or so I thought, when I finalized my linked list project. However, when it came to implementing a static library of stack routines and associated data type, I had a horrible time. every library file wanted a node structure in it however when I linked the library files together, I got error messages! I had to figure out a way to have only one node struct reference that I could share with the library files. I appealed to the instructor for help!
Date: Wed, 12 Oct 2011 19:54:26 -0400 (EDT) From: John Rine <jr018429@lab46.corning-cc.edu> To: wedge@lab46.corning-cc.edu, haas@corning-cc.edu Subject: static library HELP!!!!! I am trying to finish my stack library and mange all the crap going on in my personal life and it ain't going very good. I think I got lucky compiling and linking the linked List library. I am having a time with the stack. I took a different approach with it. I am having many library files with names describing the functions inside. For example: createFixedStack.c createFixedStack.h listStackSize.c listStackSize.h destroyFixedStack.c destroyFixedStack.h I also have a test program named: stackTest.c please look closely at the #include "..." in the files, also look closely at the way I created the static library. What am I doing wrong????? I can't find any good examples on the Internet. My issues are compounded by having a struct. please look closely at how the struct is included in the includes. I took copious notes. From you class, I got: main #include "mything.h" how does "mything.h in the test program relate to multiple include files?? I also got the following: ar rcs libdll.a *.o How does libdll relate to "mything.h" in the test program? I am missing something!!!! in stackTest.c I am declaring the individual .h files: #include "createFixedStack.h" #include "destroyFixedStack.h" #include "listStackSize.h" I successfully created .o files for these libraries using the following: lab46:~/Stack$ gcc -c createFixedStack.c -o createFixedStack.o lab46:~/Stack$ gcc -c destroyFixedStack.c -o destroyFixedStack.o lab46:~/Stack$ gcc -c listStackSize.c -o listStackSize.o Then I can successfully create a static library using: lab46:~/Stack$ ar rcs libStackJRdll.a *.o Code and includes //createFixedStack.h //John T. Rine //October 12, 2011 #ifndef _CREATEFIXEDSTACK_JR_H #define _CREATEFIXEDSTACK_JR_H #include<stdio.h> #include<stdlib.h> struct Node { int data; struct Node * prev; struct Node * next; }; typedef struct Node node; void createFiixedStackList(node **, node **, int); #endif //createFixedStack.c //John T. Rine //October 12, 2011 #include<stdlib.h> #include<stdio.h> #include"createFixedStack.h" void createFixedStack(node **head, node **tail, int elements) { int i; node *new; new = NULL; *head = *tail = NULL; for(i = 1; i<=elements; i++) { if (*head == NULL) { *head = (node *) malloc(sizeof(node)); *tail = *head; (*head)->prev = NULL; (*head)->next = NULL; } else { new = (node *) malloc(sizeof(node)); new->prev = *tail; new->next = NULL; (*tail)->next = new; *tail = new; } } } //destroyFixedStack.h //John T. Rine //October 12, 2011 #ifndef _DESTROYFIXEDSTACK_JR_H #define _DESTROYFIXEDSTACK_JR_H #include<stdio.h> #include<stdlib.h> struct Node { int data; struct Node * prev; struct Node * next; }; typedef struct Node node; void destroyFixedStackHead(node *); void destroyFixedStackTail(node *); #endif //destroyFixedStack.c //John T. Rine //October 12, 2011 #include<stdlib.h> #include<stdio.h> #include "destroyFixedStack.h" void destroyFixedStackHead(node *head) { node *temp; node *temp2; temp = NULL; temp2 = NULL; temp = head; while(temp != NULL) { temp2 = temp->next; if (temp->prev != NULL) temp->prev = NULL; if (temp->next != NULL) temp->next = NULL; free(temp); temp = temp2; } } void destroyFixedStackTail(node *tail) { node *temp; node *temp2; temp = NULL; temp2 = NULL; temp = tail; while(temp != NULL) { temp2 = temp->prev; if (temp->prev != NULL) temp->prev = NULL; if (temp->next != NULL) temp->next = NULL; free(temp); temp = temp2; } } //listStackSize.h //John T. Rine //October 12, 2011 #ifndef _LISTSTACKSIZE_JR_H #define _LISTSTACKSIZE_JR_H #include<stdio.h> #include<stdlib.h> struct Node { int data; struct Node * prev; struct Node * next; }; typedef struct Node node; int listStackSizeHead(node *); int listStackSizeTail(node *); #endif //listrStackSize.c //John T. Rine //October 12, 2011 #include<stdlib.h> #include<stdio.h> #include"listStackSize.h" int listStackSizeHead(node *head) { int size = 0; while (head != NULL) { head = head->next; size++; } return size; } int listStackSizeTail(node *tail) { int size = 0; while (tail != NULL) { tail = tail->prev; size++; } return size; } //stackTest.c //Author: John T. Rine //Date: October 12, 2011 #include "createFixedStack.h" #include "destroyFixedStack.h" #include "listStackSize.h" int main(int argc, char **argv) { node *head, *tail; head = tail = NULL; printf("Creating a list of 10 nodes...\n"); createFixedStack(&head, &tail, 10); getchar(); //Holds the console window open on a Windows machine } However when I try to create the test executable, it bombs-HELP!!! John T. Rine Graduate Electrical Technology-Electronics Graduate General Studies --- Lab46: Penguin Powered
I finally figured that I could create a struct .h file to define the node structure and then include that .h file in my lother library files. Sure enough, it worked!
Date: Thu, 13 Oct 2011 10:40:10 -0400 From: Matthew Haas <wedge@lab46.corning-cc.edu> To: John Rine <jr018429@lab46.corning-cc.edu> Subject: Re: static library HELP!!!!! (fwd) On Oct 12, 2011, at 11:34 PM, John Rine wrote: I got it. The issue is that the structure used as a node is shared throughout all of the functions. When you break them up, you can't include the structure in every .h file, so what you do is to creat e a structure.h file and include that in the broken up files. Its seems you also need it in the test file as well. Man did that was driving me crazy.
</cli> My instructor pointed out, however, that I could have simply made one .h file for all of my library files! Why didn't I think of that?
Date: Thu, 13 Oct 2011 10:40:10 -0400 From: Matthew Haas <wedge@lab46.corning-cc.edu> To: John Rine <jr018429@lab46.corning-cc.edu> Subject: Re: static library HELP!!!!! (fwd) Parts/Attachments: 1 OK ~61 lines Text 2 Shown ~62 lines Text ---------------------------------------- On Oct 12, 2011, at 11:34 PM, John Rine wrote: I got it. The issue is that the structure used as a node is shared throughout all of the functions. When you break them up, you can't include the structure in every .h file, so what you do is to creat e a structure.h file and include that in the broken up files. Its seems you also need it in the test file as well. Man did that was driving me crazy. John, You may have appeared to resolve the issue, but I think the situation is still inordinately complex and can be simplified. For your stack library, you should be able to get away with just 1 header file, let's call it: stack.h stack.h can look as follows: ------------------------------------- #ifndef _STACK_H #define _STACK_H #include "linkedlist.h" struct stack { struct list *data; struct node *top; }; typedef struct stack Stack; Node *pop(Stack *); int push(Stack *, Node *); Node *peek(Stack *); int isEmpty(Stack *); #endif ------------------------------------- All your .c files can just #include "stack.h", which will take care of all the function prototypes, struct definition, and even pull in the linked list stuff for you (the linkedlist.h file will similarly have #ifndef _LINKED_LIST_H guards). With so many header files, the way you seem to be approaching it might be creating a lot more managerial work for yourself... let the preprocessor take care of it for you. Is this code on Lab46? I took a quick peek and couldn't find it. -Matthew -- Matthew Haas Lab46 System Administrator Instructor of Computer & Information Science http://lab46.corning-cc.edu/haas/home/ [lab46.corning-cc.edu]
I finally finished my doubly linked stack library project :) !!!
It is available at:
http://lab46.corning-cc.edu/user/jr018429/portfolio/stack
I learned about implementing stacks using doubly linked structure
node structures. I also learned how to use a single .h file for
all library function prototypes and the library node structure definition.
I also learned that another more complicated way of implementing the library would
be to create a strucure .h file which defines the node structure and then
including that in the other library files, assuming one is using a .h
file per library .c file. Yet another way might be to include the node
structure definition in each .h file but wrap it in a #ifndef, #define,
#endif block as follows:
#ifndef _NODESTRUCT_H #define _NODESTRUCT_H struct Node { int data; node *next; node *prev; } #endif
State machines are ubiquitous in programming and in hardware design-synchronous digital logic design. I found a very good tutorial on statemachine design at: http://johnsantic.com/comp/state.html .
I shared this link and what I know about state-machines with my Data Structures and Systems Programming classes.
Date: Wed, 19 Oct 2011 23:06:46 -0400 (EDT) From: John Rine <jr018429@lab46.corning-cc.edu> To: data@lab46.corning-cc.edu, sys@lab46.corning-cc.edu Subject: State Machines in Programming Check out this link on state machines: http://johnsantic.com/comp/state.html State machines are a very import concept in both hardware and software design. Stae machines are either, in the case of hardware, clock driven or in software, loop, or interrupt driven. State machines store their last state and then compare this last state to input and if defined in their design, will change state when triggered by a clock, loop, or interrupt. State machines implemented in software can be used to perform hardware control, for example machine tool and robotics software. Soft state machines can be used in game design such that game flow changes based on the game's previous state and input from the player. One way to implement state machines in software by combining loop and selecttion structures. In hardware they are implemented using a register (flip-flops) and decoding logic. Why even discuss a hardware implement here? Well as we learned last sememmster in Computer Organizations, hardware can be simulated in software! The decoding logic of a hardware defined state machine decodes the outputs of the state register (output and state storage) and input and caauses the state register's state to change when the output state and inputs change to some value defined by the design. Even though a synchronous counter is not considered to be a state machine, it may be helpful as an analogy to understanding them. A synchronous counter is reset when firat powered up. The decoding circuitry sees 0 on the out put of the counter and decodes this value to be 1 on the input. On the next clock pulse, the counter changes to 1 on its output. now the decoding circuitry sees 1 on the output and decodes this to 2 on the input. When the next clock tick occurs, the output changes to 3 and so on... To get to a state machine from a synchronous counter, simply add inouts from the outside to the ddecoding circuitry. Now consider a hardware state machine, on power up the state machine's outputs are set to 0. Now if a sensor on an input changes state, when the next clock pulse occurs and if the decoding circuitry is designed to do so, a state machine output will change in response to the sensor's input. This output will maintain its state until the decoding logic coupled with certain input states associate with the decoding design and a clock pulse causes it to change. There are two types of hardware state machines: 1. Moore, and 2. Meally At least one author has described the cpu as a state machine. I am sure I have made the subject of state machines as clear as mud. John T. Rine Graduate Electrical Technology-Electronics Graduate General Studies --- Lab46: Penguin Powered
I added and committed my forkExample.c program to the Subversion repository.
lab46:~/src/sysprog$ svn add forkExample.c A forkExample.c lab46:~/src/sysprog$ svn commit -m "Added and commited a simple example of using fork -John Rine" Adding sysprog/forkExample.c Transmitting file data . Committed revision 16.
I added and committed my useMalloc.c program to the Subversion repository.
lab46:~/src/data$ svn add useMalloc.c A useMalloc.c lab46:~/src/data$ svn commit -m "Added and committed useMalloc.c, an example program demonstrating dynamic memory allocation of structures and arrays -John Rine" Sending data/Stack/libdll.a Adding data/useMalloc.c Transmitting file data .. Committed revision 17. lab46:~/src/data$
I conducted and documented an experiment to determine if a string literal could be assigned to a pointer pointing to dynamically allocated memory and then be used in a program, then when the data is no longer needed, deallocate it.
The experiment is documented in Part II, experiment 1.
I added and committed the code I wrote to implement an array-based stack data structure.
lab46:~/src/data$ svn add arrayStack.c A arrayStack.c lab46:~/src/data$ svn commit -m "Added and committed an array-based stack program. -John Rine" Adding data/arrayStack.c Sending data/useMalloc.c Transmitting file data .. Committed revision 18. lab46:~/src/data$
I added and committed the code I wrote to design and test doubly-linked list functions.
lab46:~/src/data$ svn add linkedListDev.c A linkedListDev.c lab46:~/src/data$ svn commit -m "Added and committed linkedListDev.c, a linked list development program -John Rine" Adding data/linkedListDev.c Transmitting file data . Committed revision 19. lab46:~/src/data$
I added and committed the code I wrote to learn about threads.
lab46:~/src/sysprog$ svn add threadTest.c A threadTest.c lab46:~/src/sysprog$ svn commit -m "Added and committed threadTest.c a program to illustrate thread creation and termination -John Rine" Sending sysprog/interface.c Adding sysprog/threadTest.c Transmitting file data .. Committed revision 20. lab46:~/src/sysprog$
I added and committed the code I wrote to implement an array-based queue.
lab46:~/src/data$ svn add queueTest.c A queueTest.c lab46:~/src/data$ svn commit -m "Added and committed an array-based example of a queue -John T. Rine" Adding data/queueTest.c Transmitting file data . Committed revision 21. lab46:~/src/data$
I entered my part deux (II) course objectives for systems programming and data structures courses. I also completed my third experiment for part II. I also wrote system programming topic information for the synchronization methods mutex, and barrier.
malloc is a c library function for dynamically allocating memory in the “heap”.
dynamically allocated memory is memory that has been set aside for use during the execution of the program, also know as “run time”.
malloc can be used to dynamically allocate variables as well as arrays, including multidimensional arrays and structures. The malloc function becomes available for use in a program after the stdlib.h header has been added to the program.
//useMalloc.c //John T. Rine //October 23, 2011 #include<stdlib.h> #include<stdio.h> struct Test { char *message1; char *message2; }; typedef struct Test test; int main(int argc, char **argv) { //malloc a struct test *testPTR; testPTR = (test *)malloc(sizeof(test)); testPTR->message1 = "Hello "; testPTR->message2 = "world!"; printf("Message1 = %s, message2 = %s\n", testPTR->message1, testPTR->message2); free(testPTR); //malloc a char array int i = 0; int ii = 0; char * inputString = "John T. Rine\0"; char * string = NULL; printf("input string contains %s\n", inputString); while(*(inputString + i) != '\0') i++; printf("Character count = %d\n", i); string = (char *)malloc(sizeof(char) * (i + 1)); for(ii = 0; ii <= (i + 1); ii++) *(string + ii) = *(inputString + ii); printf("Dynamically allocated array contains %s\n", string); free(string); return 0; }
Compilation and execution of useMalloc.c were successful as seen below.
lab46:~/src/data$ ./useMalloc Message1 = Hello , message2 = world! input string contains John T. Rine Character count = 12 Dynamically allocated array contains John T. Rine lab46:~/src/data$
Since the data structures class is now making copious use of dynamically allocated memory using malloc and free to allocate and deallocate memory to make, manage, and destroy linked lists, stacks, quesues and so on, wouldn't it be a good idea to understand what the heap is, and how its used?
Dynamically allocated memory is usually allocated from a pool of unused memory known as the “heap” or “free store”. Because the exact memory address of a dynamic memory allocation is not known in advance, dynamically allocated memory is accessed indirectly through the use of pointers.
The exact method used to organize the heap and allocate and deallocate parts of it is hidden behind an abstract interface.
The stack is a last in, first out (LIFO) data structure. A stack can have any data type, including structures as elements, but has only a few basic operations which can be performed on it: initialize or create, push, pop and peek. The initialize or create operation creates a stack and initializes it. The push operation adds a new item to the top of the stack. The pop operation removes an item from the top of the stack. The stack peek operation gets the data from the top of the stack without deleting it or changing the stack pointer.
//arrayStack.c //John T. Rine //October 28, 2011 #include<stdio.h> #include<stdlib.h> struct Stack { char *array; int top; int size; }; typedef struct Stack stack; int cntChars(char *); void createStack(stack *, int); void push(stack *, char); char pop(stack *); int isEmpty(stack *); int isFull(stack *); int main(int argc, char **argv) { int i; int count; stack newStack; char stringArray[200]; printf("Enter a string: "); gets(stringArray); count = cntChars(stringArray); createStack(&newStack, count); if(isEmpty(&newStack)) printf("Stack is empty\n"); else printf("Stack is not empty\n"); for(i = 0; i < count; i++) { push(&newStack,stringArray[i]); printf("The character going into tos is: %c\n", newStack.array[i]); } if(isEmpty(&newStack)) printf("Stack is empty\n"); else printf("Stack is not empty\n"); for(i = 0; i < count; i++) printf("The character in tos is: %c\n", pop(&newStack)); for(i = 0; i < count; i++) { push(&newStack,stringArray[i]); printf("The character going into tos is: %c\n", newStack.array[i]); } push(&newStack,'H'); return 0; } int cntChars(char *inputString) { // returned value "count" does not include '\0' int count = 0; while(*(inputString + count) != '\0') ++count; return(count); } void createStack(stack *stackVar, int size) { char *array; array = (char *)malloc(sizeof(char) * size); if (array == NULL) { fprintf(stderr, "Not enough memory to create the stack.\n"); exit(1); } stackVar->array = array; stackVar->size = size; stackVar->top = -1; } int isEmpty(stack *stackVar) { return stackVar->top < 0; } int isFull(stack *stackVar) { return stackVar->top >= stackVar->size - 1; } void push(stack *stackVar, char element) { if (isFull(stackVar)) { fprintf(stderr, "Can't push on the stack is full\n"); exit(1); } stackVar->array[++stackVar->top] = element; } char pop(stack *stackVar) { if (isEmpty(stackVar)) { fprintf(stderr, "Can't pop from stack; stack is empty\n"); exit(1); } return stackVar->array[stackVar->top--]; }
Execution of the source code listed above with the string “Oh no! I have just been Rick rolled!” as input.
lab46:~/src/data$ gcc arrayStack.c -o arrayStack /tmp/cczFb9N2.o: In function `main': arrayStack.c:(.text+0x35): warning: the `gets' function is dangerous and should not be used. lab46:~/src/data$ ./arrayStack Enter a string: Oh no! I have just been Rick rolled! Stack is empty The character going into tos is: O The character going into tos is: h The character going into tos is: The character going into tos is: n The character going into tos is: o The character going into tos is: ! The character going into tos is: The character going into tos is: I The character going into tos is: The character going into tos is: h The character going into tos is: a The character going into tos is: v The character going into tos is: e The character going into tos is: The character going into tos is: j The character going into tos is: u The character going into tos is: s The character going into tos is: t The character going into tos is: The character going into tos is: b The character going into tos is: e The character going into tos is: e The character going into tos is: n The character going into tos is: The character going into tos is: R The character going into tos is: i The character going into tos is: c The character going into tos is: k The character going into tos is: The character going into tos is: r The character going into tos is: o The character going into tos is: l The character going into tos is: l The character going into tos is: e The character going into tos is: d The character going into tos is: ! Stack is not empty The character in tos is: ! The character in tos is: d The character in tos is: e The character in tos is: l The character in tos is: l The character in tos is: o The character in tos is: r The character in tos is: The character in tos is: k The character in tos is: c The character in tos is: i The character in tos is: R The character in tos is: The character in tos is: n The character in tos is: e The character in tos is: e The character in tos is: b The character in tos is: The character in tos is: t The character in tos is: s The character in tos is: u The character in tos is: j The character in tos is: The character in tos is: e The character in tos is: v The character in tos is: a The character in tos is: h The character in tos is: The character in tos is: I The character in tos is: The character in tos is: ! The character in tos is: o The character in tos is: n The character in tos is: The character in tos is: h The character in tos is: O The character going into tos is: O The character going into tos is: h The character going into tos is: The character going into tos is: n The character going into tos is: o The character going into tos is: ! The character going into tos is: The character going into tos is: I The character going into tos is: The character going into tos is: h The character going into tos is: a The character going into tos is: v The character going into tos is: e The character going into tos is: The character going into tos is: j The character going into tos is: u The character going into tos is: s The character going into tos is: t The character going into tos is: The character going into tos is: b The character going into tos is: e The character going into tos is: e The character going into tos is: n The character going into tos is: The character going into tos is: R The character going into tos is: i The character going into tos is: c The character going into tos is: k The character going into tos is: The character going into tos is: r The character going into tos is: o The character going into tos is: l The character going into tos is: l The character going into tos is: e The character going into tos is: d The character going into tos is: ! Can't push on the stack is full lab46:~/src/data$
A linked list is a data structure whose elements each contain pointers to other elements in the linked list. There are singly-linked lists whose pointers only point in one direction, and doubly-linked lists which has pointers pointing in the direction of head and pointers which point in the direction of the tail. The list is traversed using the pointers contained in the node.
For example, a list can be traversed from the head using the “next” pointer as follows:
temp = head; while(temp != NULL) //while temp is not at the end of the list { printf("%d ",temp->data); //printf the value of the data in the current node temp = temp->next; //load temp with the address of the next node }
//linkedListDev.c //John T. Rine //October 28, 2011 #include<stdio.h> #include<stdlib.h> struct Node { int data; struct Node * prev; struct Node * next; }; typedef struct Node node; void createList(node **, node **, int); void destroyListHead(node *); void destroyListTail(node *); int listSizeHead(node *); int listSizeTail(node *); void printIntDataHead(node *); void insert(node **, node **, int, int); void append(node **, node **, int, int); void deleteNode(node **, node **, int); void loadListData(node *); void loadNode(node *, int, int); void createNode(node*, node*); void copyList(node *, node **, node **); int findData(node *, int); int main(int argc, char **argv) { node *head, *tail, *copyHead, *copyTail, *temp; head = tail = copyHead = copyTail = NULL; int i = 1; printf("Creating a list of 4 nodes...\n"); createList(&head, &tail, 4); printf("Size of the list is: %d\n", listSizeHead(head)); printf("Load list data\n"); loadListData(head); printIntDataHead(head); printf("Inserting node 0 with data of 3200 before head node...\n"); insert(&head, &tail, 0, 3200); printf("Size of the list is: %d\n", listSizeHead(head)); printIntDataHead(head); printf("Inserting node with data of -3200 before tail node...\n"); insert(&head, &tail, listSizeHead(head) - 1, -3200); printf("Size of the list is: %d\n", listSizeHead(head)); printIntDataHead(head); printf("Appending node with data of 2300 after head node...\n"); append(&head, &tail, 0, 2300); printf("Size of the list is: %d\n", listSizeHead(head)); printIntDataHead(head); printf("Appending node with data of -2300 after tail node...\n"); append(&head, &tail, listSizeHead(head) - 1, -2300); printf("Size of the list is: %d\n", listSizeHead(head)); printIntDataHead(head); printf("Loading node 0 with data of 0...\n"); loadNode(head, 0, 0); printf("Size of the list is: %d\n", listSizeHead(head)); printIntDataHead(head); printf("Loading tail node with data of 255...\n"); loadNode(head, listSizeHead(head) - 1, 255); printf("Size of the list is: %d\n", listSizeHead(head)); printIntDataHead(head); printf("Deleting head node...\n"); deleteNode(&head, &tail, 0); printf("Size of the list is: %d\n", listSizeHead(head)); printIntDataHead(head); printf("Deleting tail node...\n"); deleteNode(&head, &tail, listSizeHead(head) - 1); printf("Size of the list is: %d\n", listSizeHead(head)); printIntDataHead(head); printf("Deleting node 2...\n"); deleteNode(&head, &tail, 2); printf("Size of the list is: %d\n", listSizeHead(head)); printIntDataHead(head); copyList(head, ©Head, ©Tail); printf("Size of the list is: %d\n", listSizeHead(copyHead)); printIntDataHead(copyHead); printf("The node location of 3 is %d\n", findData(copyHead, 3)); destroyListHead(head); return 0; } void createList(node **headd, node **taill, int elements) { int i; node *new, *head, *tail; new = head = tail = NULL; for(i = 1; i<=elements; i++) { if (head == NULL) { head = (node *) malloc(sizeof(node)); tail = head; head->prev = NULL; head->next = NULL; } else { new = (node *) malloc(sizeof(node)); new->prev = tail; new->next = NULL; tail->next = new; tail = new; } } *headd = head; *taill = tail; } void destroyListHead(node *head) { node *temp; node *temp2; temp = NULL; temp2 = NULL; temp = head; while(temp != NULL) { temp2 = temp->next; if (temp->prev != NULL) temp->prev = NULL; if (temp->next != NULL) temp->next = NULL; free(temp); temp = temp2; } } void destroyListTail(node *tail) { node *temp; node *temp2; temp = NULL; temp2 = NULL; temp = tail; while(temp != NULL) { temp2 = temp->prev; if (temp->prev != NULL) temp->prev = NULL; if (temp->next != NULL) temp->next = NULL; free(temp); temp = temp2; } } int listSizeHead(node *head) { int size = 0; while (head != NULL) { head = head->next; size++; } return size; } int listSizeTail(node *tail) { int size = 0; while (tail != NULL) { tail = tail->prev; size++; } return size; } void printIntDataHead(node * head) { node * temp = NULL; temp = head; while(temp != NULL) { printf("%d ",temp->data); temp = temp->next; } printf("\n"); } void insert(node ** head, node ** tail, int position, int data) { int i; node *temp, *temp2; temp = temp2 = NULL; temp = *head; for(i = 0; i < position; i++) { temp = temp -> next; } if (*head == NULL) { *head = (node *) malloc(sizeof(node)); *tail = *head; (*head)->prev = NULL; (*head)->next = NULL; (*head)->data = data; } else if (*head == temp) { temp2 = (node *) malloc (sizeof(node)); temp2->next = *head; (*head)->prev = temp2; *head = (*head)->prev; (*head)->prev = NULL; (*head)->data = data; } else { temp2 = (node *) malloc (sizeof(node)); temp2->next = temp; temp2->prev = temp->prev; temp->prev->next = temp2; temp->prev = temp2; temp2->data = data; } } void append(node **head, node **tail, int position, int data) { int i; node *temp, *temp2; temp = temp2 = NULL; temp = *head; for(i = 0; i < position; i++) { temp = temp -> next; } if (*head == NULL) { *head = (node *) malloc(sizeof(node)); *tail = *head; (*head)->prev = NULL; (*head)->next = NULL; (*head)->data = data; } else if (*tail == temp) { temp2 = (node *) malloc (sizeof(node)); temp2->prev = *tail; temp2->next = NULL; (*tail)->next = temp2; *tail = temp2; (*tail)->data = data; } else { temp2 = (node *) malloc (sizeof(node)); temp2->prev = temp; temp2->next = temp->next; temp->next->prev = temp2; temp->next = temp2; temp2->data = data; } } void deleteNode(node **head, node **tail, int position) { int i; node * temp = NULL; temp = *head; for(i = 0; i < position; i++) { temp = temp->next; } if(temp != *head && temp != *tail) { temp->next->prev = temp->prev; temp->prev->next = temp->next; temp->prev = NULL; temp->next = NULL; } else if (temp == *head) { temp->next->prev = NULL; *head = temp->next; temp->next = NULL; } else { temp->prev->next = NULL; *tail = temp->prev; temp->prev = NULL; } free(temp); } void loadListData(node *head) { int i = 0; node *temp = NULL; temp = head; printf("Enter a value or -1 to quit: "); scanf("%d", &i); while(i != -1) { temp->data = i; temp = temp->next; if(temp == NULL) { printf("List is full of data!\n"); break; } printf("Enter a value or -1 to quit: "); scanf("%d", &i); } } void loadNode(node *head, int position, int value) { int i; node *temp = NULL; temp = head; temp = head; for(i = 0; i < position; i++) { temp = temp->next; } temp->data = value; } void createNode(node* head, node* tail) { head = (node *) malloc(sizeof(node)); tail = head; head->prev = NULL; head->next = NULL; } void copyList(node *head, node **copyHead, node **copyTail) { node *new, *temp; new = *copyHead = *copyTail = temp = NULL; temp = head; while(temp != NULL) { if (*copyHead == NULL) { *copyHead = (node *) malloc(sizeof(node)); *copyTail = *copyHead; (*copyHead)->prev = NULL; (*copyHead)->next = NULL; (*copyHead)->data = temp->data; } else { new = (node *) malloc(sizeof(node)); new->prev = *copyTail; new->next = NULL; (*copyTail)->next = new; *copyTail = new; (*copyTail)->data = temp->data; } temp = temp->next; } } int findData(node *head, int data) { int counter = 0; while(head != NULL) { if(head->data == data) break; counter++; head = head->next; } return counter; }
lab46:~/src/data$ ./linkedListDev Creating a list of 4 nodes... Size of the list is: 4 Load list data Enter a value or -1 to quit: 1 Enter a value or -1 to quit: 2 Enter a value or -1 to quit: 3 Enter a value or -1 to quit: 4 List is full of data! 1 2 3 4 Inserting node 0 with data of 3200 before head node... Size of the list is: 5 3200 1 2 3 4 Inserting node with data of -3200 before tail node... Size of the list is: 6 3200 1 2 3 -3200 4 Appending node with data of 2300 after head node... Size of the list is: 7 3200 2300 1 2 3 -3200 4 Appending node with data of -2300 after tail node... Size of the list is: 8 3200 2300 1 2 3 -3200 4 -2300 Loading node 0 with data of 0... Size of the list is: 8 0 2300 1 2 3 -3200 4 -2300 Loading tail node with data of 255... Size of the list is: 8 0 2300 1 2 3 -3200 4 255 Deleting head node... Size of the list is: 7 2300 1 2 3 -3200 4 255 Deleting tail node... Size of the list is: 6 2300 1 2 3 -3200 4 Deleting node 2... Size of the list is: 5 2300 1 3 -3200 4 Size of the list is: 5 2300 1 3 -3200 4 The node location of 3 is 2 lab46:~/src/data$
The element of the stack data structure which is available for stack operations (see the data structures topic “Stack” for details of stack operations) is known as the top of TOS (top of stack).
The stack position top may have data “pushed” (see the data topic “Pushing” for details of the stack operation push) into it at which point the stack pointer, a pointer pointing to the stack element which is available for stack operations, is incremented so as to expose the next stack element for stack operations.
The stack position top may also have data “popped” (see the data topic “Popping” for details of the stack operation pop) from it at which point the stack pointer, is decremented to expose the next stack element for stack operations.
If, a data structure such as a stack is full and cannot accept (store) anymore data, it is considered to be in an overflow state.
If, a data structure, such as a stack, is empty, no more data can be taken from it; it cannot be “popped” again as the data retreived would be erroneous, and the data structure position pointer, the stack pointer in the case of stacks, would be manipulated to point to some memory location which is no longer part of the data structure; this is considered to be the “underflow” state.
The function free, is used to release heap (see the data topic “Heap” for details) memory which was previously allocated dynamically, that is at run time, through the use of one of the memory allocation functions. free takes a single pointer argument; it releases the memory pointed to by its argument.
A structure or record is a collection of variables grouped together under a single identifier. The data are related somehow, that is the point of a structure or record. A classic example of a structure or record is that of an employee. Character array or string members of an employee structure or record might be the employee's first and last names, street, address, city, and state of residence. Integer members of the employee structure or record might be employee number, age, etc. The structure data type, also known as an abstract data type, provides an elegant and powerful way for keeping related data together.
A queue is a FIFO (see the data topic “FILO/FIFO” for details) type data structure. That is, data is taken from the queue in the same order that it was placed into it.
Enqueuing
Dequeue
The following program demonstrates an array-based queue.
//queueTest.c //John T. Rine //October 29, 2011 #include<stdio.h> #include<stdlib.h> struct Queue { char *queueArray; int count; int size; int startIndex; }; typedef struct Queue queue; void createQueue(queue *, int); void destroyQueue(queue *); void enqueue(queue *, char); void printQueue(queue *); int queueCount(queue *); char dequeue(queue *); int main(int argc, char **argv) { queue newQueue; createQueue(&newQueue, 25); destroyQueue(&newQueue); enqueue(&newQueue, 'J'); enqueue(&newQueue, 'o'); enqueue(&newQueue, 'h'); enqueue(&newQueue, 'n'); printf("Calling printQueue(&newQueue)...\n"); printQueue(&newQueue); printf("Calling and printing return value from dequeue...\n"); printf("%c, ", dequeue(&newQueue)); printf("%c, ", dequeue(&newQueue)); printf("\n"); printf("Calling printQueue(&newQueue)...\n"); printQueue(&newQueue); return 0; } void createQueue(queue *queuePTR, int size) { char *queueArrayPTR = NULL; queueArrayPTR = (char *)malloc(sizeof(char) * size); queuePTR->queueArray = queueArrayPTR; queuePTR->size = size; queuePTR->count = 0; queuePTR->startIndex = 0; } void destroyQueue(queue *queuePTR) { free(queuePTR->queueArray); } void enqueue(queue *queuePTR, char data) { int queueArrayIndex; if(queuePTR->count < queuePTR->size) { queueArrayIndex = queuePTR->startIndex + queuePTR->count; queuePTR->queueArray[queueArrayIndex] = data; queuePTR->count++; } else printf("Queue is full!\n"); } void printQueue(queue *queuePTR) { int i; for(i = 0; i < queuePTR->count; i++) printf("%c, ",queuePTR->queueArray[(queuePTR->startIndex + i)%queuePTR->size]); printf("\n"); } int queueCount(queue *queuePTR) { return queuePTR->count; } char dequeue(queue *queuePTR) { char ret; if(queuePTR->count == 0) { printf("queue is empty!\n"); exit(1); } ret = queuePTR->queueArray[queuePTR->startIndex]; queuePTR->count--; queuePTR->startIndex = (queuePTR->startIndex + 1)%queuePTR->size; return ret; }
This is the output of the queueTest.c program:
lab46:~/src/data$ gcc queueTest.c -o queueTest lab46:~/src/data$ ./queueTest Calling printQueue(&newQueue)... J, o, h, n, Calling and printing return value from dequeue... J, o, Calling printQueue(&newQueue)... h, n, lab46:~/src/data$
An array is a set of similar data type data stored in a contiguous section of memory. Since data contained in a array is packaged in similar sized memory blocks and stored in contiguous memory locations, it becomes possible to simply add an array element offset to the base address of the array to access data at a specific element withing the array. The following program illustrates the use off an index to access elements of an array.
//arrayTest.c //John T. Rine //October 29, 2011 #include<stdio.h> int main(int argc, char **argv) { char array[26] = {0}; int i; printf("Enter a string (<= 25 character) to place into a character array\n"); gets(array); printf("array contains %s\n", array); i = 0; while(array[i] != '\0') { printf("array[%d] = %c\n", i, array[i]); printf("*(array + %d) = %c\n", i, *(array + i)); i++; } return 0; }
This is the output of the arrayTest.c program listed above.
lab46:~/src/data$ ./arrayTest Enter a string (<= 25 character) to place into a character array John T. Rine array contains John T. Rine array[0] = J *(array + 0) = J array[1] = o *(array + 1) = o array[2] = h *(array + 2) = h array[3] = n *(array + 3) = n array[4] = *(array + 4) = array[5] = T *(array + 5) = T array[6] = . *(array + 6) = . array[7] = *(array + 7) = array[8] = R *(array + 8) = R array[9] = i *(array + 9) = i array[10] = n *(array + 10) = n array[11] = e *(array + 11) = e lab46:~/src/data$
LIFO is an acronym for “Last In, First Out”; FIFO is an acronym for “First In, First Out”. The stack is a last in, first out or LIFO data structure whereas the queue is a first in, first out or FIFO data structure. Due to the nature of the stack, one use is to reverse the order of data items. The data items to be reveresed are pushed onto the stack, and then to reverse them, they are popped off.
Identification and definition of the chosen keyword.
If you want to demonstrate something on the command-line, you can do so as follows:
lab46:~$ cd src lab46:~/src$ gcc -o hello hello.c lab46:~/src$ ./hello Hello, World! lab46:~/src$
Identification and definition of the chosen keyword. Substitute “keyword” with the actual keyword.
If you wish to aid your definition with a code sample, you can do so by using a wiki code block, an example follows:
/* * Sample code block */ #include <stdio.h> int main() { return(0); }
Identification and definition of the chosen keyword. Substitute “keyword” with the actual keyword.
If you want to demonstrate something on the command-line, you can do so as follows:
lab46:~$ cd src lab46:~/src$ gcc -o hello hello.c lab46:~/src$ ./hello Hello, World! lab46:~/src$
Identification and definition of the chosen keyword. Substitute “keyword” with the actual keyword.
If you wish to aid your definition with a code sample, you can do so by using a wiki code block, an example follows:
/* * Sample code block */ #include <stdio.h> int main() { return(0); }
Identification and definition of the chosen keyword. Substitute “keyword” with the actual keyword.
If you want to demonstrate something on the command-line, you can do so as follows:
lab46:~$ cd src lab46:~/src$ gcc -o hello hello.c lab46:~/src$ ./hello Hello, World! lab46:~/src$
Identification and definition of the chosen keyword. Substitute “keyword” with the actual keyword.
If you wish to aid your definition with a code sample, you can do so by using a wiki code block, an example follows:
/* * Sample code block */ #include <stdio.h> int main() { return(0); }
Identification and definition of the chosen keyword. Substitute “keyword” with the actual keyword.
If you want to demonstrate something on the command-line, you can do so as follows:
lab46:~$ cd src lab46:~/src$ gcc -o hello hello.c lab46:~/src$ ./hello Hello, World! lab46:~/src$
Identification and definition of the chosen keyword. Substitute “keyword” with the actual keyword.
If you wish to aid your definition with a code sample, you can do so by using a wiki code block, an example follows:
/* * Sample code block */ #include <stdio.h> int main() { return(0); }
Identification and definition of the chosen keyword. Substitute “keyword” with the actual keyword.
If you want to demonstrate something on the command-line, you can do so as follows:
lab46:~$ cd src lab46:~/src$ gcc -o hello hello.c lab46:~/src$ ./hello Hello, World! lab46:~/src$
Identification and definition of the chosen keyword. Substitute “keyword” with the actual keyword.
If you wish to aid your definition with a code sample, you can do so by using a wiki code block, an example follows:
/* * Sample code block */ #include <stdio.h> int main() { return(0); }
The fork() system call takes no arguments and returns a process ID.
fork() is used to create new processes which are child processes of the caller. Once a child process has been created both processes will execute the next instruction following the fork call. The returned PID value is the only way to distinguish between the child and the parent.
If calling fork is successfully executed, Unix/Linux will make two identical copies of address spaces, one for the parent and the other for the child.
Both processes will start their execution at the next statement following fork.
Regarding fork's return value, the man page says the following:
from man fork: RETURN VALUE On success, the PID of the child process is returned in the parent, and 0 is returned in the child. On failure, -1 is returned in the parent, no child process is created, and errno is set appropriately.
The following code asks the user to enter the number of iterations that the parent and child processes should execute. Next, fork is called with fork assigning its return value of type pid_t to pid. Once fork is called, fork's return value is used to determine whether what is being printed currently is the child or the parent. If the return value is 0, then its the child, if its some positive value greater than 0, then its the parent.
//forkExample.c //John T. Rine //October 23, 2011 #include <sys/types.h> #include <stdlib.h> #include<stdio.h> #define CHILD 0 int globalTestVar = 0; char *child(int *); char *parent(); char *error(); int main(int argc, char **argv) { char * procID = '\0'; int localTestVar = 0; int *localTestVarPTR = NULL; localTestVarPTR = &localTestVar; pid_t pid; printf("Enter a global variable value\n"); scanf("%d", &globalTestVar); printf("Enter a local variable value\n"); scanf("%d", &localTestVar); pid = fork(); //Error, failed to fork if (pid < CHILD) procID = error(); //child else if (pid == CHILD) procID = child(localTestVarPTR); //parent else procID = parent(); //Executed by both parent and child. printf("procID = %s\n", procID); printf("Global variable = %d\n", globalTestVar); printf("Local variable = %d\n", localTestVar); } char *child(int *localTestVarPtr) { char *procID; procID = "Child Process: "; ++*localTestVarPtr; ++globalTestVar; return procID; } char *parent() { char *procID; procID = "Parent Process:"; return procID; } char *error() { char *procID; procID = "Failed to fork"; return procID; }
Execution of forkExample.c
lab46:~/src/sysprog$ ./forkExample Enter a global variable value 2 Enter a local variable value 3 procID = Parent Process: Global variable = 2 Local variable = 3 procID = Child Process: Global variable = 3 Local variable = 4 lab46:~/src/sysprog$
The main comprises a single, default thread. All other threads must be explicitly created by the programmer.
The function pthread_create creates a new thread and makes it executable. This routine can be called any number of times from anywhere within your code. The maximum number of threads that may be created by a process is implementation dependent.
For example, the code below uses the number of arguments other than the file name (argc - 1) to create a given number of threads in the program.
There are many ways in which a thread may be terminated. The thread returns normally from its starting routine. It's work is done. The thread makes a call to the pthread_exit whether its work is done or not. The thread is canceled by another thread via the pthread_cancel routine. The entire process is terminated due to making a call to either the exec() or exit(). If main() finishes first, without calling pthread_exit explicitly itself.
The program below uses the following pthread library functions:
pthread_exit() enables the programmer to specify an optional termination status parameter. This optional parameter is typically returned to threads “joining” the terminated thread.
Regarding the calling of pthread_exit from main, there is a problem if main finishes before the threads it created if pthread_exit() isn't called explicitly. All of the threads it created will terminate because main is done and no longer exists to support the threads.
By having main explicitly call pthread_exit as the last thing it does, main will kept alive to support the threads it created until they are done.
//threadTest.c //John T. Rine //October 29, 2011 #include <pthread.h> #include <stdio.h> #include <stdlib.h> void *PrintMessage(void *message) { printf("%s\n", message); pthread_exit(NULL); } int main(int argc, char **argv) { if(argc == 1) { printf("No threads specified, exiting...\n"); exit(1); } pthread_t threads[argc - 1]; int rc, t; for(t=0;t<argc - 1;t++) { printf("In main: creating thread %ld\n", t); rc = pthread_create(&threads[t], NULL, PrintMessage, *(argv + t + 1)); if (rc) { printf("ERROR; return code from pthread_create() is %d\n", rc); exit(-1); } } pthread_exit(NULL); }
Compilation, linking, and execution of the code listed above:
lab46:~/src/sysprog$ gcc threadTest.c -o threadTest -lpthread lab46:~/src/sysprog$ ./threadTest No threads specified, exiting... lab46:~/src/sysprog$ ./threadTest John In main: creating thread 0 John lab46:~/src/sysprog$ ./threadTest John Thomas In main: creating thread 0 In main: creating thread 1 John Thomas lab46:~/src/sysprog$ ./threadTest John Thomas Rine In main: creating thread 0 In main: creating thread 1 John In main: creating thread 2 Thomas Rine lab46:~/src/sysprog$
POSIX is an acronym for “Portable Operating System Interface for UniX”. POSIX is the name of a set of related standards specified by the IEEE to define the application programming interface (API), along with shell and utilities interfaces, for software compatible with variants of the Unix operating system, although the standard can apply to any operating system. POSIX support guarantees code is portable from system to system and it is increasingly becoming a requirement that applications conform to POSIX standards. For example, the USA's Joint Technical Architecture—Army (JTA-A) standards set specifies that conformance to the POSIX standard is critical to support software interoperability.
Wikipedia (http://en.wikipedia.org/wiki/POSIX) lists items addressed in the various versions of POSIX: Parts before 1997, POSIX comprised several standards: POSIX.1, Core Services (incorporates Standard ANSI C) (IEEE Std 1003.1-1988) * Process Creation and Control * Signals * Floating Point Exceptions * Segmentation / Memory Violations * Illegal Instructions * Bus Errors * Timers * File and Directory Operations * Pipes * C Library (Standard C) * I/O Port Interface and Control * Process Triggers POSIX.1b, Real-time extensions (IEEE Std 1003.1b-1993) * Priority Scheduling * Real-Time Signals * Clocks and Timers * Semaphores * Message Passing * Shared Memory * Asynch and Synch I/O * Memory Locking Interface POSIX.1c, Threads extensions (IEEE Std 1003.1c-1995) * Thread Creation, Control, and Cleanup * Thread Scheduling * Thread Synchronization * Signal Handling POSIX.2, Shell and Utilities (IEEE Std 1003.2-1992) * Command Interpreter * Utility Programs Versions after 1997, the Austin Group developed the POSIX revisions. The specifications are known under the name Single UNIX Specification, before they become a POSIX standard when formally approved by the ISO. POSIX:2001 or IEEE Std 1003.1-2001 equates to the Single UNIX Specification version 3[5] This standard consisted of: * the Base Definitions, Issue 6, * the System Interfaces and Headers, Issue 6, * the Commands and Utilities, Issue 6. POSIX:2004 or IEEE Std 1003.1-2004 involved a minor update of POSIX:2001. It incorporated two technical corrigenda.[6] Its contents are available on the web.[7] POSIX:2008 As of 2009[update] POSIX:2008 or IEEE Std 1003.1-2008 represents the current version.[8][9] A free online copy is available.[10] This standard consists of: * the Base Definitions, Issue 7, * the System Interfaces and Headers, Issue 7, * the Commands and Utilities, Issue 7.
The semaphore is a synchronization method. A semaphore is a kernel variable that is accessible by all of the processes currently executing on the system.
Processes use semaphores to coordinate access to shared system resources between them. A semaphore is a counter; when it is zero, the semaphore can block a thread’s execution using sem_wait until another thread increments the counter using sem_post.
The following example code came from http://pages.cs.wisc.edu/~travitch/pthreads_primer.html
This is the result of compiling, linking and then executing the example code listed above:
#include <semaphore.h> #include <pthread.h> #include <stdio.h> #define THREADS 20 sem_t OKToBuyMilk; int milkAvailable; void* buyer(void *); int main(int argc, char **argv) { int i; pthread_t threads[THREADS]; milkAvailable = 0; // Initialize the semaphore with a value of 1. // Note the second argument: passing zero denotes // that the semaphore is shared between threads (and // not processes). if(sem_init(&OKToBuyMilk, 0, 1)) { printf("Could not initialize a semaphore\n"); return -1; } for(i = 0; i < THREADS; ++i) { if(pthread_create(&threads[i], NULL, &buyer, NULL)) { printf("Could not create thread %d\n", i); return -1; } } for(i = 0; i < THREADS; ++i) { if(pthread_join(threads[i], NULL)) { printf("Could not join thread %d\n", i); return -1; } } sem_destroy(&OKToBuyMilk); // Make sure we don't have too much milk. printf("Total milk: %d\n", milkAvailable); return 0; } void* buyer(void *arg) { // P() sem_wait(&OKToBuyMilk); if(!milkAvailable) { // Buy some milk ++milkAvailable; } // V() sem_post(&OKToBuyMilk); return NULL; }
lab46:~/src/sysprog$ gcc testSemaphore.c -o testSemaphore -lpthread lab46:~/src/sysprog$ ./testSemaphore Total milk: 1 lab46:~/src/sysprog$
The mutex is a synchronization method. The word mutex means mutual exclusion (between threads in this usage) and is a combination of the two words as follows: MUTual EXclusion. A mutex is used cooperatively between threads to guarantee that only one of the threads is allowed to access shared memory or run certain application code at a time.
The barrier is a synchronization method. A barrier for a set of threads or processes makes any thread or process stop at mutex and cannot continue until the remaining threads or processes reach this barrier.
File locking is a device that controls access to a file by allowing only one process to access it at one time.
Asynchronous input, is a non-blocking type of I/O that allows other processing to continue while input is being received.
First, Linux utilizes permissions bits to control file access. There are three types of access: read, write, and execute.
Also there is file locking which is a device that controls access to a file by allowing only one process to access it at one time.
Kernel space is protected, nothing contained in it can be used in a program (called) directly. There are therefore services which are provided to act as interfaces between applications in user space and the kernel. A system call is the only way a programmer may use these services.
Individual bits within a larger data package, a byte for instance, can be used to represent something.
So rather than having a variable hold a value that represents only one thing, each bit within the variable can represent something.
One example of the use of bit sets would be using chmod to set file permissions.
Bit masks are used to manipulate only certain bits within a larger data package. Bit masking of data is carried out using two things, a bit mask, and a bitwise logical operation.
Bit masks are used to either select or deselect which bits are set or changed; bitwise operations actually change the data based on the bit mask value.
For example, data bits can be set using the bitwise or:
data = 00000000 mask = 01010101 data = data | bit mask data = 01010101
Data bits can be reset using bitwise and:
data = 11111111 mask = 01010101 data = data & bit mask data = 01010101
Other bitwise operations which can be used to bit mask and bit set repectively are exclusive or and complement.
A signal is a software interrupt delivered to a process when an event occurs.
The code below was taken from http://www.c.happycodings.com/Gnu-Linux/code18.html and is used to demonstrate how signals work in a program.
//http://www.c.happycodings.com/Gnu-Linux/code18.html //Signal, catch Ctrl-C #include <stdio.h> #include <unistd.h> /* sleep(1) */ #include <signal.h> void ex_program(int sig); int main(void) { (void) signal(SIGINT, ex_program); while(1) printf("sleeping .. ZZZzzzz ....\n"), sleep(1); return 0; } void ex_program(int sig) { printf("Wake up call ... !!! - Catched signal: %d ... !!\n", sig); (void) signal(SIGINT, SIG_DFL); }
Executing the code listed above produces the following output:
lab46:~/src/sysprog$ gcc sigTest.c -o sigTest lab46:~/src/sysprog$ ./sigTest sleeping .. ZZZzzzz .... sleeping .. ZZZzzzz .... sleeping .. ZZZzzzz .... sleeping .. ZZZzzzz .... sleeping .. ZZZzzzz .... sleeping .. ZZZzzzz .... ^CWake up call ... !!! - Catched signal: 2 ... !! sleeping .. ZZZzzzz .... sleeping .. ZZZzzzz .... sleeping .. ZZZzzzz .... sleeping .. ZZZzzzz .... ^C lab46:~/src/sysprog$
I would like to become more familiar with the various data structures, specific uses for each and be able to use them in applications.
I will learn more about linked-lists, stacks, queues, graphs and trees by:
Research and analysis of experimental results: see “Pushing” and “Popping” Part I Data Structures topics, also see “Overflow”, “Underflow”, “Linked list”, “Queues”, “malloc”, “free” Part II Data Structures topics for details.
I have written linked list and stack libraries using linked nodes. I have also written array-based stacks and queues, each have dynamically-sized arrays all which compiled, linked, and executed successfully.led, linked and executed successfully.
State the course objective; define what that objective entails.
State the method you will use for measuring successful academic/intellectual achievement of this objective.
Follow your method and obtain a measurement. Document the results here.
Reflect upon your results of the measurement to ascertain your achievement of the particular course objective.
I would like to understand fork, what its purpose for being is and about spawning child processes in more detail.
I would also like to understand mutltithreading, thread synchronization in more detail. I would like to understand more about parallel computing and how fork and multithreading play a part
I will learn more about concurrency, fork, child processes, multithreading, and thread synchronization by:
Research and analysis of experimental results: see “Threads”, ““Multithreading”, and “Semaphore” under Part I of the System programming topics, also see “Threads part deux”, “Semiphores” and “Mutexes” Part II Systeme programming topics for details.
I wrote a simple mulithreaded application which compiled, linked and executed successfully. Regarding semaphores, I experimented with code which I found on the Internet. I was able, after modifying it, to compile, link and execute it. I worked with functions from both pthreads.h and semaphore.h.
Is it possible to assign a string literal (using double-quotation marks), to a block of memory that has been dynamically allocated but has not had data yet assigned to it?
Since it is possible to assign a string literal to a character pointer and then use it in a program (i.e.print out the data it points to), it should be possible to assign a string literal to pointer, pointing to a dynamically-allocated block of memory which hasn't yet been assigned data and then when the data is no longer needed, free it.
For example:
//testStringLiteral.c //John T. Rine //October 24, 2011 #include<stdio.h> int main(int argc, char **argv) { char * nameStringPTR = NULL; nameStringPTR = "John T. Rine"; printf("nameStringPTR points to: %s\n:", nameStringPTR); return 0; }
And the execution:
lab46:~/src/data$ gcc testStringLiteral.c -o testStringLiteral lab46:~/src/data$ ./testStringLiteral nameStringPTR points to: John T. Rine lab46:~/src/data$
This version of the testMalloc.c program corresponds to the first set of program output in the data section below.
//testMalloc.c //John T. Rine //October 24, 2011 #include<stdlib.h> #include<stdio.h> int main(int argc, char **argv) { //malloc a char array char *arrayPTR = NULL; arrayPTR = malloc(sizeof(char) * 10); arrayPTR = "John Rine\0"; printf("My name is: %s\n", arrayPTR); free(arrayPTR); return 0; }
This version of the testMalloc.c program, with free commented out, corresponds to the second set of program output listed in the data section below.
//testMalloc.c //John T. Rine //October 24, 2011 #include<stdlib.h> #include<stdio.h> int main(int argc, char **argv) { //malloc a char array char *arrayPTR = NULL; arrayPTR = malloc(sizeof(char) * 10); arrayPTR = "John Rine\0"; printf("My name is: %s\n", arrayPTR); //free(arrayPTR); return 0; }
This version of the testMalloc.c program, also with free commented out, corresponds to the third set of program output listed in the data section below. Note that printf function calls have been added to check the address contained in arrayPTR before and after assigning the string to the character pointer.
//testMalloc.c //John T. Rine //October 24, 2011 #include<stdlib.h> #include<stdio.h> int main(int argc, char **argv) { //malloc a char array char *arrayPTR = NULL; arrayPTR = malloc(sizeof(char) * 10); printf("The address contained in arrayPTR before assigning a string is: 0x%x\n", arrayPTR); arrayPTR = "John Rine\0"; printf("The address contained in arrayPTR before assigning a string is: 0x%x\n", arrayPTR); printf("My name is: %s\n", arrayPTR); //free(arrayPTR); return 0; }
This last version of testMalloc.c assigns the individual characters in the string to the character-sized memory locations pointed to by the character pointer assigned to point to the dynamically allocated memory.
//testMalloc.c //John T. Rine //October 23, 2011 #include<stdlib.h> #include<stdio.h> int main(int argc, char **argv) { //malloc a char array int i = 0; int ii = 0; char * inputString = "John T. Rine\0"; char * string = NULL; printf("input string contains %s\n", inputString); while(*(inputString + i) != '\0') i++; printf("Character count = %d\n", i); string = (char *)malloc(sizeof(char) * (i + 1)); for(ii = 0; ii <= (i + 1); ii++) *(string + ii) = *(inputString + ii); printf("Dynamically allocated array contains %s\n", string); free(string); return 0; }
Program output after assigning a string to a character pointer which points to a set of dynamically allocated character sized memory locations, printing out the contents pointed to, and then the freeing the memory. This output was created by the first version of the testMalloc.c program listed in the Experiment section listed above.
lab46:~/src/data$ gcc testMalloc.c -o testMalloc lab46:~/src/data$ ./testMalloc My name is: John Rine *** glibc detected *** ./testMalloc: free(): invalid pointer: 0x00000000004006cc *** ======= Backtrace: ========= /lib/libc.so.6(+0x71ad6)[0x7f9874d51ad6] /lib/libc.so.6(cfree+0x6c)[0x7f9874d5684c] ./testMalloc[0x4005d6] /lib/libc.so.6(__libc_start_main+0xfd)[0x7f9874cfec4d] ./testMalloc[0x4004c9] ======= Memory map: ======== 00400000-00401000 r-xp 00000000 00:11 2147645911 /home/jr018429/src/data/testMalloc 00600000-00601000 rw-p 00000000 00:11 2147645911 /home/jr018429/src/data/testMalloc 01f1e000-01f3f000 rw-p 00000000 00:00 0 [heap] 7f9870000000-7f9870021000 rw-p 00000000 00:00 0 7f9870021000-7f9874000000 ---p 00000000 00:00 0 7f9874aca000-7f9874ae0000 r-xp 00000000 ca:01 57346 /lib/libgcc_s.so.1 7f9874ae0000-7f9874cdf000 ---p 00016000 ca:01 57346 /lib/libgcc_s.so.1 7f9874cdf000-7f9874ce0000 rw-p 00015000 ca:01 57346 /lib/libgcc_s.so.1 7f9874ce0000-7f9874e38000 r-xp 00000000 ca:01 57396 /lib/libc-2.11.2.so 7f9874e38000-7f9875037000 ---p 00158000 ca:01 57396 /lib/libc-2.11.2.so 7f9875037000-7f987503b000 r--p 00157000 ca:01 57396 /lib/libc-2.11.2.so 7f987503b000-7f987503c000 rw-p 0015b000 ca:01 57396 /lib/libc-2.11.2.so 7f987503c000-7f9875041000 rw-p 00000000 00:00 0 7f9875041000-7f987505f000 r-xp 00000000 ca:01 57564 /lib/ld-2.11.2.so 7f987524c000-7f987524f000 rw-p 00000000 00:00 0 7f987525b000-7f987525e000 rw-p 00000000 00:00 0 7f987525e000-7f987525f000 r--p 0001d000 ca:01 57564 /lib/ld-2.11.2.so 7f987525f000-7f9875260000 rw-p 0001e000 ca:01 57564 /lib/ld-2.11.2.so 7f9875260000-7f9875261000 rw-p 00000000 00:00 0 7fffca6cc000-7fffca6e1000 rw-p 00000000 00:00 0 [stack] 7fffca6f3000-7fffca6f4000 r-xp 00000000 00:00 0 [vdso] ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall] Aborted lab46:~/src/data$
Program output with free commented out. This output was created by the second version of the testMalloc.c program listed in the experiment section above.
lab46:~/src/data$ ./testMalloc My name is: John Rine lab46:~/src/data$
Program output with free commented out and with printf function calls to print out the address contained in arrayPTR before and after assigning the string to the character pointer. This program output was created by the third version of the testMalloc program listed in the experiment section above.
lab46:~/src/data$ gcc testMalloc.c -o testMalloc lab46:~/src/data$ ./testMalloc The address contained in arrayPTR before assigning a string is: 0x86d010 The address contained in arrayPTR before assigning a string is: 0x4006f6 My name is: John Rine lab46:~/src/data$
This last set of program output corresponds the the last incarnation of the testMalloc.c program listed above in the experiment section.
lab46:~/src/data$ gcc testMalloc.c -o testMalloc lab46:~/src/data$ ./testMalloc input string contains John T. Rine Character count = 12 Dynamically allocated array contains John T. Rine lab46:~/src/data$
Based on the data collected, my hypothesis was proven to not be correct.
The first verision of the testMalloc.c program crashed when free executed which seemed to indicate that the issue seemed to be misuse of the free function.
The second version of the program, in which free was commented out, ran flawlessly reinforcing the notion that the issue has to do with free.
The third version of the program introduced printf calls to print out the address of arrayPTR before and after the assignment of the string literal to it. This version of the program demonstrates that assigning a string literal to a pointer pointing to newly allocated and not yet used memory causes the address stored in the pointer to no longer point to the dynamically llocated memory, but to the beginning address of the string literal. Therefore, when free attempted to free memory no longer being pointed to, it caused an exception to be thrown.
The fourth and final version of the testMalloc.c program demonstrates that the proper way to assign a string to dynamically allocated memory in C is to do it character by character.
In C, even though it is possible to assign a string literal to a pointer and then use it, it is not possible to assign a string literal directly to a pointer pointing to dynamically allocated memory. This is because assigning a string literal to it changes the address stored in it so that when the memory is later freed, an exception is thrown because the pointer no longer points to the dynamically allocated memory.
Is it possible to use curses library input functions to handle and/or get function (F) keys in the same way that other key characters are handledretrieved?
Currently, for my system programming projects, I am developing a GUI (Graphical User Interface) interface, with which to program and display the results of operations (register values), for the 8085 CPU project begun in Computer Organization last sememster.
The GUI is to be developed using curses. I started with a function to read keyboardin input, however, the curses input function, getch, could not recognize the function (F) keys for some reason.
Date: Sun, 18 Sep 2011 21:25:29 -0400 (EDT) From: John Rine <jr018429@lab46.corning-cc.edu> Reply-To: "\\\"Systems\\\" Classes Discussion List" <sys@lab46.corning-cc.edu> To: sys@lab46.corning-cc.edu Subject: [SYS] Trouble with Curses recognizing F keys and other keyboard keys All, I am having trouble with curses recognizing function keys and the escape key. I am using code like this: #include<curses.h> int main() { int c; initscr(); keypad(stdscr,TRUE); noecho(); move(0,0); c=getch(); while(c != KEY_F(1) && c != 'q') { move(0,0); printw("%c\n",c); refresh(); c=getch(); } endwin(); return 0; } it will exit with 'q' but not KEY_F(1) or the F1 key. Also, the esc key is not recognized when using the KEY_EXIT constant. Anyone have any ideas as to how to get function keys and the escape key to work with curses? thanks, John T. Rine --- Lab46: Penguin Powered
The instructor stated that he didn't have experience with curses and functions keys, but that this question could be the basis for an experiment; he challenged me to, using the scientific method, put together a hypothesis and a set of experiments whose outcome would help me answer the question posed.
Date: Mon, 19 Sep 2011 08:43:07 -0400 From: Matthew Haas <wedge@lab46.corning-cc.edu> Reply-To: "\\\"Systems\\\" Classes Discussion List" <sys@lab46.corning-cc.edu> To: sys@lab46.corning-cc.edu Subject: Re: [SYS] Trouble with Curses recognizing F keys and other keyboard keys On 09/18/2011 09:25 PM, John Rine wrote: > > I am having trouble with curses recognizing function keys and the escape key. > I am using code like this: > #include<curses.h> > > int main() > { > int c; > initscr(); > keypad(stdscr,TRUE); > noecho(); > move(0,0); > c=getch(); > while(c != KEY_F(1) && c != 'q') > { > move(0,0); > printw("%c\n",c); > refresh(); > c=getch(); > } > endwin(); > return 0; > } > it will exit with 'q' but not KEY_F(1) or the F1 key. Also, the esc key is not recognized when using the KEY_EXIT constant. Anyone have any ideas as to how to get > function keys and the escape key to work with curses? I've never played with the function keys... so that would take some experimenting. Escape, even though there may not be a #define for it (all the keys available to you are #define'd in /usr/include/curses.h, check it out), has a value. The trick is, what is it? Hmm... this could be another experiment. If you know that pretty much every key on the keyboard has a value (which ones do not have a direct value?), how could we figure out what the values of keys are? What is the data type of the 'c' variable in the program above? What type of data are we displaying in the printw() function call above? Could you perhaps CHANGE the format specifier to match the actual data type of the 'c' variable? What would happen then? If you then compile and run the program and start pressing keys, what happens? What do you see when you press 'a', 'A', spacebar? Do you know what these values correspond to? What do you think happens when you start pressing some keys that do not directly have printable characters associated with them, like... escape. What does it display? -Matthew -- Matthew Haas Lab46 System Administrator Instructor of Computer& Information Science http://lab46.corning-cc.edu/haas/home/ _______________________________________________ SYS mailing list SYS@lab46.corning-cc.edu http://lab46.corning-cc.edu/mailman/listinfo/sys
Based on what I've read, it should be possible to uses curses library functions to handle function key input.
Since I was having trouble getting curses functions to recognize function (F) keys, I designed a simple program to read keyboard input using a curses function and then printed out the results. The program has the minium required to read and verify keyboard input.
//curseskeys.c //John T. Rine //October 29, 2011 #include <ncurses.h> int main() { int ch; initscr(); raw(); keypad(stdscr, TRUE); noecho(); printw("Type any character\n"); ch = getch(); if(ch == KEY_F(1)) printw("F1 Key pressed"); else { printw("The pressed key is "); printw("%c", ch); } refresh(); getch(); endwin(); return 0; }
Since the F keys were not being recognized by the curses getch function, I wrote a program that gets keyboard input from stdin and stores it in an array. I then print out the characters stored in the array.
//getFkeys.c //John T. Rine //October 29, 2011 #include<stdio.h> int main(int argc, char **argv) { char array[10] = { 0 }; int i; char c; fgets(array,9,stdin); for (i = 0; i < 10; i++) printf("Array[%d] = %d\n", i, array[i]); return 0; }
curseskeys.c execution with puTTY keyboard function and keyboard keys set to ESC[n~.
Result of entering the character 'a':
Type any character The pressed key is a
Result of entering the F1 key:
lab46:~/src/sysprog$ ./curseskeys lab46:~/src/sysprog$ ~
curseskeys.c execution with puTTY keyboard function and keyboard keys set to VT100+.
Result of entering the 'a' key:
Type any character The pressed key is a
Result of entering the F1 key:
Type any character F1 Key pressed
getFkeys.c execution with puTTY keyboard function and keyboard keys set to ESC[n~.
Result of entering the character 'a':
lab46:~/src/sysprog$ ./getFkeys a Array[0] = 97 Array[1] = 10 Array[2] = 0 Array[3] = 0 Array[4] = 0 Array[5] = 0 Array[6] = 0 Array[7] = 0 Array[8] = 0 Array[9] = 0
Result of entering the F1 key:
lab46:~/src/sysprog$ ./getFkeys ^[[11~ Array[0] = 27 Array[1] = 91 Array[2] = 49 Array[3] = 49 Array[4] = 126 Array[5] = 10 Array[6] = 0 Array[7] = 0 Array[8] = 0 Array[9] = 0 lab46:~/src/sysprog$
getFkeys.c execution with puTTY keyboard function and keyboard keys set to VT100+.
Result of entering the character 'a':
lab46:~/src/sysprog$ ./getFkeys a Array[0] = 97 Array[1] = 10 Array[2] = 0 Array[3] = 0 Array[4] = 0 Array[5] = 0 Array[6] = 0 Array[7] = 0 Array[8] = 0 Array[9] = 0 lab46:~/src/sysprog$
Result of entering the F1 key:
lab46:~/src/sysprog$ ./getFkeys ^[OP Array[0] = 27 Array[1] = 79 Array[2] = 80 Array[3] = 10 Array[4] = 0 Array[5] = 0 Array[6] = 0 Array[7] = 0 Array[8] = 0 Array[9] = 0 lab46:~/src/sysprog$
The data (program output from curseskeys.c) indicates that in order to use the curses getch function to get function (F) key input, the keyboard setting in puTTY must be set to something other than ESC[n~. The program executions that were able to read function (F) key input in this experiment were performed with the keyboad setting st to VT100+. The data collected from the the program output of getFkeys.c indicates that the keyboard/terminal settings do infact influence what is returned from a function (F) key keypress. With the puTTY keyboard/function key setting set to ESC[n~, the output of getFkeys.c with a character input of 'a' is:
a Array[0] = 97 Array[1] = 10 Array[2] = 0 Array[3] = 0 Array[4] = 0 Array[5] = 0 Array[6] = 0 Array[7] = 0 Array[8] = 0 Array[9] = 0
whereas the output with the puTTY keyboard/function key setting set as above, the output of getFkeys.c with a keyboard input of F1 is:
^[[11~ Array[0] = 27 Array[1] = 91 Array[2] = 49 Array[3] = 49 Array[4] = 126 Array[5] = 10 Array[6] = 0 Array[7] = 0 Array[8] = 0 Array[9] = 0
With the puTTY keyboard/function key setting set to VT100+, the output of getFkeys.c with a character input of 'a' is:
a Array[0] = 97 Array[1] = 10 Array[2] = 0 Array[3] = 0 Array[4] = 0 Array[5] = 0 Array[6] = 0 Array[7] = 0 Array[8] = 0 Array[9] = 0
whereas the output with the puTTY keyboard/function key setting set as above, the output of getFkeys.c with a keyboard input of F1 is:
^[OP Array[0] = 27 Array[1] = 79 Array[2] = 80 Array[3] = 10 Array[4] = 0 Array[5] = 0 Array[6] = 0 Array[7] = 0 Array[8] = 0 Array[9] = 0
indicating that the keyboard/terminal settings do NOT influence what is returned when a character key is pressed, but do influence what is returned when a function (F) key is pressed.
Since it appears that the terminal keyboard/function key setting does influence what is returned when a function (F) key is pressed, it would be a good idea to guarantee termminal settings before an applications, using function keys, executes. This could, or should be able to be accomplished either through the use of a shell script, modifying a system configuration file, or through the use of a programming library.
If the library header file for functions used in a program is included in a source file, shouldn't compiling the source file alone cause the creation of an executable (that is linking is automatic, after all, the header file for the library was included in the source file)?
Based on what I've read it should not link successfuly because standard c libraries are located in libc.so, while the math library is located in libm.so. The standard c libraries are linked by default, whereas the math library is not.
I used the following program to collect data for the experiment. This file has math.h and stdio.h headers file included in the source file.
//mathTest.c ///John T. Rine //October 30, 2011 #include <math.h> #include <stdio.h> int main (int argc, char **argv) { double x = 0; printf("Enter a value to takes its square root\n"); scanf("%lf", &x); printf ("The square root of %lf is %lf\n", x, sqrt(x)); return 0; }
These are the results of the first attempt at compiling mathTest.c; the exact invocation of the gcc compiler uses was: gcc mathTest.c -o mathTest
lab46:~/src/sysprog$ gcc mathTest.c -o mathTest /tmp/ccJHwf08.o: In function `main': mathTest.c:(.text+0x51): undefined reference to `sqrt' collect2: ld returned 1 exit status lab46:~/src/sysprog$
These are the results of the second attempt at compiling mathTest.c; the exact invocation of the gcc compiler used was: gcc mathTest.c -o mathTest -lm
lab46:~/src/sysprog$ gcc mathTest.c -o mathTest -lm lab46:~/src/sysprog$
This are the results of executing the program after successfully compiling and linking it.
lab46:~/src/sysprog$ ./mathTest Enter a value to takes its square root 144 The square root of 144.000000 is 12.000000 lab46:~/src/sysprog$
My hypothesis was correct as can be seen from the data collected from the experiment. If the math library is not linked, no executable is created, however, if the math library is linked, them the executable is created successfully.
If a library is not part of the C standard library, when the program is being compiled and linked there must be something to indicate what should be linked.
Since curses is not part of the C standard library, what happened while compiling and linking the math library will also occur when a curses program is compiled and linked.
For example compiling and linking a curses program without indicating what should be linked:
lab46:~/src/sysprog$ gcc curseskeys.c -o curseskeys /tmp/cco3mJn0.o: In function `main': curseskeys.c:(.text+0x9): undefined reference to `initscr' curseskeys.c:(.text+0xe): undefined reference to `raw' curseskeys.c:(.text+0x15): undefined reference to `stdscr' curseskeys.c:(.text+0x22): undefined reference to `keypad' curseskeys.c:(.text+0x27): undefined reference to `noecho' curseskeys.c:(.text+0x36): undefined reference to `printw' curseskeys.c:(.text+0x3d): undefined reference to `stdscr' curseskeys.c:(.text+0x45): undefined reference to `wgetch' curseskeys.c:(.text+0x60): undefined reference to `printw' curseskeys.c:(.text+0x71): undefined reference to `printw' curseskeys.c:(.text+0x85): undefined reference to `printw' curseskeys.c:(.text+0x8c): undefined reference to `stdscr' curseskeys.c:(.text+0x94): undefined reference to `wrefresh' curseskeys.c:(.text+0x9b): undefined reference to `stdscr' curseskeys.c:(.text+0xa3): undefined reference to `wgetch' curseskeys.c:(.text+0xa8): undefined reference to `endwin' collect2: ld returned 1 exit status lab46:~/src/sysprog$
Compiling and linking a curses program with an indication of what should be linked:
lab46:~/src/sysprog$ gcc curseskeys.c -o curseskeys -lcurses lab46:~/src/sysprog$
It is an interesting observation that the math library is linked as -lm and its dynamic library file name is libm.so. The curses library is linked as -lcurses; this implies that the curses dynamic library file name should be libcurses.so.
Since the math library is included in a source file as #include<math.h>, and since the curses library is included in a source file as #include<curses.h>, then these dynamic libraries should be in the same path and also be in the same path as the c standard library (libc.so). A search for libcurses.so, therefore, int the c library path should be successful; there should be a dynamic library file by the name of libcurses.so in the c library path.