User Tools

Site Tools


opus:fall2011:bh011695:part1

Part 1

Entries

September 19, 2011

Doubly Linked List Class

Well, I think I'm finally at a good point with my linked list class. I may add a few more functions that, perhaps, compare linked lists to see if they're the same or copy one linked list into another linked list. As it stands right now many of the functions are overloaded to handle multiple data types. I can append and insert nodes into the list as well as delete nodes. Creating this class and implementing it really boosted my knowledge on doubly linked lists. At first, I was like, “huh?” but now I feel I've reached a decent level of understanding. Doing the insert functions was where I really had to think about things. Dropping a new node and relinking all the pointers to the right places really hurts the brain at first. I'd also like to try an implementation with templates. This will minimize the number of functions and, hopefully, will really cement my understanding of the subject.

September 23, 2011

Function Pointer

I think I've come to understand the whole function pointer thing. It was just hard to come up with a practical use for them. In, C++ I remember discussing that the only difference between a class and a struct in C++ was that a class contains private members whereas in a function everything is public. However, in C structs cannot contain any functions. However, it is possible to create a function and put a pointer function within the struct. Now you can have a semi-sort of member function for your struct.

October 1, 2011

We've moved onto creating a stack today. Well, I guess I should say yesterday at this point but… At first it was kind of weird. I thought it would be difficult to mold the idea into my Linked List Class but it really didn't take that much. Instead of creating several Node pointers, I just instantiated a linked list object called stack. To push to the stack, I would just call the insert function and insert to the first point in the list. When popping from the stack I would just get the value at the first point in the list and then delete that node. Right now, I'm trying to get a palindrome checker using the stack but it's being a little goofy.

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

Pointer

A pointer is a data type that contains the memory address where another value is stored in memory.

#include <stdio.h> 
 
int main()
{
	int regVar = 0;
	int *pointVar = &regVar;
 
	printf("regVar is stored at 0x%x. \n", &regVar);
	printf("pointVar points to 0x%x. \n", pointVar);
	printf("regVar = %d\n", regVar);
	printf("The value of pointVar = %d\n", *pointVar);
 
	return 0;
}
lab46:~$ ./pointer
regVar is stored at 0x22ff74.
pointVar points to 0x22ff74.
regVar = 0
The value of pointVar = 0
lab46:~$

Array

An array is a sequence of equally spaced address in memory. Arrays usually come in two flavors: one dimensional arrays and two dimensional arrays. One dimensional arrays are in a row format. Ex. array[0], array[1], array[3]… Two dimensional arrays use a row column format. Ex. array[0][0], array[0][1], array[0][2]…

Pointer Arithmetic

Pointer arithmetic is a means of manipulating a position in memory via addition or subtraction. Pointer arithmetic and array subscripting are two ways of doing the same thing. To do the same

#include <cstdlib>
#include <iostream>
 
using namespace std;
 
int main()
{
    int *intPointer, x;
    intPointer = (int*) malloc(sizeof(int)*5);
 
    for (x = 0; x < 5; x++) cout << intPointer++ << endl;
 
    return 0;
}
lab46:~$ ./pointerArithmetic
0x2145010
0x2145014
0x2145018
0x214501c
0x2145020
lab46:~$

Null Pointer

In C/C++, a null pointer is a special case. Null is a mnemonic which makes it a little clearer that there is no object associated with a pointer. Integers and memory addresses are interchangeable. Zero, null, is the exception because in C it is guaranteed that 0 will never be a valid memory location. Attempting to access a null pointer would be bad. If you're fuzzy on the whole good bad thing, I want you to imagine all life as you know it stopping instantaneously, and every molecule in your body exploding at the speed of light.

#include <stdio.h>
 
int main()
{
    char *cp = NULL;
    printf("%c\n", *cp);
 
    return 0;
}
lab46:~/src$ ./nullPoint
Segmentation fault (code dumped)
lab46:~/src$ 

Void Pointer

A void pointer can be looked at kind of like a shape shifter. It can store an address to any data type. In C, it will be converted to any other data type when assigned. However, it can't be dereferenced without a cast.

#include <stdio.h>
 
int main()
{
	int i = 0;
	char c = 'A';
 
	void* q = &i;
	printf("%d\n", *(int*)q);
 
	q = &c;
	printf("%c\n", *(char*)q);
 
	return 0;
}
lab46:~$ ./voidPoint
0
A
lab46:~$

Memory Allocation: Static Vs Dynamic

Static memory allocation is the process of the allocating memory at compile time. This happens when variables are declared locally within a function.

{
   int i, j;
 
   i = 1;
   j = i + 4;
}

With dynamic memory allocation, memory is created at run time. In C, malloc() is used to allocate memory and in C++ the keyword new is used. This memory will exist until the user deallocates it via free() in C, and delete in C++ or the garbage collector takes care of it. In C

{ 
	int *i = NULL;
 
	i = malloc(sizeof(int));
 
	free(i);
 
	return 0;
}

In C++

{
	int *i;
 
	i = new int;
 
	delete i;
 
	return 0;
}

Structures (structs)

A structure, or struct, is a compound data type consisting of multiple variables of, possibly, different data types. This makes for a nice way to group information that is related. This can be particularly useful when accessing records within a file. For instance, you may have a file which contains the first and last name and age of the employees at a company.

struct empInfo {
   char firstName[50];
   char lastName[50];
   int age;
};

If we want to access the members of a struct, we'd do as follows.

   struct empInfo joe;
   joe.firstName = "Joe";
   joe.lastName = "Smith";
   joe.age = 29;

Structure Pointer

A structure pointer is a much like any other pointer one would use. Using the structure example above, to create a pointer to that structure, one would do as follows:

   struct empInfo *empPoint;
   empPoint = malloc(sizeof(struct empInfo));

Accessing the members of a struct pointer is a little different than accessing the members of a struct declared statically. Lets say we want to store the age of an employee into our struct, we'd do the following:

   empPoint -> age = 20;

Linked List

A linked list is an unspecified number of structure pointers all chained together. Only the start and the end are specified. Every other part of the chain is linked by the “next” pointer in the previous part of the chain. In order to maneuver through the list, one needs to resume back to the beginning of the list and move forward.

struct Node {
   int value;
   struct Node *next;
};

The above struct is the core of a linked list. The variable value stores what integer data we have. The node pointer next points to the next item in the list. If there is only one item in the list or this node is the end of the list, next points to NULL. If we're somewhere in the middle of the list, next will point to whatever the next item in the list is.

int value, i;
 
if (pos > listLength || pos < 0) 
	pos = 0;
 
tmp = start;	
 
for (i = 0; i < pos; i++)
	tmp = tmp -> next;	
 
value = tmp -> intVal; 

This code first checks if the desired position in the list is out of bounds and sets the pos to 0. We then move to the beginning of the list and cycle through until we reach the desired position and retrieve the value

Doubly Linked List

A doubly linked list isn't much different that a singly linked list. The only major difference is that your struct will also contain a pointer to the previous item in the list. With this type of list you can move from either the beginning of the list to the end or from the end to the beginning.

struct Node {
  int value;
  struct Node* prev;
  struct Node* next;
};

The only difference between this struct and the one from above is the Node pointer prev. This means that there will be a few more loose ends to tie up. So, if we were to delete a node somewhere in the middle of the list.

tmp -> next -> prev = tmp -> prev;
tmp -> prev -> next = tmp -> next;
tmp -> prev = NULL;
tmp -> next = NULL;
free(tmp);

In the above code, first, we set the prev pointer in the next list element to point at the list element before tmp. So, if we have 3 nodes One, Two, and Three, and we're deleting node Two, we're Three's prev to point at Two. Now we set the next pointer of the previous element in the list to point at the node after tmp. So, One's next will point at Three. We then set all of the pointers within Two to NULL and deallocate the memory.

Function Pointers

A function pointer is a bit of a special case pointer. A function starts at a certain address in memory. We can dereference a pointer to invoke a function.

#include <stdio.h>
 
int add(int, int);
int sub(int, int);
 
struct Thing {
	int val1, val2;
	int (*addition)(int, int);
	int (*subtraction)(int, int);
};
 
int main()
{
	int x, y;
	struct Thing myThing;
 
	myThing.addition = &add;
	myThing.subtraction = &sub;
 
	printf("First int: ");
	scanf("%d", &x);
 
	printf("Second int: ");
	scanf("%d", &y);
 
	printf("Addition: %d\n", myThing.addition(x, y));
	printf("Subtraction: %d\n", myThing.subtraction(x, y));
 
	return 0;
}
 
int add(int a, int b)
{
	return a + b;
}
 
int sub(int a, int b)
{
	return a - b;
}

In C, it's not possible to declare a function inside of a struct. However, we can create function pointers to work around and have some functions within our struct to process the struct's data.

Version Control

Version control, in relation to our coursework, is the monitoring and manipulation of the changes within our source code. We can create changes and upload them to our repository, revert to an older change within the repository, and also we can view any changes that have been made.

lab46:~/src/cpu$ svn update
At revision 432.
lab46:~/src/cpu$
lab46:~/src/cpu$ 
------------------------------------------------------------------------
r3 | bh011695 | 2011-01-27 13:05:23 -0500 (Thu, 27 Jan 2011) | 1 line

added nandGate function
------------------------------------------------------------------------
r2 | jr018429 | 2011-01-27 09:56:47 -0500 (Thu, 27 Jan 2011) | 1 line

added boolean operators
------------------------------------------------------------------------
r1 | wedge | 2011-01-23 19:30:06 -0500 (Sun, 23 Jan 2011) | 1 line

Initial commit
------------------------------------------------------------------------

SYSPROG Topics

User Space

In Unix memory is segregated into two sections. First there is kernel space and secondly there is also user space. User space encompasses the area where the memory is used for user applications.

Kernel Space

The location in memory where the operating system is stored is referred to as system space or kernel space. The operating system is referred to as the kernel. The kernel has sole access to any kind of peripheral device such as a printer, mouse, or keyboard. If an application wants to access any of these devices, it requires permission from the kernel.

File Access (open, read, write, lseek, close)

open() read/write flags

The function open of type int which returns a file descriptor. If opening the file was unsuccessful a -1 will be returned, otherwise will return an integer. It takes, as parameters a filename and an int constant, the read/write flag, to tell the function what you plan on doing with the file: reading, writing, or reading and writing.

read()

read() is a system call which reads from a file descriptor. As parameters, it takes a file descriptor, a void pointer buf, and a count. read() will read count number of bytes starting from buf into the buffer from the file descriptor.

write()

write() is used to store data into a file. write() has the parameters: a file descriptor, buffer, and amount. write() will take amount bites from buffer and send them to the file descriptor. If successful, write() will return the number of bytes written. If it fails it will return a -1. It is possible for the number of bytes sent to be different from the number of bytes requested. The system could possibly put a limit on the size of a file. There is also the possibility of disk space. Perhaps there is no more space left on the hard drive.

lseek()

lseek() is used to find an offset within a file. It takes, as parameters, a file descriptor, the distance in bytes from the base, and the base which can be 0: start of file, 1: current position within the file, or 2: the end of the file.

close()

Whenever finished with a file descriptor, it needs to be closed. close() takes as a parameter a file descriptor and returns a 0 upon success and a -1 on error. An error, for example, if you were to try to open a file that does not exist a -1 will be returned by close().

#include <stdio.h>
#include <stdlib.h>
 
#define OFFSET 100
#define BASE 0
#define BUFF_SIZE 50
 
int main(int argc, char** argv)
{
   char *filePath, c[BUFF_SIZE];
   int fd1, fd2;
 
   filePath = (char*) malloc(sizeof(char) * 100);
 
   if (argc != 2) {
     printf("error: no filepath entered\n");
   } else {
     fd1 = open(argv[1], "r");
     fd2 = creat("myFile", 644);
     lseek(fd1, OFFSET, BASE);
     read(fd1, c, BUFF_SIZE);
     write(fd2, c, BUFF_SIZE);
     close(fd1);
     close(fd2);
   }
 
   return 0;
}

The data outputted to the file is a tad unintelligible. I thought I was doing everything right. It would appear that things aren't getting read into the buffer properly but I'm not sure why that would be.

File descriptors

A file descriptor is a means for which a process can talk to a file. When you open a file, a file descriptor will be created. A -1 signifies that there was an error. However, if there was no error an integer will be returned that will. This is the file descriptor. Any files opened will have a different file descriptor. This file descriptor will be used for operations performed on the file.

fd = open("myFile", "r");

This is how one would create a file descriptor.

Buffering

Buffering is the means of taking data and storing in memory in chunks of a predetermined size. An example of this would be prompting the user for some character data and storing the first 50 bytes into an array. Once the desired operations have been performed on the data another 50 bytes would be stored into the array. Repeat this until there is no more data to process. The kernel has its own buffers which it uses to save time. It keeps copies of disk blocks in memory because of how long it would take to keep writing back and forth between memory and the hard disk.

System Calls

A system call is a function that requests a service from the kernel. System calls can be divided into several groups: process control, file management, device management, information maintenance and communication. read() write() open() and close are all examples of a system call.

File Types and File Properties

When you do an ls -l a lot of information is displayed. However, on the far left you can find the file type designation. There are many different types of files such as directories, regular files, sockets, symbolic links, or named pipes. In one of the earlier examples we used creat() to create a file. When creat() is called a filetype is designated to to the file. It is simply just a regular file. However, different system calls can be used to create different types of files.

A file also has many different properties such as its owner, its permissions, its name, the last time it had been written to, its size, or its create data. Like the file type, all of these things can be displayed by doing a simple ls -l. Using chown(), it is possible to be able to change the owner of a file. As parameters, chown() takes the path to the file, the owner id, and the group id. It is also possible to change the permission bits of a file using chmod(). It's parameters are a file path and the new permissions.

bh011695@lab46:~/discrete$ ls -l
total 776
-rw-r--r-- 1 bh011695 lab46     96 Sep 17 13:05 Makefile
-rwxr-xr-x 1 bh011695 lab46 684685 Sep 23 23:35 a.out
-rwxr-xr-x 1 bh011695 lab46   7104 Sep  7 15:45 assignmentFive
-rw-r--r-- 1 bh011695 lab46    654 Sep  9 17:34 assignmentFive.c
-rwxr-xr-x 1 bh011695 lab46   7065 Sep 10 10:07 assignmentOne
-rw-r--r-- 1 bh011695 lab46    602 Sep  9 17:36 assignmentOne.c
-rwxr-xr-x 1 bh011695 lab46   8553 Sep  9 15:38 assignmentTwo
-rw-r--r-- 1 bh011695 lab46    776 Sep  9 17:33 assignmentTwo.c
-rwxr-xr-x 1 bh011695 lab46   8046 Sep 17 13:09 count
-rw-r--r-- 1 bh011695 lab46    344 Sep 17 13:09 count.c
-rw-r--r-- 1 bh011695 lab46   1872 Sep 17 13:09 count.o
-rw-r--r-- 1 bh011695 lab46   4154 Sep 23 23:34 libStringLib.a
drwxr-xr-x 2 bh011695 lab46   4096 Sep 29 10:21 stringLib
-rw-r--r-- 1 bh011695 lab46    874 Sep 17 12:30 stringLib.c
-rw-r--r-- 1 bh011695 lab46    228 Sep 17 12:30 stringLib.h
-rw-r--r-- 1 bh011695 lab46   2312 Sep 23 23:39 stringLib.o
-rwxr-xr-x 1 bh011695 lab46   7697 Sep 23 23:40 test
-rw-r--r-- 1 bh011695 lab46   3237 Sep 24 14:31 test.c
-rw-r--r-- 1 bh011695 lab46   1552 Sep 23 23:39 test.o
-rw-r--r-- 1 bh011695 lab46    120 Sep 23 23:30 test1.c

Bit Sets and Bit Masks

Bit masking involves checking to see if a certain bit is a one or a zero. To turn a bit on a logical or operation is used. To turn a bit off a logical and is used. It also possible to check the status of a single bit or to change multiple bit values.

#include <stdio.h>
 
int main()
{
  int num = 97;
  int mask = 128;
 
  printf("num = %d\n", num);
  //Turn on the left most bit
  printf("num = %d\n", num = num | mask);
  //turn off the left most bit
  mask = 127;
  printf("num = %d\n", num = num & mask);
 
  return 0;
 }
lab46:~$./mask
num = 97
num = 225
num = 97

User IDs, Group IDs

An unsigned integer value is designated to every user within the system. This UID ranges between 0 and 32767. 0 is always designated to root. A GID, or group ID, follows the same convention. Any user on the system can run the id command to obtain their user and group ID.

bh011695@lab46:~$ id
uid=5577(bh011695) gid=5000(lab46) groups=5000(lab46),1734(sys),1738(data),2999(bigworld),5577(bh011695)

Filesystem Structure; inodes and data blocks

An inode stores information about a file The only things the inode does not contain are the files data and the file's name. Every file on the system has an inode associated with it. All of the inodes on the system are contained inside of an inode table. Data blocks are where the file data is actually stored. When a file is to be stored, the kernel will locate however many blocks are needed to store the file. These data blocks may or may not be adjacent to each other. The kernel will then store the information within these data blocks.

Directories

In Unix, a directory is a special type of file. A directory contains all of the names of the files stored within it. To be able to view the files of a directory with their respective inode numbers is to do an ls -1ia.

bh011695@lab46:~$ ls systemsProg -1ia
573673308 .
 66461891 ..
573676539 .swp
573654795 Output.txt
573673286 cli
573673302 cli.c
573655652 filesandargs.c
573655709 fork.c
573655682 fork2.c
573654788 fprintf
573655613 fprintf.c
573655696 fscanf.c
573655614 getopt.c
573655620 mtest
573655617 mtest.c
573655706 output.txt
573655618 screentest.c
573655707 stringmanip.c

Looking at the output, there is a big list of numbers followed by file names. For instance inode 573655707 is associated with stringmanip.c. All of the meta data for stringmanip.c is stored within this inode.

Symbolic links or just links for short are very much like a shortcut in windows. A link is a file that points to another file. The reason for this is because multiple files can have the same inode number.

bh011695@lab46:~/ASM_6502$ ln helloWorld.asm newHi.asm
bh011695@lab46:~/ASM_6502$ ls -1ia
553450825 .
 66461891 ..
556055369 0x8.65s
556055370 0x9.65s
556055378 0xA.65s
553450824 ASM_EOCE.txt
556055371 helloWorld.asm
556055371 newHi.asm

If we look at the output of ls after doing the ln, we see that helloWorld.asm and newHi.asm both share the same inode number.

DATA Objectives

Objective 1

Choose the appropriate data structure for solving a given problem. Apply the data structure that would be best suited for solving some problem.

Method

I've used our stack implementation from earlier to be able to solve the palindrome problem.

#include "LinkedList.h"
#include <cstdio>
#include <cstdlib>
 
void push(char, LinkedList&);
char pop(LinkedList&);
 
int main()
{
	LinkedList stack;
	char *string, *start, c;
	int unequal = 0;
 
	string = (char*) malloc(sizeof(char)*50);
	start = string;
 
	printf("Enter a string: ");
	scanf("%s", string);
 
	printf("Your string is %s.\n", string);
 
	while (*string != '\0') 
		push(*string++, stack);
 
	string = start;
 
	while (stack.length() > 0 ) {
		if (pop(stack) != *string++)
			unequal = -1;
		stack.del(0);
	}
 
	string = start;
 
	if (unequal == 0)
		printf("%s is a palindrome.\n", string);
	else	
		printf("%s is not a palindrome.\n", string);
 
	return 0;
}
 
void push(char value, LinkedList &s)
{
	s.insert(value, 0);
}
 
char pop(LinkedList &s)
{
	return s.getCharVal(0);
}

Measurement

lab46:~$ ./palindrome
Enter a string: noon
Your string is noon.
Noon is a palindrome

./palindrome
Enter a string: lair
Your string is lair.
lair is not a palindrome.

Analysis

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

  • How did you do? - It works pretty well. There's no need to worry about reversing the word yourself since it comes off the stack in reverse order.
  • Room for improvement? - It was a pretty simple example, so there's probably not much you can do to enhance it.
  • Could the measurement process be enhanced to be more effective? - Again, since it was a fairly simple example there's not much more to measure. The only two things to be concerned with are if it is a palindrome or if it isn't.
  • 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? - You could possibly assign a certain problem to a certain data structure.

SYSPROG Objectives

Objective 1

Better understand file I/O for efficient data processing. Be able to read and write using C functions.

Method

I've created a bit of a file copying program. It opens an input file, reads the character data into it, and then copies it into a new file.

#include <stdio.h>
#include <stdlib.h>
 
int main(int argc, char** argv)
{
	char *filePath;
	int inChar;
	FILE *inFile, *outFile;
 
	filePath = (char*) malloc(sizeof(char) * 100);
 
	if (argc != 2) {
		printf("Path to file: ");
		scanf("%s", filePath);
		inFile = fopen(filePath, "r");
		outFile = fopen("fileCopy.txt", "w");
	} else {
		inFile = fopen(argv[1], "r");
		outFile = fopen("fileCopy.txt", "w");
	}
 
	while ((inChar = fgetc(inFile)) != EOF)
		fputc(inChar, outFile);
 
	fclose(inFile);
	fclose(outFile);
 
	return 0;
}

Measurement

It does what it's supposed to. It reads input from a file and then outputs it into a new file.

Analysis

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

  • How did you do? - Not bad.
  • Room for improvement? - Yeah, there are multiple ways to do what I did there. I could have employed those as well.
  • Could the measurement process be enhanced to be more effective? I think it would definitely benefit to use the other file IO functions.
  • Do you think this enhancement would be efficient to employ? It would certainly make one more versatile on the subject.
  • Could the course objective be altered to be more applicable? How would you alter it? You could specifically ask for to demonstrate file IO using a file descriptor and using a file pointer.

Experiments

* Vs &

Question

I had some issues with part of the project in discrete. I was having a little confusion as passing a pointer. I'm used to either passing a normal variable by value or passing by referencing using &. So, the question is, aren't sending a pointer and passing by reference the same thing?

Resources

Well, from what I know about pointers, when you pass one to a function you're passing a memory address. When you pass by reference, you pass the memory address of the variable that you're passing, a pointer. http://www.cplusplus.com/forum/beginner/7117/

Hypothesis

Passing a variable by reference and passing a pointer to a variable will achieve the same result.

Experiment

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

Data

#include <cstdio>
 
void first(int&);
void second(int*);
 
int main()
{	
	int i = 25;
	int *j = &i;
 
	first(i);
	second(j);
 
	return 0;
}
 
void first(int& i)
{
	printf("%d\n", i);
}
 
void second(int *i)
{
	printf("%d\n", *i);
}
lab46:~$ ./exp1
25
25

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? There is one thing that I didn't think about. A pointer can be set to NULL where a variable sent by reference cannot.

Conclusions

For the most part, sending a pointer to a function and passing a variable by reference isn't much difference. The only real difference between the two of these is the ability to set a pointer to NULL which doesn't exist when passing by reference.

String Vs String

Question

Something I've wondered in C++ there is a string type however, in C we create a pointer or an array of characters. Are these two things identical in size?

Resources

The two should be the same size. A C string should be one byte times the number of elements and the string type, unless there's added overhead, should be the same size. However, I want to say that I've tested this before and the two variables were of different sizes. Thought I can't quite remember.

Hypothesis

A C string and a C++ string type variable should be the same size in bytes if they are of the same length.

Experiment

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

Data

int main()
{ 	
	char *s1 = "cats";
	string s2 = "cats";
 
	printf("s1 is %d bytes\n", sizeof(s1));
	printf("s2 is %d bytes\n", sizeof(s2));
 
	return 0;
}
lab46:~$ ./size
s1 is 4 bytes
s2 is 4 bytes

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? (shortcomings in hypothesis) There is something I noticed. This brings up a new question. A null terminator, though unseen, is tacked onto the end of the C string. That seems like it should have made the string 5 bytes but it was only 4. Why would this be?

Conclusions

It does turn out that both the C String and the string type are the same size if they are of the same length. However, I'm NOT sure as to why they're only four bytes. “cats\0” should be 5 bytes I would think.

How Deep is the Well?

Question

The SysProg book had an experiment. Create a shell script that seems to recursively create directories. Even a second after there should be lots and lots of directories. Kind of like sticking a mirror in front of another mirror and looking at it. The question is, how do you delete them?

Resources

The book says that it shouldn't take long to create a directory tree that will go beyond the abilities of most commands that work on directory trees.

Hypothesis

There won't be a simple command that deletes this tree. Rm will not delete a directory if it contains any other files. Rmdir works very much the same and lacks a recursive option. Neither of these should work.

Experiment

The experiment will be to use a shell script to create a gigantic directory tree. After the tree has been created, check the number of sub-directories with ls. Confirm this by cd-ing through the tree. Lastly, try to delete the tree with a fairly simple command.

Data

Create a huge file tree

#!/bin/bash
while true
  do
    mkdir deep-well
    cd deep-well
   done

Doing an ls -lh gives us the following output on our new directory tree

drwxr-xr-x 3 ubuntu ubuntu 2.0k 2011-10-01 12:57 deep-well

I strolled through the tree and found the directory count, 3, in the ls was quite wrong. So, if that doesn't work, will it be possible to delete the tree using standard rm and rmdir. Both of these result in failure.

ubuntu:~$ rm deep-well/
rm:cannot remove `deep-well/': Is a directory
ubuntu:~$ rmdir deep-well
ubuntu:~$ rmdir: failed to remove `deep-well': Directory not empty

Now what happens when we add the force and recursive options to rmdir?

ubuntu@ubuntu:~/scripts$ ls
2Fake.sh    deepWell.sh    guessing_game.sh  random_num_generator.sh
anagram.sh  dialog.sh      jumble2.sh        test_jumble.sh
array.sh    dice_game.sh   jumble.sh         yrProd.sh
auto_draw   fake_work.sh   mousescroll.sh
deep-well   ghostarray.sh  palindrome.sh
ubuntu@ubuntu:~/scripts$ cd deep-well/deep-well/deep-well/deep-well/deep-well/deep-well/deep-well/deep-well/deep-well/deep-well/deep-well/deep-well/
ubuntu@ubuntu:~/scripts/deep-well/deep-well/deep-well/deep-well/deep-well/deep-well/deep-well/deep-well/deep-well/deep-well/deep-well/deep-well$ pwd
/home/ubuntu/scripts/deep-well/deep-well/deep-well/deep-well/deep-well/deep-well/deep-well/deep-well/deep-well/deep-well/deep-well/deep-well
ubuntu@ubuntu:~/scripts/deep-well/deep-well/deep-well/deep-well/deep-well/deep-well/deep-well/deep-well/deep-well/deep-well/deep-well/deep-well$ cd ~/scripts
ubuntu@ubuntu:~/scripts$ rm -rf deep-well/
ubuntu@ubuntu:~/scripts$ ls
2Fake.sh    deepWell.sh   ghostarray.sh     mousescroll.sh           yrProd.sh
anagram.sh  dialog.sh     guessing_game.sh  palindrome.sh
array.sh    dice_game.sh  jumble2.sh        random_num_generator.sh
auto_draw   fake_work.sh  jumble.sh         test_jumble.sh
ubuntu@ubuntu:~/scripts$ 

Analysis

Based on the data collected:

  • was your hypothesis correct? - No
  • was your hypothesis not applicable? - Yes
  • is there more going on than you originally thought? (shortcomings in hypothesis) I don't think so.
  • what shortcomings might there be in your experiment? - I may need to run the shell script for, at least, a few seconds.
  • what shortcomings might there be in your data? - I should, although I'm not sure how possible to dive to the bottom of the tree.

Conclusions

It is possible to delete a fairly large directory tree with a simple command line. However, it would be worth retesting while keeping track of how long the shell script runs for, 5 seconds, 10 seconds, etc. It is possible that it's simply not running long enough. There may be a point where commands will no longer be able to do any kind of operations on the tree.

opus/fall2011/bh011695/part1.txt · Last modified: 2011/10/03 12:03 by wedge