User Tools

Site Tools


opus:fall2011:bkenne11:start

Table of Contents

Brandon Kennedy's Fall 2011 Opus

Welcome!

Introduction

This shall be from here-on-out the Opus of Brandon Kennedy!!! I am in my 3rd computer science semester at CCC, currently enrolled in:

  1. Calculus 3
  2. Systems Programming
  3. Data Structures
  4. Discrete Structures
  5. walking

I also tutor at the MLC in Elmira on tuesday and wednesday from 4-8, and thursday 4-6, come visit!!!

Part 1

Entries

September 16th, 2011

These last few weeks of class have been crazy. Over the summer my programming was lacking in quantity so it was that much harder to transition into this semester. But i was able to catch up and even learn about these few things already!

  • The use of malloc to allocate the size of a pointer array
  • The use of argv and argc in my main functions
    1. This was useful because i can now accept command line arguments!!!

Some topics that i am having a lot of trouble understanding are:

  • Linked lists

There is not much to linked lists, i understand the concept of tmp → next = start or a line like such. But when to put which line, and the order of the commands is quite confusing to me!!!!!

September 19th 2011

I am pretty sure that the linked lists light buld just clicked! For my class project in data structures i am creating a linked list implementation using characters. It will have several different functions that will be in several different files, all used as a library.

  • I was alluded by how i was to pass a list into a function to modify it, and then i realized(with a little help) that that was not the case!
  • I am still trying to grasp it all, and i have a few things to sort out, but i believe my linked list project will go quite smoothly from here on out!
  • Whereas linked lists do not yet seem like a good thing to me, i am sure they have their uses. Right now they seem like a waste of time, and way too much of a hassle.

September 22nd, 2011

I have to say that at first i was skeptical, but as i progressed the deffinitions started to help. Every deffinition I have done so far has helped me learn something. Whether it is a small syntax issue, or a major use issue where i didn't even know that certain function/use existed! So far i have done:

  • Pointers
  • arrays
  • version control
  • etc…

One thing that puzzles me now is still linked lists!!! I now have to remove a whole list, and deallocate the memory it was using, kinda hard for me. an example of what i am trying is below:

deletelist(Node *thing, Node *stop) //function must be passed the first and last node in the list
{
        if(thing = stop)
        {
                free(thing);
        }
        else
        {
                Node *test;
                test = (Node *) malloc (sizeof(Node));
                while(thing != stop)
                {
                        test = thing -> next;
                        thing -> next -> prev = NULL;
                        thing -> next = test;
                        free(thing);
                        thing = next;
                }
                free(stop);
                free(test);
                free(thing):
        }
}

September 25th, 2011

And i used to think that a library was that place down the street where nerds banded together to feel safe… But they are so much more!!! We have been working with librarys in not just Data Structures, but discrete structures aswell, and i am so glad we have! There are a lot of lessons to learn from library building. Like for instance:

  1. Making sure all of your files are labeled clearly since libraries can be very large.
  2. Making sure no header files are double listed.
  3. making sure to always update, compile, and save every file as you work on it.

DATA Topics

Pointers

A pointer is a variant of a data type that deals with location. A pointer “points to” a storage address. So if you reference a storage address, call it address A, and that address contains another storage address, say address F, address A is then a pointer to address F.

in the program below, c is a pointer to a.

#include <stdio.h>
 
int main()
{
    int a=5;
    int b=7;
    int c;
    int d;
 
    c=a;
    d=b*c;
    printf("%d\n", d);
    return(0);
}

Allocation

  1. Static vs. Dynamic

Static

Not all variables are automatically allocated. The following kinds of variables are statically allocated:

  • all global variables, regardless of whether or not they have been declared as static;
  • local variables explicitly declared to be static.

Statically allocated variables have their storage allocated and initialized before main starts running and are not deallocated until main has terminated.

String constants (except those used as initializers for variables of type array of char) are statically allocated. In most expressions a string constant generates a pointer to the first char in the string.

#include <stdio.h>
int main(void)
{
  char s[] = "dog";
  char *e = "food";
  printf("A %s eats %s\n", s, e);
  return 0;
}

Dynamic

The problem with static allocations is that the programmer must know before hand how much data the program will need to handle. So he or she must make a guess at the largest possible amount of data that could be used. Dynamic allocation is the automatic allocation of memory in C/C++, Unlike declarations, which load data onto the programs data segment, dynamic allocation creates new usable space on the programs STACK.

{
#include<stdio.h>
int main()
int *array;
array=(int *) malloc(size*sizeof(int));
return 0;
 }

Version Control

Version control is simply the management of changes to files, documents, programs many other types of information stored as computer files. This is widely used by large programming teams where many people edit the same file. Bugs or features of the software are often only present in certain versions because of the fixing of some problems and the introduction of others as the program develops. Therefore, for the purposes of fixing bugs, it is very important to be able to retrieve and run different versions of the software to determine in which version(s) the problem occurs.

A few functional uses of version control are:

  1. Commit
    • Commiting changes made to a working file back into the repository
  2. Check-out
    • Check out a working copy of the file from the repository
  3. Update
    • merges changes made in the repository (by other people, for example) into the local working copy.

Arrays, Pointer arithmetic

ARRAY

An array is a is a data type that can be indexed. It is described as a collection of elements, or information segments. An array is storage of any data type. arrays can contain integers, pointers and characters, and in that sence, can contain strings. For this example we will focus on integers.

Notice the below array is defined as data type “int” then a name with an array symbol after it “[]” containing the word size which is equal to an integer. This creates an array with 20 “sections” or “segments” for information to be stored. As i said above, arrays can be indexed, meaning they are in an order, and you can move about that array to store/retrieve data. you do this by use of the array symbol “[]”.

An array starts at the numeric index of 0, meaning it contains the sections 0-19. If you want to access the 4rth item of data, or fourth integer stored in the array, you would use list[3] because location 3 is the fourth space when you start at 0.

 int size = 20;
 int list[size];
 
 size[3] = 46;
 
 printf("%d", size[3]);

This example will save 46 in the array position 4 and then print out the contents of array position 4, which will be 46.

Pointer Arithmetic

Pointer arithmetic is like moving about an array. An array can be defined in another way than by use of the array symbol []. It can be defined in another way, like this:

int *list;
list = malloc(sizeof(char)*50);
  • This array is an array of pointers to memory locations.
  • Pointer arithmetic refers to incrementing/decrementing pointer arrays.
int *array;
*(list+1) = 34;
*(list+5) = 4; 
for(i=5;i<0;i--)
{
  *(list+i) = 3+i
}
printf("%d", *(list+1));

This will save 34 into the array, allong with many other pointer arithmetic operations, and then print out the contents of that array position. Moving about an array in this manner is called “Pointer Arithmetic”.

Variables

Numeric and character.

Variables are memory locations that are given names and can be assigned values. Variables are used to store different types of data in memory for future use.

Numeric types have several subtypes like integers or real values. characters are letters and ASCII symbols. Here is a list of data types and their range. (this list assumes signed integers)

  1. short Numeric - Integer signed: -32768 to 32767 unsigned: 0 to 4294967295
  2. int Numeric - Integer signed: -2147483648 to 2147483647 unsigned: 0 to 4294967295
  3. long Numeric - Integer signed: -2147483648 to 2147483647 unsigned: 0 to 4294967295
  4. float Numeric - Real signed: 1.2 X 10-38 to 3.4 X 1038 no unsigned
  5. double Numeric - Real signed: 2.2 X 10-308 to 1.8 X 10308 no unsigned
  6. char Character signed: -128 to 127 unsigned: 0 to 255

These values are all relative to the operating system, as is the same for the size. A char is typically one byte but may not always be. Programmers should always use the sizeof() function to determine the size of the variable type they wish to use.

example:

int main()
{
     int a = sizeof(int);
     int b = sizeof(short);
     int c = sizeof(char):
 
     printf("%d\n", a);
     printf("%d\n", b);
     printf("%d\n", c);
 
     return 0
}

Keyword 6

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$ 

memory deallocation

When you dynamically allocate memory in a program you have to deallocate it once you are done.

by use of C

free(num);
free(ch)
free(db);

by use of C++

delete number;
delete ch;
delete db;
 
If you allocate memory and do not deallocate it, you can cause memory leaks. 

Function Pointers

CProgramming.com states: A function pointer is a variable that stores the address of a function that can later be called through that function pointer. This is useful because functions encapsulate behavior. For instance, every time you need a particular behavior such as drawing a line, instead of writing out a bunch of code, all you need to do is call the function.

Keyword 10

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$ 

Keyword 11

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);
}

Keyword 12

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$ 

SYSPROG Topics

Reading a file

Gets or extracts data from a file opened by an executing program. The information is stored in the buffer and used by the program, then the next read continues from where the last stopped. This continues to the Eod Of File flag or untill the file is closed.

Openning a file

In order for the system or a program to access or affect nother program during execution first the file must be opened by the program being executed.

Closing a file

After an executing program has finished with a file, and before run completion, any file which was opened by the program needs to be closed. This is done with the file close command.

File Accessing

File access can be dictated and restricted on an individual, group, and global scope. The abilities to read, write, and execute a file can each be set at each of these levels.

Writing a file

File Write puts data into a file. It can create a file if it doesn't already exist, and can append to or replace an existing file.

Keyword 6

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$ 

Keyword 7

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);
}

Unix domain sockets

Also called an IPC socket, a Unix domain socket is an endpoint for data communications that allows processes operating in the same system to exchange data. The APL for these sockets is similar to an internet socket, meaning the processes don't have to have the same ancestry.

These sockets are usually found on POSIX operating systems.

Coroutines

Coroutines are a pretty cool thing. As far as i've read they generalize subroutines like generators do, but are more powerful. They allow lots of entry points for suspending and resuming at different points.

The C programming guide says that Coroutines are best used when implementing components such as iterators, infinite lists, cooperative tasks and pipes.

Keyword 10

Keyword 11

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);
}

Keyword 12

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$ 

DATA Objectives

Objective 1

Choose the appropriate data structure for solving a given problem.

Method

I will do this by comming up with a simple, but applicable problem in code, and applying a data structure to resolve this prolem.

Measurement

This objective took me about 30 minutes to complete, I took not one, but two cases where a data structure needed to be implemented, and in both cases i was able to effectively, efficiently and quickly come up with a data structure/structures to solve each problem. The actual soving of each problem took seconds to think up, and seconds to minutes to code.

Analysis

I believe that based on my ability to quickly and effectively solve these data structure problems, I completed this objective perfectly.

I would also say that this objective could be altered just a little bit to give room for a small example of what we did for the objective, maybe asking for code if applicable, or some other type of example. If not, then this objective was very effective in helping me understand the reasoning behind this course.

Objective 2

Discuss the representation and use of primitive data types and built-in data structures

Method

I will research primitive data types and built-in-structures to determine their formal definition and a few examples, i will then bring that data before another individual to discuss the use of primitive data types and built-in-structures to help myself and the other individual better learn the uses and need for primitive data types and built-in-structures.

Measurement

This objective took me roughly 4-5 hours to complete, I reserched many of these data types and structures, and presented the information before an individual who proceeded to discuss and explain a few of these in depth. I now plan to record the use of these structures as learned in class and review them in a drive to better understand the representation and use of primitive data types and built-in-structures.

documentation of data

Primitive data types:

  1. Boolean
  2. Char
  3. Float
  4. Double
  5. Int
  6. String

Built-in-structures:

  1. Stacks
  2. Queues
  3. Linked Lists
  4. AVL trees
  5. Binary Search Trees
  6. Binary Heap
  7. Red Black Tree

and many others.

Analysis

I believe that yet again i achieved a very good understanding of the course objective and put a lot of effort into this objective. I believe it was done effectively and well and since there is much room for improvement with these topics, it is a good thing the class is only 25% done!

Objective 3

Describe common applications for each data structure described in class

Method

As each data structure appears, i will ask questions and record programs and applications of each data structure that is given in class in an attempt to have each of the structure described to me in an understandable way.

Measurement

So far so good, I have had linked lists explained to me in many ways by recording programs and using them to ask multiple questions to ensure that i understand the data structure that was being taught.

Analysis

The method used to complete this objective seems to be an effective one. It falls in line with my teachers objectives for the course and for our learning and has so far provided much valid information reguarding the data structures being taught. I believe it will continue to be an effective method of learning that will help not only me, but others to convert to this style aswell.

SYSPROG Objectives

Objective 1

better understand file I/O for efficient data processing

Method

State the method you will use for measuring successful academic/intellectual achievement of this objective.

Measurement

Follow your method and obtain a measurement. Document the results here.

Analysis

Reflect upon your results of the measurement to ascertain your achievement of the particular course objective.

  • How did you do?
  • Room for improvement?
  • Could the measurement process be enhanced to be more effective?
  • Do you think this enhancement would be efficient to employ?
  • Could the course objective be altered to be more applicable? How would you alter it?

Experiments

Experiment 1

Question

Can you enter an integer into the command line to be saved as argv[x] when argv[] is defined as data type char? What will happen when you try to print?

Resources

Hypothesis

I do not think the desired integer will be printed out unless the argv[x] is cast to an integer because argv has been defined as data type char.

Experiment

I will test this hypothesis by writing a small program to receive command line arguments. I will then print out a character to show that the program works properly, and then i will receive and print an integer saved under the same data type.

Data

Character Test

#include<stdio.h>
 
int main(int argc,char  **argv)
{
        printf("The character argument entered is:%s\n", argv[1]);
        return 0;
}
lab46:~/src/DataS/Project1$ ./experiment1 y
The character argument entered is:y
lab46:~/src/DataS/Project1$ ./experiment1 r
The character argument entered is:r
lab46:~/src/DataS/Project1$ ./experiment1 U
The character argument entered is:U

As you can see above, the program receives a character and then prints that character out, with no problems.

Integer Test

#include<stdio.h>
 
int main(int argc,char  **argv)
{
        printf("The character argument entered is:%s\n", argv[1]);
        return 0;
}
lab46:~/src/DataS/Project1$ ./experiment1 35
The character argument entered is:35
lab46:~/src/DataS/Project1$ ./experiment1 3
The character argument entered is:3
lab46:~/src/DataS/Project1$ ./experiment1 5
The character argument entered is:5

As you can see above, the program receives an integer and then prints that integer out, with no problems.

Changes

#include<stdio.h>
 
int main(int argc,char  **argv)
{
        int a=5; //new line
        int b;   // new line
        printf("The character argument entered is: %s\n", argv[1]);
        b = (a + *argv[1]); // new line
        printf("The results of our arithmetic: %d\n", b); // new line
        return 0;
}
lab46:~/src/DataS/Project1$ nano experiment1.c
lab46:~/src/DataS/Project1$ gcc -o experiment1 experiment1.c
experiment1.c: In function 'main':
experiment1.c:8: error: invalid operands to binary * (have 'int' and 'char *')
lab46:~/src/DataS/Project1$ nano experiment1.c
lab46:~/src/DataS/Project1$ gcc -o experiment1 experiment1.c
experiment1.c: In function 'main':
experiment1.c:8: warning: assignment makes integer from pointer without a cast
lab46:~/src/DataS/Project1$ nano experiment1.c
lab46:~/src/DataS/Project1$ gcc -o experiment1 experiment1.c
lab46:~/src/DataS/Project1$ ./experiment1 5
The character argument entered is: 5
The results of our arithmetic: 58

Based on the added arithmetic operation: b = 5 + 5, (The first 5 is the value of a, the second 5 is the command line argument), we see that 5 + 5 = 58???.

Analysis

Based on the data collected:

  • was your hypothesis correct?
    1. No
  • was your hypothesis not applicable?
    1. No, it just didnt cover all the possibilities
  • is there more going on than you originally thought? (shortcomings in hypothesis)
    1. Appearently, it appears i did not account for the computer just shoving whatever command line arguments it got into the array, and spitting them straight out as they were received.

Conclusions

Based on the experiment above, integer values can be saved into a character array, and printed directly from that array, but not manipulated without a cast. The reason for this is:

lab46:~/src/DataS/Project1$ gcc -o experiment1 experiment1.c
experiment1.c: In function 'main':
experiment1.c:8: error: invalid operands to binary * (have 'int' and 'char *')

This compiler error shows that an invalid operands to binary * was going on on line 8. Which when counted, is the line the code: b = (a + argv[1]) (at that point of compiling) was placed. This means that the integer was saved in the array with a binary representation that was not accessable by regular arithmetic means. But, the printing statement could print the integer because the binary given to the array was the same as what was printed out of the array, so the conversions in and out of the array were the same, and the integer could be expressed.

As i now understand, an integer can be saved into a character array via command line arguments, and printed with no errors, but not manipulated, which is wher ei was stuck. I had believe that the integer could not be manipulated or printed.

Experiment 2

Question

What is the question you'd like to pose for experimentation? State it here.

Resources

Collect information and resources (such as URLs of web resources), and comment on knowledge obtained that you think will provide useful background information to aid in performing the experiment.

Hypothesis

Based on what you've read with respect to your original posed question, what do you think will be the result of your experiment (ie an educated guess based on the facts known). This is done before actually performing the experiment.

State your rationale.

Experiment

How are you going to test your hypothesis? What is the structure of your experiment?

Data

Perform your experiment, and collect/document the results here.

Analysis

Based on the data collected:

  • was your hypothesis correct?
  • was your hypothesis not applicable?
  • is there more going on than you originally thought? (shortcomings in hypothesis)
  • what shortcomings might there be in your experiment?
  • what shortcomings might there be in your data?

Conclusions

What can you ascertain based on the experiment performed and data collected? Document your findings here; make a statement as to any discoveries you've made.

Experiment 3

Question

What is the question you'd like to pose for experimentation? State it here.

Resources

Collect information and resources (such as URLs of web resources), and comment on knowledge obtained that you think will provide useful background information to aid in performing the experiment.

Hypothesis

Based on what you've read with respect to your original posed question, what do you think will be the result of your experiment (ie an educated guess based on the facts known). This is done before actually performing the experiment.

State your rationale.

Experiment

How are you going to test your hypothesis? What is the structure of your experiment?

Data

Perform your experiment, and collect/document the results here.

Analysis

Based on the data collected:

  • was your hypothesis correct?
  • was your hypothesis not applicable?
  • is there more going on than you originally thought? (shortcomings in hypothesis)
  • what shortcomings might there be in your experiment?
  • what shortcomings might there be in your data?

Conclusions

What can you ascertain based on the experiment performed and data collected? Document your findings here; make a statement as to any discoveries you've made.

Part 2

Entries

October 6th, 2011

Ahh, the sweet smell of victory! On this sixth day of october i have already finished all 12 of my data structures keywords for this month!!! I have learned a LOT about sorting algorithms, and i am so ready to ask a lot of questions requarding sorting, especially selection sorting.

I am also working on 2 other programming projects. One is a doubly linked list implementation that is not going well, and the other is a String difference function that i now have to delete 3/4 of what i wrote because appearently, i took it out of context… I made the function to:

  1. Compare two strings and save the matching characters into an array
  2. concatenate the two given strings
  3. compare the concatenated string to the matching characters array and erase the charaters that match.

i guess it was a little much…

October 20th, 2011

Just finished coding Projects 2 and 3, also known as queue and stack. Pretty simple concepts, deffinitely fundamental to more advanced lists. The main things that i walked away from this project with are a better understanding of the ar command, and the creation of libraries.

On a side note, i want the old journals back… Whereas opuses are a great was organize your current projects and journal entries, they seem to be taking away from the great deffinition / learning time that we spent in class in C.

October 24th, 2011

Running in circles in dicrete, trying to finish this program, writing this library, understanding what the heck we are trying to accomplish! Then bam! Joe hits us with a program. We are going to take all of the functions we are trying to write and try to build a card game. We are going to use these broad functions to write a texas hold'em poker game. We are currently writing the game in a very high level pseudo code, so high we are outlining like such:

  • deal
  • shuffle
  • score
  • bank
  • evaluate hand
  • etc…

We are establing a rough list of major functions before breaking them down into smaller groups to get specific. After we have finished this major outline we will move into the functions individually and define elements like:

  1. Deal
    • how many players?
    • how many cards?
    • how big was the deck originally? 52 or less? larger?
    • who is the dealer?
    • etc…

October 31st, 2011

As this Opus is wrapping itself up, this will be my last edition to to it. I have finished:

  • 12 Data keywords
  • 12 Sys keywords
  • 1 Data objective
  • 1 Sys objective
  • 2 experiments
  • 1 retest
  • This is my 4rth dated entry.

Over the past week I have been studying concurrency based on forking. We are currently discussing forking in class through a half written program provided by matt. He is going to show us the functionality of the concept, and then let us loose on the code so that we can experiment and learn through trial and error. It is an awesome concept, really makes me wonder about Asynchronous I/0. I'd love to see a real-time application of the fork function in a already written and working program.

data Topics

Enqueuing

Enqueuing is most easily express through an example of a coffee shop. Since we all know that coffee shops always have a line, picute this! enqueuing is like someone walking up to the end of the line. yep, that's pretty much it!

example of enqueuing below.

    enqueue(&Q, (rand() % 100) + 1); /* Fill with random numbers from 1 to 100 */

Queues are common in computer programs, where they are implemented as data structures coupled with access routines, as an abstract data structure or in object-oriented languages as classes. Common implementations are circular buffers and linked lists.

Since most arrays are limited in space, queuing and dequeuing become very useful when editing them.

Dequeuing

Dequeuing can also be expressed via a coffee shop, so imagine you are standing in line. You walk to the counter and order a caramel cappacino, pay, and leave the line. As soon as you have left the front of the line, you have dequeued.

unsigned int k = 0;
    while (k < 100) {
        enqueue(&Q, (rand() % 100) + 1); /* Fill with random numbers from 1 to 100 */
        ++k;
    }
    k = 1;
    while (!queue_empty_p(&Q)) {
        int data;
        dequeue(&Q, &data);
        printf("(%d) %d\n", k, data);
        ++k;
    }

Queues are common in computer programs, where they are implemented as data structures coupled with access routines, as an abstract data structure or in object-oriented languages as classes. Common implementations are circular buffers and linked lists.

Since most arrays are limited in space, queuing and dequeuing become very useful when editing them.

Queue

A queue is a collection of items or data that are kept in a specified order and the principal operations performed on the collection are the addition and subtraction from the front and end of a line. A queue can be expressed as a singly linked list. As i said in other examples, a queue is like a line, you can leave the front, or join the back.

struct queue_node
{
    struct queue_node *next;    
    int data;
};
 
struct queue
{
    struct queue_node *first;
    struct queue_node *last;
};

This code may look familiar, that is because it is a linked list, a singly linked list to be exact.

Buffer overrunning

Buffer overrunning or overflowing is caused when a program, when writing to the buffer, overruns or overflows the boundary's of the buffer and writes to adjacent memory. This is called a violation of memory safety.

Wikipedia states: “Buffer overflows can be triggered by inputs that are designed to execute code, or alter the way the program operates. This may result in erratic program behavior, including memory access errors, incorrect results, a crash, or a breach of system security. They are thus the basis of many software vulnerabilities and can be maliciously exploited.”

Buffer overflowing is very unlikely because of the implementation of segfaults. This is done by checking that the stack has not been altered when the function returns. If it has been altered, the program exits with a segmentation fault. Three systems that do this are Stackguard, libsafe, and ProPolice, all of which are gcc compiler patches.

buffer underruning

Buffer underruning, or underflowing is cause when a buffer is sent data at a speed lower than the speed the data is being read from it. This means that whatever is reading from the buffer has to pause and wait for the stream to send data to the buffer so that the data can be read. In computing, this is most commonly refered to as lagging. “dang laggers!”.

This can be prevented/fixed by increasing the size of the buffer. If you wish to read data at a speed of 5, and the stream is sending it at a speed of 4, you are going to experience buffer underflow. So, you can increase you buffer size to 10, leaving you a 2 second window, or even to 300 to give you a full minute window. The unfortunate side to this is an increase in latency between the input and output, which is very undesirable in applications like video gaming.

LIFO or FIFO?

LIFO - Last in, First out. FIFO - First in, First out.

LIFO

LIFO can be expressed like a stack of plates. You can take a plate from the top, but no where else, hence the term “last in, first out”. By definition, a lifo is a linear structured list. YOu can take something from the top, but no where else. If you had such a thing as a linear array, where you loaded information in, but could not access any member, only the last one in, if you loaded the numbers {6,3,8,5,4} into the LIFO array in that order, the last one in would be 4, so the first one out, LIFO, would be 4.

FIFO

FIFO is slightly different, and can be expressed through the example of a hose. If you have a piece of hose that is 6“ in diameter, and you put a couple balls in it that are just over 3” in diameter, what ball is the first one out the other end? The first ball put in. Hence the term “first in, first out”. If you loaded the numbers {6,3,8,5,4} into a FIFO array in that order, the first one in would be 6, so the first one out, FIFO, would be 6.

Sorting algorithms

Sorting algorithms are an algorithm that puts members of a list in a specified order. ex:

  1. Numerical order
  2. Lexicographical order (character order)

Sorting is most useful when you plan to search through your data to find a specific value, or if you wish to output your data in any specific order, like sorted by last names, or age.

A few popular sorting methods:

  1. Bubble sort, which begins at the top of the data, and if the first is greater than the second, it swaps them and so on and so forth.
  2. Selection sort, this algorithm finds the lowest value and swaps it with the first position for n amount of times, making it more efficient.
  3. Insertion sort, this takes items one by one from the list and inserts them into their correct position.
  4. Shell sort, this runs on bubble sort and insertion sort by moving out of place elements more than one place at a time.

There are many more sorting methods, but for this example, we will only list these methods. Below is a C implementation of a bubble sort.

void bubbleSort(int numbers[], int array_size)
{
  int i, j, temp; 
  for (i = (array_size - 1); i > 0; i--)
  {
    for (j = 1; j <= i; j++)
    {
      if (numbers[j-1] > numbers[j])
      {
        temp = numbers[j-1];
        numbers[j-1] = numbers[j];
        numbers[j] = temp;
      }
    }
  }
}

Bubble sorting

Bubble sorting begins at the top of the data, and if the first is greater than the second, it swaps them and so on and so forth. Below is an example of a bubble sort.

void bubbleSort(int numbers[], int array_size)
{
  int i, j, temp;
  for (i = (array_size - 1); i > 0; i--)
  {
    for (j = 1; j <= i; j++)
    {
      if (numbers[j-1] > numbers[j])
      {
        temp = numbers[j-1];
        numbers[j-1] = numbers[j];
        numbers[j] = temp;
      }
    }
  }
}

This type of sorting is good for sorting arrays of numbers or letter into alphebetical or numerical order.

Insert sort

Insertion sort takes items one by one from the list and inserts them into their correct position. this type of sorting is very easy to implement and is very effective on small groups of data. Below is a quick look at some pseudo code for an insert loop in a 0 based array like in C.

 for j ←1 to length(A)-1
     key ← A[ j ]
     > A[ j ] is added in the sorted sequence A[0, .. j-1]
     i ← j - 1
     while i >= 0 and A [ i ] > key
         A[ i +1 ] ← A[ i ]
         i ← i -1
     A [i +1] ← key

below is a quick visual representation of what goes on during an insert sort:

  • 5 7 0 3 4 2 6 1 (0)
  • 5 7 0 3 4 2 6 1 (0)
  • 0 5 7 3 4 2 6 1 (2)
  • 0 3 5 7 4 2 6 1 (2)
  • 0 3 4 5 7 2 6 1 (2)
  • 0 2 3 4 5 7 6 1 (4)
  • 0 2 3 4 5 6 7 1 (1)
  • 0 1 2 3 4 5 6 7 (6)

Note: some items used from wikipedia as visual aids.

Shell sorting

Shell sorting was created by a man named Donald Shell in 1959. It runs on a sorting method devised by Donald, and finishes with insertion sort by moving out of place elements more than one place at a time. While this method of sorting may not be the best for all cases of data, it is highly effective on small and medium groups of data.

“The algorithm begins by performing a gap insertion sort, with the gap being the first number in the increment sequence. It continues to perform a gap insertion sort for each number in the sequence, until it finishes with a gap of 1. When the increment reaches 1, the gap insertion sort is simply an ordinary insertion sort, guaranteeing that the final list is sorted. ” ~wikipedia

This simply means that the numbers in the set of data are arranged into n number of columns, lets say 5 columns, the columns are then sorted so that they are in order, lowest to highest. The sorting then aranges them into n - x columns, say 3 columns, these columns again are sorted from lowest to highest, providing more number to be in the right order. The sorting will eventually get down to 1 column where a regular insertion sort is perfomed which arranges the data into one long column where all the data is properly sorted.

  • [ 13 14 94 33 82 25 59 94 65 23 45 27 73 25 39 10 ]
   13 14 94 33 82
   25 59 94 65 23
   45 27 73 25 39
   10
 
   10 14 73 25 23
   13 27 94 33 39
   25 59 94 65 82
   45
 
   10 14 73
   25 23 13
   27 94 33 
   39 25 59 
   94 65 82
   45
 
   10 14 13
   25 23 33
   27 25 59 
   39 65 73 
   45 94 82
   94

At this point the data is arranged again into a line and sorted using the insertion sort.

Selection sorting

Selection sort algorithm finds the lowest value and swaps it with the first position for n amount of times, O(n^2) making it inefficient on larger lists.

The algorithm operates as so:

  1. Finds the smallest value in the list
  2. Swaps that value with the value in the first position
  3. repeats these steps starting with the second position and incrementing each iteration.

This breaks the list up into two parts, the items already sorted, and the sublist of items stuck at the end, waiting to be sorted.

Below is an example of this algorithm sorting 6 elements:

  64 2 9 40 28 15 init.
  2 64 9 40 28 15  [1]
  2 9 64 40 28 15  [2]
  2 9 15 40 28 64  [3]
  2 9 15 28 40 64  [4]
  2 9 15 28 40 64  [5]

as you can see, this method is very effective on a small list, only taking 5 steps to sort 6 elements of data.

Implementation of this in C is below:

int iPos;
int iMin;
for (iPos = 0; iPos < n; iPos++)
{
    iMin = iPos;
    for (i = iPos+1; i < n; i++) 
    {
        if (a[i] < a[iMin]) 
        {
             iMin = i;
        }
    }
    if ( iMin != iPos ) 
    {
        swap(a, iPos, iMin);
    }
}

Heap sorting is a popular variant of this sorting algorithm as it has taken the basic structure and improved it using an implicit heap data structure.

Quick sort algorithms

Quick sort, a comparison algorithm, was designed by Tony Hoare and is faster in use than other O(nlogn) algorithms.

This alrogithm divides the list into 2 smaller sublist of higher and lower values. Quick sort can then sort these values by three steps:

  1. Pick a pivot element from the list
  2. Execute the partition operation by moving all elements less than the pivot to one side, and all elements greater than the pivot to the other side, resting the pivot in its final position.
  3. recursively sort the lists on either side of the pivot meaning the lower, and higher value lists.

cprogramming.com has given a simple pseudocode implementation of this topic:

   function quicksort('array') //pass the function the array of all elements
      create empty lists 'less' and 'greater' //sort out the lesser from the greater
      if length('array')1 //if 1 or less elements
          return 'array'  // an array of zero or one elements is already sorted
      select and remove a pivot value 'pivot' from 'array' //find a value in the center, or some other means of grabbing a pivot value
      for each 'x' in 'array' //for every element in the array
          if 'x''pivot' then append 'x' to 'less' //self explanitory
          else append 'x' to 'greater'
      return concatenate(quicksort('less'), 'pivot', quicksort('greater')) //return the final sorted array
 

sysprog Topics

user space or userland

User space is the area of memory where all user applications are run. This involves software that works with file manipulations and performs input/output. Each user process has its own virtual memory location and cannot access the memory locations of other proccesses without permission.

referenceed cprogramming.com

          The Jargon File

Kernel space

In computing, the kernel is the main part of most computer operating systems, it is a bridge between applications and the actual data processing done at the hardware level. The kernel's responsibilities include managing the system's resources and the communication between hardware and software components.

A computers operating system usually seperates virtual memory into kernel space and user space. Kernel space is reserved for running the kernel, kernel extensions, and most device drivers.

File descriptor

A file descriptor is an indicator for accessing a file. In C, and most other languages, a file descriptor is an integer, like C type int. Aside from this, every file proccess has 3 basic commands or operations. File in, File out, and Standard file error. A file descriptor is usualy an index for entry in a kernel-resident data structure that contains all the details for openning and accessing file. All applications pass commands via system calls where the files are then access by the kernel based on the commands sent.

Some operations that can be used with file descriptors are:

  • Read()
  • Write()
  • lseek()
  • fsync()
  • sendfile()

system calls

As refered to in the last keyword, a system call is how a program requests something from a computer systems kernel. This can include hardware or software related calls and can be things like scheduling, accessing the hard disk and many more.

System calls can be divided into 5 catagories:

  1. Proccess control
    1. load
  2. file management
    1. open, close
  3. device management
    1. read, write, reposition
  4. information maintenance
    1. get/set time or date
  5. communication
    1. send/receive messages

side note: On POSIX operating systems usual calls are:

  • open()
  • close()
  • read()
  • write()
  • wait()
  • fork()
  • exit()

File Types and properties

  1. Regular file -rw-r-—r– no modifier in first position
    1. Regular files are nothing special, they contain regular ascii text.
  2. Directory drwxr-xr-x a d in the modifier position
    1. A directory is refered to as a special file, and has to be the most common special file. The layout of directories are specified by the file system used. A directory is a file full of files. So a directory could be filled with more directories, that are filled with more directories, and so on, and all could contain regular files.
  3. Symbolic link lrwxrwxrwx a l in the modifier position
    1. A symbolic link is a reference to another file somewhere in the file system.
  4. Named pipe prw-rw—- s p as a modifier
    1. Pipes connect the output of one unix file to the input of another.
  5. Socket srwxrwxrwx an s as a modifier
    1. A socket allows for communication between two processes. These sockets can also send file descriptors by use of sendmsg() and rescmsg();
  6. Device file brw-rw—- , crw——-
    1. Device files are used to apply access rights and to direct operations on the files to the appropriate device drivers.
      1. Character device provides a serial stream of input or output
      2. block device is randomly accessable
  7. Door Dr–r–r–
    1. A door is a special file for communication between a client and a server, currently only in Sun Solaris operating system.

Pipes

A unix pipe provides a one way flow of data. If someone was to enter the command : who | sort , the unix shell who evaluate the who command, and send that data into the sort command as its entry data.

who —–> | —–> sort

write           read

The same goes for functions, as you can run a function that returns data, and pipe that data to another function

I/0 Redirection

I/0 redirection is simply redirection input or output signals to a location other than it's standard direction. For instance, “concatenate > confile” would send the output of the concatenate function to the file confile, truncating the data to the end of the file. To append data simply use » instead of >.

To redirect standard input, use concatenate < confile, resulting in concatenate using confile as input.

symbol
input <
output »
truncate >

I/0 Redirection and pipes

Since a unix shell reads commands from the left to the right, pipes and I/0 redirection can be used in conjunction with each other.

Ex: concatenate | file1 > sort > filesorted

This will run the program concatenate, pipe the output to a file so that sort can use the contents of that file and run a sorting expression and place the input in the file “filesorted”.

similarly, a pipe can be used in place of I/0 redirection, and vice versa.

Ex: concat1 | concat2 ~this will pipe the output of concat1 to be used as the input for concat2 Ex: concat1 > file1 concat2 < file1 rm tmpfile ~this is equivalent to the piping command above.

internet socket

An internet socket or network socket is an endpoint of a bidirectional inter-process communication flow across an Internet Protocol-based computer network, such as the Internet. ~wikipedia.

Internet sockets constitute as a mechanism for delivering incoming data packets to the appropriate application process or thread, and is all based on a combination of ip addresses, remote and local. Each socket is mapped by the operating system to an application. Within these application and the operating system, these sockets are refered to by an integer called a socket number.

Every socket has an address which is a combination of a port number and an ip address. Each socket also runs on a transport protocol, UDP, TCP, Raw IP, and many others.

Server Socket

A server creates on startup that remain in the listening state untill called by client programs.

For a listening TCP socket, the remote address presented by netstat may be denoted 0.0.0.0 and the remote port number 0.

A TCP server may serve several clients concurrently, by creating a child process for each client and establishing a TCP connection between the child process and the client.

Unique dedicated sockets are created for each connection. These are in established state, when a socket-to-socket virtual connection or virtual circuit (VC), also known as a TCP session, is established with the remote socket, providing a duplex byte stream. ~wikipedia

Therefore, a server socket is a socket created by a server at startup that runs in the listening state until called by a client program. These sockets establish a TCP connection between the server and client. IF it is a TCP server, multiple clients can be run simultaneously.

signals

A signal is a type of inter-process communication used in UNIX operating systems. It is a type of message sent to a process to notify it that an event happend. When the process gets the signal it stops it's normal flow and allows its signal handler to execute.

Ex:

SignalDescriptionSignal number on Linux
SIGABRTProcess aborted6
SIGALRMSignal raised by <tt>alarm</tt>14
SIGBUSBus error: “access to undefined portion of memory object”7
SIGCHLDChild process terminated, stopped (or continued*)17
SIGCONTContinue if stopped18
SIGFPEFloating point exception: “erroneous arithmetic operation”8
SIGHUPHangup1
SIGILLIllegal instruction4
SIGINT (POSIX)Interrupt2
SIGKILLKill (terminate immediately)9
SIGPIPEWrite to pipe with no one reading13

These are only a few of the 64 unix signals.

<signal.h> can also be referenced for more information on this topic.

Blocking vs. non-blocking

blocking and non-blocking are forms of input/output processing.

  • Blocking or Synchronous I/0 starts a process and waits for it to finish before continuing.
    • This would mean that step one would have to finish before step 2 could start, and step 2 would have to finish before step 3 could start, and so on and so forth.
  • non-blocking or Asynchronous I/0 starts a process and continues before that process is finished.
    • This type of processing deals with concurrency. This would allow steps 2, 3, and 4 to start before step one has terminated.

Operating systems implement many functions to use Asynchronous I/0 at many different levels. This type of processing only requires basic functionality to check if steps have checked in or completed, and alerts the other steps accordingly.

data Objective

Objective 1

Discuss the representation and use of primitive data types and built-in data structures

Method

I will research primitive data types and built-in-structures to determine their formal definition and a few examples, i will then bring that data before another individual to discuss the use of primitive data types and built-in-structures to help myself and the other individual better learn the uses and need for primitive data types and built-in-structures.

Measurement

This objective took me roughly 4-5 hours to complete, I reserched many of these data types and structures, and presented the information before an individual who proceeded to discuss and explain a few of these in depth. I now plan to record the use of these structures as learned in class and review them in a drive to better understand the representation and use of primitive data types and built-in-structures.

documentation of data

Primitive data types:

  1. Boolean
  2. Char
  3. Float
  4. Double
  5. Int
  6. String

Built-in-structures:

  1. Stacks
  2. Queues
  3. Linked Lists
  4. AVL trees
  5. Binary Search Trees
  6. Binary Heap
  7. Red Black Tree

and many others.

Analysis

I believe that yet again i achieved a very good understanding of the course objective and put a lot of effort into this objective. I believe it was done effectively and well and since there is much room for improvement with these topics, it is a good thing the class is only 25% done!

sysprog Objective

Objective

To develop a better understanding of concurrency.

Method

I will now start to ask questions about concurrency, and concurrency in the programs we are writing to see if there is any concurrency going on in our current programs. I will then document that concurrency and try to find or create more concurrency in other programs to better understand it.

Analysis

concurrency is sahweeeeet! We are going to be touching on the fork() function possibly this Friday in an attempt to really understand concurrency at its finest. It is running more than one thing at a time in a function. So if a function is going to process 400 items, but you need it done in the time it would take to process 100, you can fork the function 3 times and have each fork of the program process 100 items, all at the same time!

Experiments

Experiment 1

Question

What will happen if you give the squaring function [pow()] an invalid value? Like an array?

Resources

The man page for this function, and a test program to see hand in hand the results of at valid and invalid entry.

Hypothesis

Based on the manual recordings for the pow() function, a non integer value entered into the pow() will return a domain error.

Experiment

I will test this by running through a program and passing a non integer value for the y coordinate of the pow(x,y) function.

Data

z = pow(x,zero); where x is a positive integer and zero is a character array, does not evaluate. Instead, it returns the error:

  • error: cannot convert 'char*' to 'double' for argument '2' to 'double pow(double, double)'

showing that an evaluation where x > 0 and y is a non integer, cannot be executed.

Analysis

Based on the data collected:

  • was your hypothesis correct? yes
  • was your hypothesis not applicable? no
  • is there more going on than you originally thought? no, it was a simple hypothesis, that needed a simple evaluate to be executed.
  • what shortcomings might there be in your experiment? none
  • what shortcomings might there be in your data? none

Conclusions

Based on my evaluations, i ascertain that the pow function does exactly what it is supposed to, and returns a reasonable statement “domain error”. It returns this because its input cannot be non integer, meaning it cannot accept an array.

Experiment 2

Question

Can randomness create order??

Resources

Using the monroe method for estimating pi, we can get a rough estimate for pi by generating x amount of points in a quadrant. Also, monkeys are quite fast typers.

Hypothesis

I do believe that you can get pi, respectively, by using randomness.

Experiment

How are you going to test your hypothesis? By using the monte carlo method for calculating pi. I will create a function that runs through some math based on a user define number of iterations.

Data

Monte Carlo Function
/* Program to compute Pi using Monte Carlo methods */
 
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <string.h>
#define SEED 35791246
 
main(int argc, char* argv)
{
   unsigned long int niter=0;
   double x,y;
   int i,count=0; /* # of points in the 1st quadrant of unit circle */
   double z;
   double pi;
 
   printf("Enter the number of iterations used to estimate pi: ");
   scanf("%u",&niter);
 
   /* initialize random numbers */
   srand(SEED);
   count=0;
   for ( i=0; i<niter; i++) {
      x = (double)rand()/RAND_MAX;
      y = (double)rand()/RAND_MAX;
      z = x*x+y*y;
      if (z<=1) count++;
      }
   pi=(double)count/niter*4;
   printf("# of trials= %u , estimate of pi is %g \n",niter,pi);
        return 0;
}
Execution
lab46:~/src/DataS$ ./pi
Enter the number of iterations used to estimate pi: 1
# of trials= 1 , estimate of pi is 4 
lab46:~/src/DataS$ ./pi
Enter the number of iterations used to estimate pi: 2
# of trials= 2 , estimate of pi is 2 
lab46:~/src/DataS$ ./pi
Enter the number of iterations used to estimate pi: 4
# of trials= 4 , estimate of pi is 2 
lab46:~/src/DataS$ ./pi
Enter the number of iterations used to estimate pi: 16
# of trials= 16 , estimate of pi is 2.5 
lab46:~/src/DataS$ ./pi
Enter the number of iterations used to estimate pi: 256
# of trials= 256 , estimate of pi is 2.98438 
lab46:~/src/DataS$ ./pi
Enter the number of iterations used to estimate pi: 65536
# of trials= 65536 , estimate of pi is 3.14227 
lab46:~/src/DataS$ ./pi
Enter the number of iterations used to estimate pi: 4294967296
# of trials= 0 , estimate of pi is -nan 
lab46:~/src/DataS$ ./pi
Enter the number of iterations used to estimate pi: 131072
# of trials= 131072 , estimate of pi is 3.1423 
lab46:~/src/DataS$ ./pi
Enter the number of iterations used to estimate pi: 262144
# of trials= 262144 , estimate of pi is 3.14171 
lab46:~/src/DataS$ ./pi
Enter the number of iterations used to estimate pi: 524288
# of trials= 524288 , estimate of pi is 3.13922 

Analysis

Based on this data collected, as we increase the number of random numbers, we get a closer and closer approximation of pi.

  • was your hypothesis correct? yes
  • was your hypothesis not applicable? sorta
  • is there more going on than you originally thought? yes, but no shortcoming. there is a lot of math behind this theory.

Conclusions

The monte carlo method for computing pi is a great way to show that randomness can produce order.

Retest

State Experiment

Dave Schoeffler asks: How does the system handle unexpected input. Such as a character when an integer is expected.

Resources

  • Do you feel the given resources are adequate in providing sufficient background information? No, it was a link to a forum that was difficult to understand.
  • Are there additional resources you've found that you can add to the resources list? C pocket reference by O'Reilly
  • Does the original experimenter appear to have obtained a necessary fundamental understanding of the concepts leading up to their stated experiment? No
  • If you find a deviation in opinion, state why you think this might exist. I believe the system will either use the numeric value of the character or will just output a zero value.

Hypothesis

I believe that when you enter a character when an integer is expected the program will output an error and terminate. This will happen because the system does not know what with the character value.

  • Do you feel their hypothesis is adequate in capturing the essence of what they're trying to discover? Yes
  • What improvements could you make to their hypothesis, if any? Why does the system not know what to do with the value?

Experiment

  • Are the instructions correct in successfully achieving the results? Yes
  • Is there room for improvement in the experiment instructions/description? What suggestions would you make? I would provide more code execution snippets to show that for every character value entered, the output is still 0;
  • Would you make any alterations to the structure of the experiment to yield better results? What, and why? No

Data

I used the same code as Dave.

lab46:~/src/data$ ./inttest
Enter integer: 1
 Int is 1
lab46:~/src/data$ ./inttest
Enter integer: q
 Int is 0
lab46:~/src/data$ ./inttest
Enter integer: s
 Int is 0
lab46:~/src/data$

Analysis

Answer the following:

  • Does the data seem in-line with the published data from the original author? Yes
  • Can you explain any deviations? No deviations
  • How about any sources of error? None
  • Is the stated hypothesis adequate? Yes, the program is erroring out, but without a stated error.

Conclusions

Answer the following:

  • What conclusions can you make based on performing the experiment? The system does evaluate improper data, respectively.
  • Do you feel the experiment was adequate in obtaining a further understanding of a concept? Yes
  • Does the original author appear to have gotten some value out of performing the experiment? Yes
  • Any suggestions or observations that could improve this particular process (in general, or specifically you, or specifically for the original author). A little broader searching for information on the subject.

Part 3

Entries

November 14th, 2011

Spent the better part of Data Structures reading through the fork manual, called by “man 2 fork”. We then wrote ~/src/SysProg/fork/forkify.c , a simple program to demonstate the uses and returns of the fork function along with sleep, wait, and get pid. We also covered the pid_t data type. The program demonstrated a couple of good ways to check to see what child has what PID, and to make sure the children don't do anything the parent is supposed to, and vice versa.

To use the fork function, you need to include the unistd.h header file, called by “#include<unistd.h>”. accepts a void parameter returns the PID of the forked process

wait() will wait for PID's to die, and will clean up what they did.

November 18th, 2011

Today was a good day. We spent a decent amount of time on sorting algorithms, and then each implemented our own algorithms. I used a bubble sort that sorted an integer value array.The bubble sort is found in ~/src/DataS/bubble.c and the bubble sort part is below:

 while(swap == 0)
        {
                swap=1;
                for(i=1;i<count;i++)
                {
                        if(*(list+(i-1)) > *(list+i))
                        {
                                c = *(list+(i-1));
                                *(list+(i-1))=*(list+i);
                                *(list+i) = c;
                                swap = 0;
                        }
                }
                count--;
        }

While this is a simple algorithm, it has a lot wrapped up in it. It compares the elements of an array with each other and if they are equal, it swaps them by use of a dummy variable. One the for loop ends, the highest unsorted value is at the end of the array, therefore we can reduce how far into the array we need to compare.

Also, revenge is sweet ;)

November 26th, 2011

I am pretty sure I am going to devote this whole journal entry to Thanksgiving because this year, it was pretty special. This is the first holiday that my extended family has “hung around” before or after the meal. My mom accidentally turned the oven off while messing with the turkey timer, so food was delayed about an hour. Because of that, my family had to arrive early and i dont know if they enjoyed staying, but they stayed after aswell and we had a lot of quality family time for once. And the food, ohhhh…. Stuffing is the best part of thanksgiving, fo sho son. Not to mention that but the deserts we will have for decades! We had apples pies, chocolate pies, white chocolate cheesecake and pumpkin bars, soooo good!

Month Day, Year

This is a sample format for a dated entry. Please substitute the actual date for “Month Day, Year”, and duplicate the level 4 heading to make additional entries.

As an aid, feel free to use the following questions to help you generate content for your entries:

  • What action or concept of significance, as related to the course, did you experience on this date?
  • Why was this significant?
  • What concepts are you dealing with that may not make perfect sense?
  • What challenges are you facing with respect to the course?

Remember that 4 is just the minimum number of entries. Feel free to have more.

data Topics

Hash Tables

A hash table is a data structure that maps values known as keys, like an age, to the profiles of everyone that age. These tables use a hash function that turns the key into the index of the main array.

These tables are usually comprized of an array of linked lists, allowing you to create structures like directories fairly simple.

In a well-made hash table, the average iterations for each lookup is independent of the number of elements stored in the table. Many hash table designs also allow arbitrary insertions and deletions of key-value pairs, at a constant average cost per operation. photo courtesy of wikipedia

 

Graphs

Graph structures consist of a set of ordered pairs, formaly called arcs, or edges of entities called nodes. These nodes can be part of the graph structure, or be external entities represented by integer indices.

A graph data structure may also associate to each edge some edge value, such as a symbolic label or a numeric attribute (cost, capacity, length, etc.).

The basic operations provided by a graph data structure G usually include:

  • adjacent(G, x, y): tests whether there is an edge from node x to node y.
  • neighbors(G, x): lists all nodes y such that there is an edge from x to y.
  • add(G, x, y): adds to G the edge from x to y, if it is not there.
  • delete(G, x, y): removes the edge from x to y, if it is there.
  • get_node_value(G, x): returns the value associated with the node x.
  • set_node_value(G, x, a): sets the value associated with the node x to a.

Structures that associate values to the edges usually also provide:

  • get_edge_value(G, x, y): returns the value associated to the edge (x,y).
  • set_edge_value(G, x, y, v): sets the value associated to the edge (x,y) to v.

Different data structures for the representation of graphs are used in practice:

  • Adjacency list - Vertices are stored as records or objects, and every vertex stores a list of adjacent vertices. This data structure allows the storage of additional data on the vertices.
  • Incidence list - Vertices and edges are stored as records or objects. Each vertex stores its incident edges, and each edge stores its incident vertices. This data structure allows the storage of additional data on vertices and edges.
  • Adjacency matrix - A two-dimensional matrix, in which the rows represent source vertices and columns represent destination vertices. Data on edges and vertices must be stored externally. Only the cost for one edge can be stored between each pair of vertices.
  • Incidence matrix - A two-dimensional Boolean matrix, in which the rows represent the vertices and columns represent the edges. The entries indicate whether the vertex at a row is incident to the edge at a column.

Some information derrived and simplified from wikipedia

 

Binary tree

A binary tree is a node based data structure that has two main branches, one to the left with lesser keys, and one to the right with greater keys. The placement of each node is based on it's key, and not the other values of the node. The tree is formed based on a root node that is assigned a pivot key. All other keys entered then go either to the left or right of that root node based on the rank of that key. and so on and so forth through the tree until they reach the bottom of their branch where they become a leave of the tree.

This is an effective method of data searching because after the first check, at the root node, half of the tree is no longer a possibility because the check will send the tmp variable to either the lesser or greater value branch of the root node.

Below is a sample of code that is used in a node based tree.

                Node *grep;
                grep = malloc(sizeof(Node *));
                mytree -> tmp = mytree -> root;
                while(mytree -> tmp -> value != val)
                {
                        if(val < mytree -> tmp -> value)
                        {
                                if(mytree -> tmp -> smaller != NULL)
                                        mytree -> tmp = mytree -> tmp -> smaller;
                                else
                                        mytree -> tmp -> smaller = grep;
                        }
                        else
                        {
                                if(mytree -> tmp -> bigger != NULL)
                                        mytree -> tmp = mytree -> tmp -> bigger;
                                else
                                        mytree -> tmp -> bigger = grep;
                        }

Insertion

Insertion is where a value, or key is added at an arbitrary point in a list. Observe a single-dimension array for example. This array contains the values 3, 7, 13, 21, 45, 93 and we wish to insert the value 33. If the list is ordered, the value will be inserted between the values 21 and 45. If not, the value can be inserted at any point in the array.

Tree *add(Tree *mytree, char val)
{
        if(mytree -> root != NULL)
        {
                Node *grep;
                grep = malloc(sizeof(Node *));
                mytree -> tmp = mytree -> root;
                while(mytree -> tmp -> value != val)
                {
                        if(val < mytree -> tmp -> value)
                        {
                                if(mytree -> tmp -> smaller != NULL)
                                        mytree -> tmp = mytree -> tmp -> smaller;
                                else
                                        mytree -> tmp -> smaller = grep;
                        }
                        else
                        {
                                if(mytree -> tmp -> bigger != NULL)
                                        mytree -> tmp = mytree -> tmp -> bigger;
                                else
                                        mytree -> tmp -> bigger = grep;
                        }
                }
        }
        return mytree;
}

Removal

Removal is pretty straight forward, just as insertion was. Removal refers to the removing, pop, or displacement of an arbitrary value/key or node. If we go back to the example of an array, this time containing the values 3,7,13,21,33,45,93 with 33 added from the insertion operation. And we remove an arbitrary value, say 33, we will then turn the array back to the starting array of 3,7,13,21,45,93, showing that insert and remove are opposites.

#include"tree.h"
 
Tree *del(Tree *mytree, char val)
{
        if(mytree -> root != NULL)
        {
                mytree -> tmp = mytree -> root;
                while(mytree -> tmp -> value != val)
                {
                        if(val < mytree -> tmp -> value)
                        {
                                if(mytree -> tmp -> smaller -> value = val)
                                {
                                        mytree -> solo = mytree -> tmp -> smaller;
                                        mytree -> tmp2 = mytree -> solo -> bigger;
                                        while(mytree -> tmp2 -> smaller != NULL)
                                                mytree -> tmp2 = mytree -> tmp2 -> smaller;
                                        mytree -> tmp2 -> smaller = mytree -> solo -> smaller;
                                        mytree -> tmp -> smaller = solo -> bigger;
                                        mytree -> solo -> smaller = NULL;
                                        mytree -> solo -> bigger = NULL;
                                        free(mytree -> solo);
                                }
                                else
                                        mytree -> tmp = mytree -> tmp -> smaller;
                        }
                        else
                        {
                                if(mytree -> tmp -> bigger -> value = val)
                                {
                                        mytree -> solo = mytree -> tmp -> bigger;
                                        mytree -> tmp2 = mytree -> solo -> bigger;
                                        while(mytree -> tmp2 -> smaller != NULL)
                                                mytree -> tmp2 = mytree -> tmp2 -> smaller;
                                        mytree -> tmp2 -> smaller = mytree -> solo -> smaller;
                                        mytree -> tmp -> smaller = solo -> bigger;
                                        mytree -> solo -> smaller = NULL;
                                        mytree -> solo -> bigger = NULL;
                                        free(mytree -> solo);
                                }
                                else
                                        mytree -> tmp = mytree -> tmp -> bigger;
                        }
                }
        }
        return mytree;
}

Searching means to move about a data structure to see if a given value or key is in that data arrangement. This can be best explained through an example of a linked list search.

#include"linkedlist.h"
Node *find(List *mylist, char f) //Mylist is the list we are looking through, f is the value to find.
{
        Node *test2; // tmp node for moving about the list.
        test2 = mylist -> start;
        while((test2 != NULL)  && (test2 -> value != f)) //while list is populated and test2 does not find the value
        {
                if(test2 -> next != NULL) //while list is populated
                {
                        test2 = test2 -> next;  //move to next spot
                }
        }
        if(test2 -> value != f)
        {
                test2 -> value = #;
        }
        return test2; //returns the address of the node that contains the value, or # if not found.
}

Tree Traversal(pre-order, post-order and in-order

Tree traversal is visiting each node in a tree structure to examine or update those nodes. Three traversal structures are classified by the way each node is visited.

pre-order

  1. Visit the root
  2. Visit the left branch
  3. visit the right branch

post-order

  1. Visit the left branch
  2. Visit the right branch
  3. Visit the root

in-order

  1. Visit the left branch
  2. Visit the root
  3. Visit the right branch

Merge Sort

Merge sort is a “divide to conquer” sorting algorithm that operates on a O(n logn) comparison basis.

A merge sort works like so:

  1. If the list only has 0 or 1 elements, then it is already sortd
  2. If not, then the list is recursively divided into two sublists about half the size
    1. 2 lists, then 4 lists, then 8 lists, etc… till each list has 1 element.
  3. The list is then compared element by element, recursively grouping the lists into pairs
    1. 8 lists, then 4 lists, then 2 lists, then 1
  4. Once the lists are all combined, the merge sort is complete.

A binary search is a O(1) best case, O(logn) worst case sorting algorithm that works off from an already sorted array. This method takes a given key and compared it to the middle key of the array. If the given key is greater, the index of the array is moved one to the right. If the given key is less, the index is moved to the left one. This operation is repeated until the desired key is found, or the array index's next is null. In this case a special “end of file” indicator is returned.

Computational Complexity

  1. Computational complexity is a theory in computer science that classifies problems based on their difficulty.
  2. A computational problem is a problem that can be solved by a computer through a set of mathematical instructions.

These computational problems are given a complexity level based on the amount of resources need to perform. The computer defines these levels based on a set of models of computation that project how much time and storage needed for the problem to complete.

Asymptotic Notation

This Notation is used to classify different algorithms based on the time they take to complete. Each algorithm has three recorded times, a worse case, best case, and average case. The time it takes for each case is given in a mathmatical expression like (nlogn) or n^2 where n is the number of iterations of the algorithm.

  1. Best case is when the time taken to evaluate the algorithm is the minimum. In a sorting algorithm this would mean a best case would be just n.
  2. Worst case would be, well, lets just say someone actually made an algorithm that take n^infinity.
  3. Average case is just as it sounds, the average time it takes for x number of algorithms to evaluate. Evaluated by:
    1. (total time for all algorithms)/(x number of algorithms)

Big-O

Big-O is roughly affirmed with the upper bound asymptote or as the worst possible case.

Big-Theta

Describes the case where the upper and lower bounds of a function are on the same order of magnitude.

Big-Omega

Describes the lower bound, or best case.

Memory Allocation

Memory is managed statically, automatically, and dynamically. In this example we will look at static versus dynamic allocation.

Dynamic

Static memory is not adequate for all situations. You might want to make a variable that could contain one word, or 1000 sentances, but you don't want to allocate enough memory for 1000 sentances if you are just storing one word. That is where Dynamic memory allocation comes in and Malloc() is an example of this. Dynamic memory is allocated from the heap, so as long as there is memory left to allocate, a program can use as much as needed, or as little as needed. A linked list is a great example of Dynamic memory allocation. If the user wants to use more memory storage the program can allocate memory like so:

        Node* tmp3;
        tmp3 = (Node *) malloc (sizeof(Node));
        tmp3 -> value = d;

This will create a node structure based on some Struct, and allocate memory of a pre-defined size, the size of the Node, and place a specified value in that node. This can be called recursively or in a loop as needed, thus creating dynamic memory allocation. Since this memory was allocated via Malloc(), it can be removed with the free() function, thus freeing up the space used my malloc().

Static

Static memory is allocated and fixed for the lifetime of the program. This memory is allocated on the stack and comes and goes as the functions call for it, but still exists whether called or not. This can be useful for programs that know exactly how much memory will be used during the lifetime of the program, and will never need to allocate more that a given amount of memory.

   int input;
   printf("please enter input");
   scanf("%d", input);

This will allocated static memory and same input into it, which will then exist for the lifetime of the program whether it is used or not, and cannot be freed by functions like free().

sysprog Topics

Named Pipes

A named pipe is a more indepth pipe from unix computer systems, and is an inter-process communicator. A regular pipe is usually unnamed because it only exists and acts anonymously while the program is runnning. A named pipe exists after the life on the program and must be deleted. It is called System-Persistent.

mkfifo my_pipe
gzip -9 -c < my_pipe > out.gz
cat file > my_pipe
rm my_pipe

File locks

File locking restricts access to one user or process at a time to avoid changes being over written (interceding updates).

  • If John checks the file out
  • Then Mark checks the same file out
  • Then john changes the phone number in the file and saves it
  • Then Mark, who has an original copy changes the address and saves the file
  • johns changes are lost

Most systems support file locking to prevent updates happening in this fashion. Therefore Mark must wait for John to finish before he can check a copy of the file out. Use of file locking should be monitored as a poor use of it can cause a gridlock in the system.

ID's

ID's are numbers assigned to users and groups on a Linux system(and possibly others) so that the kernel has a way to address them. This is used mainly for permissions. One can set individual permission levels or group levels and place individuals into that group.

A users UID and GID can both be attained through the id command.

lab46:~$ id
uid=5689(bkenne11) gid=5000(lab46) groups=5000(lab46),1734(sys),1738(data),5689(bkenne11)
lab46:~$

User ID

Once you log into a Linux system you become a number to the kernel. This number is your user ID. This ID helps to set permissions for what user number # can do. Exapmles of this in affect are user ID 0. The Zero user is Root and enjoys unlimited/unrestricted access to the system.

Group ID

A group can be created with special permissions that allows it's member to have the permissions of the group. You then can create a group with permissions to manage the mail client of a system so that those users and those users only have special rights to manage or maintain the mail client.

Device files

A deivce file, or special file, is like an interface for software to interact with device drivers via standard input and output. These usually conect periferals like printers, mice, keyboards and serial ports but can also be used to access more specific things like disk partitions.

There are two general kinds of device files in Unix-like operating systems, known as character special files and block special files. The difference between them lies in how data written to and read from them is processed by the operating system and hardware.

CONReceives typed data until Z (Ctrl-Z) is pressed.Prints data to the console.
RNN/APrints text to the printer.
AUXReads data from an auxiliary device, usually a serial port.Sends data to an auxiliary device, usually a serial port.
NULReturns null or no data.Discards received data.
CLOCK$Returns system real-time clock.N/A
LPT1 (also 2–9)Reads data from the selected parallel portSends data to the selected parallel port
COM1 (also 2–9)Reads data from the selected serial portSends data to the selected serial port

Directories

A typical file system may contain thousands upon thousands of files which can be organized by Directories(often called folders). These directories can hold files and or other directories making a tree system of files. The files contained within a folder are called subfiles or subfolders. For example:

You have a file system that is phone book. You can have a directory call phbook that contains directories for all leters of the alphabet, which contain directories for all people with the last name -blank-, which are files of the information of each person.

On unix based systems:

comandaction
cdchange current directory
lslist current directory
mkdirmake directory called ?
rm -dremove directory ?
mvmove directory

Buffering

A buffer is a place where data you have just recieved is stored once downloaded from somewhere like the internet. This given you an opportunity to work on that data in real time incase your download speed is too slow to work on the data as it is recieved. This is useful when rendering videos off from the internet on sites like youtube or hulu, but can also be used in file reading. On unix-like system the command read-partial can be used to read a file to a buffer up to a certain point where it can then be read to another file or etc.

Shared Memory

Shared memory is memory that can be simultaneously accessed by multiple programs on a running system to provide communication between those programs.

Shared memory can also be refered to as a large block of RAM that can be accessed by multiple CPU's on a multi-cpu system.

Unix domain sockets

Also called an IPC socket, a Unix domain socket is an endpoint for data communications that allows processes operating in the same system to exchange data. The APL for these sockets is similar to an internet socket, meaning the processes don't have to have the same ancestry.

These sockets are usually found on POSIX operating systems.

Coroutines

Coroutines are a pretty cool thing. As far as i've read they generalize subroutines like generators do, but are more powerful. They allow lots of entry points for suspending and resuming at different points.

The C programming guide says that Coroutines are best used when implementing components such as iterators, infinite lists, cooperative tasks and pipes.

A good time to use a file link is when you have several different programs that need to use the same data, but are in different directories. The programs can of course call the files with their complete file name, but that can get slopy and can be hard to change if the file is moved. This is when file links come in handy.

A file link is a directory entry that refers to a file. There are a few ways to do this, but the most common is a symbolic link. A symbolic link is a special file that contains a refrence to another file or directory by it's pathname. Any program that uses a symbolic link treats it as if it is operating on the target file.

synchronizing data

The process of keeping consistency with data from a source to a target storage device and vice versa is called data synchronization. In english, this process harmonizes data contained in data storage spaces such as files or file servers. A good example of file synchronization is a USB flash drive or a hard drive of a home computer. This process prevents copying already identical files, saving a lot of time.

To sum it up, It creates one big data storage of one copy of all the files, instead of copying every source and having multiples of each file.

Threads

My last keyword for my fall 2011 opus, almost sad, but deffinitely not! I have chosen threads because it is something that has always avoided my grasp. I have wanted to learn about and understand a thread for a long time, so here we go!

A thread is a thread of execution, or a unit of processing that can be scheduled by the operating system to evaluate at the scheduled time. Since a thread is the smallest unit of processing, a thread is actually contained within a process. Not just that, but there can be multiple threads inside of a process which can share resources like memory, but only inside that process. Multithreading can be expressed like multiple contractors building the same house, at the same house, and working off from the same building plan, but maybe not the same pages.

A few notes about threads:

  1. They share their address space
  2. they exist as subsets of a process
  3. context switching between threads is faster than processes.

data Objective

Objective

Describe common applications for each data structure described in class

Method

As each data structure appears, i will ask questions and record programs and applications of each data structure that is given in class in an attempt to have each of the structure described to me in an understandable way.

Measurement

So far so good, I have had linked lists explained to me in many ways by recording programs and using them to ask multiple questions to ensure that i understand the data structure that was being taught.

Analysis

The method used to complete this objective seems to be an effective one. It falls in line with my teachers objectives for the course and for our learning and has so far provided much valid information reguarding the data structures being taught. I believe it will continue to be an effective method of learning that will help not only me, but others to convert to this style aswell.

sysprog Objective

Objective

explore efficient solutions to data- and processing- intensive problems.

Method

Exploring Asymptotic algorithms for data processing.

Measurement

Going very well, i have seen a lot of algorithms for data processing and I can see how it is very important to be consistently developing solutions to data and processing intensive problems.

Analysis

  • How did you do? very well
  • Room for improvement? Always, there will always be a need and room for improvement in data processing.
  • Could the measurement process be enhanced to be more effective? If I knew it could, i would have.
  • Do you think this enhancement would be efficient to employ? N/A
  • Could the course objective be altered to be more applicable? How would you alter it? Yes, remove the last two questions.

Experiments

Experiment 1

Question

Can I implement a tree program through a library and not use function prototypes? What will happen if I don't?

Resources

Hypothesis

I think that I will be able to compile and run my program properly without using prototypes, but i am guessing i will get some warning considering so.

Experiment

I am going to use a previously written tree library and remove it's prototypes, then compile.

Data

Bingo! When recompiling this tree structure without function prototypes it went through! I ran the program and everything worked properly, give or take getting 2 unrelated compiler warnings. It looks like the compiler doesn't need prototypes.

code

main
#include"tree.h"
 
int main()
{
        int input;
        Tree *mytree;
        mytree = malloc(sizeof(Tree *));
        while(input != -1)
        {
                printf("Enter a positive integer value: ");
                scanf("%d", &input);
                if (input != -1)
                        mytree = add(mytree, input);
        }
        printf("Enter - 1 - to add a node\n");
        printf("Enter - 2 - to delete a node\n");
        printf("Enter - 3 - to print the nodes in post order\n");
        scanf("%d", &input);
        if(input == 1)
        {
                printf("Enter a positive integer value: ");
                scanf("%d", &input);
                mytree = add(mytree, input);
        }
        else if(input == 2)
        {
                printf("These are the values in the tree,\n");
                printf("please enter a value to delete: ");
                postpr(mytree -> root);
                scanf("%d", &input);
                del(mytree, input);
        }
        postpr(mytree -> root);
        printf("\n");
        return 0;
}
add
*
* add.c, a tree manipulation function.
* Made by Brandon Kennedy for Data Structures
* Semester: Fall: 2011
*
* prototype: Tree *add(Tree *, char);
* Returns a tree struct containing the address of the root, tmp, tmp2, and solo nodes..
*/
#include"tree.h"
 
Tree *add(Tree *mytree, int val)
{
        Node *grep;
        grep = malloc(sizeof(Node *));
        grep -> value = val;
        if(mytree -> root != NULL)
        {
                mytree -> tmp = mytree -> root;
                while(mytree -> tmp -> value != val)
                {
                        if(val < mytree -> tmp -> value)
                        {
                                if(mytree -> tmp -> smaller != NULL)
                                {
                                        mytree -> tmp = mytree -> tmp -> smaller;
                                        printf("smaller\n");
                                }
                                else
                                        mytree -> tmp -> smaller = grep;
                        }
                        else
                        {
                                if(mytree -> tmp -> bigger != NULL)
                                {
                                        mytree -> tmp = mytree -> tmp -> bigger;
                                        printf("bigger\n");
                                }
                                else
                                        mytree -> tmp -> bigger = grep;
                        }
                }
        }
        else
        {
                mytree -> root = grep;
        }
        return mytree;
}
delete
#include"tree.h"
 
Tree *del(Tree *mytree, char val)
{
        if(mytree -> root != NULL)
        {
                mytree -> tmp = mytree -> root;
                while(mytree -> tmp -> value != val)
                {
                        if(val < mytree -> tmp -> value)
                        {
                                if(mytree -> tmp -> smaller -> value = val)
                                {
                                        mytree -> solo = mytree -> tmp -> smaller;
                                        mytree -> tmp2 = mytree -> solo -> bigger;
                                        while(mytree -> tmp2 -> smaller != NULL)
                                        {
                                                mytree -> tmp2 = mytree -> tmp2 -> smaller;
                                        }
                                        mytree -> tmp2 -> smaller = mytree -> solo -> smaller;
                                        mytree -> tmp -> smaller = mytree -> solo -> bigger;
                                        mytree -> solo -> smaller = NULL;
                                        mytree -> solo -> bigger = NULL;
                                        free(mytree -> solo);
                                }
                                else
                                        mytree -> tmp = mytree -> tmp -> smaller;
                        }
                        else
                        {
                                if(mytree -> tmp -> bigger -> value = val)
                                {
                                        mytree -> solo = mytree -> tmp -> bigger;
                                        mytree -> tmp2 = mytree -> solo -> bigger;
                                        while(mytree -> tmp2 -> smaller != NULL)
                                        {
                                                mytree -> tmp2 = mytree -> tmp2 -> smaller;
                                        }
                                        mytree -> tmp2 -> smaller = mytree -> solo -> smaller;
                                        mytree -> tmp -> smaller = mytree -> solo -> bigger;
                                        mytree -> solo -> smaller = NULL;
                                        mytree -> solo -> bigger = NULL;
                                        free(mytree -> solo);
                                }
                                else
                                        mytree -> tmp = mytree -> tmp -> bigger;
                        }
                }
        }
        return mytree;
}
print
#include"tree.h"
 
void postpr(Node *lantro)
{
        if(lantro != NULL)
        {
                postpr(lantro -> smaller);
                printf("%d, ", lantro -> value);
                postpr(lantro -> bigger);
 
        }
}
tree.h
#ifndef _TREE_H_ #define _TREE_H_ #include<stdlib.h> #include<stdio.h>
 
struct node{
        char value;
        struct node *bigger;
        struct node *smaller;
};
typedef struct node Node;
 
struct tree{
        struct node *root;
        struct node *tmp;
        struct node *tmp2;
        struct node *solo;
};
typedef struct tree Tree;
 
#endif

Analysis

Based on the data collected:

  • was your hypothesis correct? Not entirely. I was able to run the program, but i didn't get any related compile time errors.
  • was your hypothesis not applicable? no.
  • is there more going on than you originally thought? Yes. It isn't that the compiler should spit out errors, but that the compiler cannot see the errors that are happening.
  • what shortcomings might there be in your experiment? If i knew, I would have changed them!
  • what shortcomings might there be in your data? If i knew, I would have collected the data!

Conclusions

It appears(by reading and reviewing data) that if you don't include function prototypes, the compiler cannot see potential errors like:

  • If you call a function that expect 2 arguments, and you only give it one.
    • In this case, the function will have to get that argument from the stack, which could be anything!

In conclusion, include prototypes! It only takes a line per prototype, and saves you from a lot of potential trouble.

Experiment 2

Question

How much more memory does a linked list use than an array?

Resources

The C programming guide Cprogramming.com/threads%read\input

Hypothesis

I don't feel that a linked list should take up very much more memory than an array.

They have the same basic structure, a next and a previous. they may be incrememnted differently, but they hold the same basic structure.

Experiment

To test this hypothesis i am going to write a quick program that will create an array with an integer value, and a struct with an integer value. I will then use the sizeof command to retrieve the size of both data structures and multiply then by 100 to show a decent difference in their memory uses.

Data

#include<stdio.h>
struct node {
   int value;
};
typedef struct node Node;
int main()
{
   int array[10];
   int i;
   for (i=0;i<10;i++)
      array[i] = i;
   printf("node size is %d in bytes\n", (sizeof(Node)*100));
   printf("array is %d bytes\n", (sizeof(array[3])*100));
   return 0;
}

Done with the above code:

lab46:~$ ./exper
node size is 400 in bytes
array is 400 bytes
lab46:~$

Done with the code manipulated so that the array is of type char.

lab46:~$ ./exper
node size is 400 in bytes
array is 100 bytes
lab46:~$

Analysis

Based on the data collected:

  • was your hypothesis correct? No, The array and linked list took up the same amount of memory.
  • was your hypothesis not applicable? No
  • is there more going on than you originally thought? No

Conclusions

As far as I can conclude from this experiment, the data structure used matter none in reference to the memory space allocated when creating/using that structure. The only thing that affects the memory used is the data type of the variable being allocated. In this experiment, I gace two command line examples. The first was a linked list node and an array slot both of type int. They, when sized, use the same amount of memory to store the integers they are given. In the second CLI example the node structure in of type int, and the array is of type char and this is where we can see some change. The node of type int takes up four bytes while the array slot of type char takes up 1 byte, showing that these data structure are only the size (memory wise) of the data types allocated inside of them.

The Catch!

Thought this experiment was over? Well think again!

The above experiment is correct in it's context, but only because the node structure created is for a linked list of one node. What happens while i make it a singly linked list? or a doubly linked list?

Lab46 is a 64 bit system that has char value of 1 byte and int value of 4 bytes, this is important. That means that when you created a variable with the data type char, the system allocates it a block size of 1 byte, same for an integer, but of block size 4. The next block size after that is 8 then 16, also important. When the node structure for the above linked list was created:

#include<stdio.h>
struct node {
   int value;
};
typedef struct node Node;

Inside of the structure there is only an integer value, nothing else, causing this node to only use 4 bytes of data. This is fine for a list of one node, but what about an 10 nodes? or 100? Since linked lists use pointers to nodes to keep track of the address of other nodes, these pointers must be taken into account also. On lab46, the system allocates 8 bytes for a pointer to a node.

#include<stdio.h>
struct node {
   int value;
   struct node *next;
};
typedef struct node Node;

This singly linked list will take up memory for two things:

  1. A data type of int 1 byte
  2. A pointer to a node 8 bytes

total bytes: 9 Since the block sizes around this are 8 and 16, the system will allocate 16 bytes of data and pad the unneeded space. But what does that mean for a doubly linked list?

#include<stdio.h>
struct node {
   int value;
   struct node *next;
   struct node *prev
};
typedef struct node Node;

This doubly linked list will take up memory for:

  1. A data type of int 1 byte
  2. a pointer to a node 8 bytes
  3. a pointer to a node 8 bytes

total bytes: 17 Since this is above 16, we have to go to the next block size, which is 32.

So, to REALLY conclude, while a data type is worth it's respective bytes no matter the data structure it is contained in, the data structure can need other data types allocated to operate. Therefore:

  1. A linked list will always require at least 8 bytes of data to operate
  2. A doubly linked list will always require at elast 16 bytes of data to operate
  3. an array, well, doesn't need squat…

I think that covers everything…

State Experiment

Karl Kraus.

Question: After learning about enum I was curious as to what value it starts at, is it 0 or 1? Or possibly some other random value?

Resources

Evaluate their resources and commentary. Answer the following questions:

  • Do you feel the given resources are adequate in providing sufficient background information? yes, the material is very straight forward, no gaps for questions.
  • Are there additional resources you've found that you can add to the resources list? The manual page for emun()
  • Does the original experimenter appear to have obtained a necessary fundamental understanding of the concepts leading up to their stated experiment? Yes, enum is a simple function, and there was an adequate understanding of it prior to the project.
  • If you find a deviation in opinion, state why you think this might exist. N/A

Hypothesis

State their experiment's hypothesis. Answer the following questions: there was no hypothesis stated

  • Do you feel their hypothesis is adequate in capturing the essence of what they're trying to discover? N/A
  • What improvements could you make to their hypothesis, if any? I would actually write a hypothesis

Experiment

Follow the steps given to recreate the original experiment. Answer the following questions:

  • Are the instructions correct in successfully achieving the results? There are no instructions, but the code given suffices.
  • Is there room for improvement in the experiment instructions/description? What suggestions would you make? Nothing to say, the project is straight forward enough
  • Would you make any alterations to the structure of the experiment to yield better results? What, and why? No

Data

#include <stdio.h>
 
int main()
{
    enum days{sunday, monday, tuesday, wednesday, thursday, friday, saturday};
    printf("%d\n", sunday);
    printf("%d\n", monday);
 
    return 0;
}
lab46:~/src$ ./karlretest
0
1
lab46:~/src$

Analysis

Answer the following:

  • Does the data seem in-line with the published data from the original author? yes
  • Can you explain any deviations? none
  • How about any sources of error? none
  • Is the stated hypothesis adequate? there is no stated hypothesis

Conclusions

Answer the following:

  • What conclusions can you make based on performing the experiment? The enum function gives the given set elements a numberic value that can be manipulated with mathmatical expressions like +,=,-.
  • Do you feel the experiment was adequate in obtaining a further understanding of a concept? Yes
  • Does the original author appear to have gotten some value out of performing the experiment? yes
  • Any suggestions or observations that could improve this particular process (in general, or specifically you, or specifically for the original author). none
opus/fall2011/bkenne11/start.txt · Last modified: 2014/01/19 04:20 by 127.0.0.1