Mikhail Potapenko's Fall 2013 Opus
Is This Thing On?
My name is Mikhail. I like science, music, and sports.
Include statements are preprocessor directives that essentially place the contents of a file into the specified place. By convention, the files have the “.h” suffix and usually contain function declarations. The file stdio.h is necessary in order to use functions such as printf(), scanf() and other input/output functions that come with C.
int main(int a, argc char **argv) is the function that is called upon execution of a bin file and is the start of the program flow.
The Mercurial Repository is a way of keeping files backed up and accesible from different places. GCC(GNU Compiler Collection) is a compiler for C. The -Wall option shows all compilation warnings. The -o option allows the user to specify the name of the bin file. Bash is a shell used to communicate with the operating system(I think?) and do terminally things. Ya I don't really understand what Bash is.
#include <stdio.h>\\ int main(int a, char**b){\\ printf("Hello, World\n");\\ printf(b[1]);\\ printf("\n");\\ return a;\\ }
This program prints “Hello world” and “e” on seperate lines.
The above are the names of the C integer dataypes. They vary in the size of the number that they can store. On my computer and for most operating systems the sizes listed correspond to how much information they can store. Each type also comes in the signed and unsigned variety.
Wrote a program to ascertain the upper bounds, lower bounds and sizeof each data type on the system the program is run on.
signed char sc=0; unsigned char uc=0; printf("an unsigned char is %lu bytes\n", sizeof(uc)); printf("lower bound is %hhu\n",uc); printf("upper bound is %hhu\n",(uc-1)); printf("signed char is %ld bytes\n", sizeof(sc)); printf("lower bound is %hhd\n", ((unsigned char)(uc-1)/2)+1); // printf("upper bound is %hhd\n\n", ((unsigned char)(uc-1)/2)); printf("upper bound is %hhd\n\n", 0xFFFF&0x7F);
The commented out line is a pretty straightforward way of getting the upper bound of a signed data type (dividing the upper range by two and adding one. The line below that utilizes a bitwise AND. 0xFFFF is a 16 bit number with all bits set to 1. When “anded” with 0x7F, the same result is obtained.
A pointer is a variable whose value is a memory address. Pointers are used to handle arrays. In C, a string is actually just an array of chars and pointers are generally “pointed” at the start of the string. To declare a pointer a star is placed before the name of the pointer (ex. char *pointer). The * operator dereferences a pointer and returns the value stored at the address contained in the pointer. & is the inverse operator and returns the address of a variable. A pointer can point to another pointer which is how two (and more) dimensional arrays are handled.
In order to use memory, you first have to tell the computer how much memory you want to use and where that memory is. This is called allocation and can be done using the malloc() function. malloc() allocates a specified number of bytes and returns a pointer to a memory block at the start (whatever that means) of that region of memory.
Scanf is an input function that takes input from STDIN and stores that input in memory pointed to by the second argument. The first argument of scanf specifies the format in which the data is stored.
The main() function has two arguments, int argc and char **argv. argc is the number of tokens in the command line while arv is the string of characters in the command line when the bin file is run. argc and argv are just conventional names and the variables may be named with any valid variable name.
Wrote a program that makes use of scanf()
char *name, fi; //declaring a pointer name=NULL; fi=0; unsigned char age=0; printf("Please enter your name:"); //asking for input name=(char*)malloc(sizeof(char)*20); //allocating memory scanf("%s", name); //getting input printf("%s, what is your age?", name); scanf("%hhu", &age); fi=*(name+0); printf("%s, your intitial is %c (%hhu) and you are %hhu years old\n", name, fi, age); //output data back to user return(0);
Wrote program that demonstrates various formatting tricks.
int x,y; if(argc>7) { printf("%d...argument count\n", argc); printf("%8d...argument count\n", argc); printf("%8.8d...argument count\n", argc); printf("%-8.4d...argument count\n", argc); printf("%X(16)...argument count\n", argc); } else { printf("must have more than 7 arguments\n"); }
Wrote program that outputs number and value of arguments entered in command line during the program call.
int i; printf("There are %d arguments.\n They are:\n", argc); for(i=0; i<argc; i++) { printf("\targv[%d]: %s\n", i, argv[i]); } return(0);
This week we were introduced to the GD library. The GD library allows the programmer to write code which creates .png image files among other things. It includes functions that draws points, polygons, lines, font handling functions and more. Images are created using GdImageCreate(int wide, int high) which returns a gdImagePtr which points to that image. Most other GD functions take the gdImagePtr as an argument so the program knows which image to modify.
I have been using the word array a lot but this week Matt taught us what it actually means. Arrays are homogeneous composite variable modifier types. This means they can hold more than one variable but all variables must be of the same data type. Arrays allow us to use a pointer and an offset to access any particular element of the array. The offset does not necessarily refer to one byte but one block of memory that contains a single instance of that particular datatype. For instance an int is bytes so (intarray+1) is actually 4 bytes over from (intarray+0).
The GD library was used to create a snowman, a house, a CCC logo, and a checkerboard pattern.
#include <stdio.h> #include <gd.h> #include "polygons.h" #include <stdlib.h> #define BLUE 0 #define RED 1 #define GREEN 2 #define BLACK 3 int main() { FILE *out=NULL; char *outfile; gdImagePtr img; unsigned short int wide=800, high=800, x, y; //size of image unsigned int colors[3]; int i=1; img=gdImageCreate(wide, high); //create image colors[BLUE]=gdImageColorAllocate(img, 0, 0, 255); //allocate colors colors[RED]=gdImageColorAllocate(img, 255, 0, 0); colors[GREEN]=gdImageColorAllocate(img, 0, 255, 0); colors[BLACK]=gdImageColorAllocate(img, 0, 0, 0); for(y=0;y<8;y++) //loop through image and place recangles { for(x=0;x<8;x++) { gdImageFilledRectangle(img, x*100, y*100, (x+1)*100, (y+1)*100, colors[RED]); if(((x+y)/2)*2==(x+y)) gdImageFilledRectangle(img, x*100, y*100, (x+1)*100, (y+1)*100, colors[BLUE]); if(i==17) gdImageFilledRectangle(img, x*100, y*100, (x+1)*100, (y+1)*100, colors[GREEN]); gdImageRectangle(img, x*100, y*100, (x+1)*100, (y+1)*100, colors[BLACK]); i++; } } outfile=imgPath(); //save image to file out=fopen(outfile,"wb"); gdImagePngEx(img, out, -1); fclose(out); gdImageDestroy(img); return(0); }
#include <stdio.h> #include <gd.h> #include "polygons.h" #define BLACK 0 #define TAN 1 #define GREEN 2 #define BLUE 3 #define WHITE 4 #define DRED 5 #define RED 6 int main() { FILE *out; char *outfile; gdImagePtr img; unsigned int color[6]; unsigned short int wide=1024, high=768, x; gdPoint points[3]; img=gdImageCreate(wide, high); color[BLACK]=gdImageColorAllocate(img, 0, 0, 0); color[TAN]=gdImageColorAllocate(img, 189, 183, 107); color[GREEN]=gdImageColorAllocate(img, 0, 255, 0); color[BLUE]=gdImageColorAllocate(img, 135, 206, 250); color[WHITE]=gdImageColorAllocate(img, 254, 254, 253); color[DRED]=gdImageColorAllocate(img, 165, 42, 42); color[RED]=gdImageColorAllocate(img, 255, 0, 0); points[0].x = 10; //populate array of "points" structs points[0].y = high/3; points[1].x = 790/2; points[1].y = 0; points[2].x = 800; points[2].y = high/3; gdImageFilledRectangle(img, 0, 0, wide-1, high-1, color[WHITE]); gdImageFilledRectangle(img, 10, 758, 800, high/3, color[TAN]); //house rectangle gdImageFilledRectangle(img, (790/2)-100, 758, (790/2)+100, high*2/3, color[DRED]); //door gdImageFilledPolygon(img, points, 3, color[DRED]);//roof gdImageFilledEllipse(img, 875, 768-50, 100, 100, color[BLUE]); gdImageFilledEllipse(img, 875, 768-125, 50, 50, color[BLUE]); gdImageFilledEllipse(img, 875, 768-162, 25, 25, color[BLUE]); gdImageFilledArc(img, (1024*2)/3, 50, 90, 100, 90, 270, color[RED], gdArc); gdImageFilledArc(img, ((1024*2)/3)+45, 50, 90, 100, 90, 270, color[RED], gdArc); gdImageFilledArc(img, ((1024*2)/3)+90, 50, 90, 100, 90, 270, color[RED], gdArc); outfile=imgPath(); out=fopen(outfile,"wb"); gdImagePngEx(img, out, -1); fclose(out); gdImageDestroy(img); return(0); }
Used Points struct from Gd library to make a polygon.
Functions in programming are like functions in math. They take inputs, manipulate them, and return output. Functions are useful for packaging code and making it look clean and organized. Functions can take and return values or pointers. passing an argument by value creates a copy of that variable and the copy is manipulated whereas passing an argument using a pointer(or by reference) results in manipulation of the data the pointer references to rather than a copy of the data. Like anything, this can be useful or detrimental.
I wrote a program in GD that creates a house with windows and a clock which shows the time of execution. I also wrote a function that creates an n-sided polygon using the GD library which I made use of in drawing.
void createPol(gdImagePtr image, int x, int y, double rx, double ry, int n, double f, unsigned int col) { gdPoint pol[n]; //create the gdPoint struct to be used unsigned int i; double m=2*M_PI/n; //angle increment for(i=0; i<n; i++) { pol[i].x=x+(int)rint(rx*sin(f+i*m)); //populating the struct with points pol[i].y=y+(int)rint(ry*cos(f+i*m)); } gdImageFilledPolygon(image, pol, n, col); //creating the polygon }
x and y are the center of the polygon. rx and ry are eccentricity factors in the x and y direction. n is the number of sides. f is a phase constant that determines orientation of the polygon. The last argument is the color of the polygon.
void createHands(gdImagePtr image, gdPoint p, int length, double angle, double wangle, unsigned int col) { gdPoint hand[6]; //the shape of the hand is relative to the wangle parameter double r1, r2; //distance to outermost points of hand, length of beginning segments of clock ha$ double a1=wangle/2.; r1=length/6.; r2=3*r1/(3.*cos(a1)); hand[0]=p; //populate structs with points of hand hand[1].x=p.x+rint(r1*sin(a1+angle)); hand[1].y=p.y-rint(r1*cos(a1+angle)); hand[2].x=p.x+rint(r2*sin(wangle+angle)); hand[2].y=p.y-rint(r2*cos(wangle+angle)); hand[3].x=p.x+rint(length*sin(angle)); hand[3].y=p.y-rint(length*cos(angle)); hand[4].x=p.x+rint(r2*sin(-wangle+angle)); hand[4].y=p.y-rint(r2*cos(-wangle+angle)); hand[5].x=p.x+rint(r1*sin(-a1+angle)); hand[5].y=p.y-rint(r1*cos(-a1+angle)); gdImageFilledPolygon(image, hand, 6, col); }
hand[0] refers to the middle of the clock. If the hand is pointing to 12 o'clock then hand[1] is counterclockwise from hand[0]. See picture below for more clear understanding. Angle is the angle of the bisecting line of the clock. wangle is the angle between the two initial line segments.
#include <gd.h> #include <stdio.h> #include <math.h> #include <stdlib.h> #include <time.h> #include "polygons.h" #include <gdfontt.h> #include <string.h> #include <gdfontl.h> #include <gdfontg.h> #define WHITE 0 #define BLACK 1 #define TAN 2 #define GREEN 3 #define LIGHTRED 4 #define BLUE 5 #define BRIGHTRED 6 #define BROWN 7 int main() { FILE *out; unsigned int color[6]; char *outfile; unsigned char num[12][3]; struct tm *info=NULL; time_t rawtime; int a,b,c; gdImagePtr img; gdPoint roof[3]; gdPoint house[4]; unsigned int wide=1024, high=1000; unsigned int rwide=((2*wide)/3); //width of roof unsigned int hwide=rwide*7/8; //width of house unsigned int hleft=rwide/16; //left wall of house unsigned int hright=hleft+hwide; //right wall of house unsigned int hhigh=(7*high)/10; //heighth of house unsigned int hup=high-hhigh; //ceiling of house unsigned int col=3; //number of window columns unsigned int ro=3; //number of window rows unsigned int windx=0; unsigned int windy=0; unsigned short int ic=0; unsigned short int ir=0; double angle=0; double handlen=(wide-hright)/2.5; unsigned int clockx=0; unsigned int clocky=0; double radx; double rady; unsigned int windoffx=0; unsigned int windoffy=0; int sleft=0; int sup=0; int minute=0; int hour=0; int sec=0; double hangle, mangle, sangle; img=gdImageCreate(wide, high); color[WHITE]=gdImageColorAllocate(img, 255, 255, 255); color[BLACK]=gdImageColorAllocate(img, 0,0,0); color[TAN]=gdImageColorAllocate(img, 143, 188, 143); color[GREEN]=gdImageColorAllocate(img, 84,139,84); color[LIGHTRED]=gdImageColorAllocate(img, 200, 0, 0); color[BLUE]=gdImageColorAllocate(img, 65, 105, 255); color[BRIGHTRED]=gdImageColorAllocate(img, 170, 17, 17); color[BROWN]=gdImageColorAllocate(img, 153, 0, 0); roof[0].x=rwide/2; roof[0].y=high/6; roof[1].x=0; roof[1].y=hup; roof[2].x=rwide; roof[2].y=hup; gdImageFilledPolygon(img, roof, 3, color[BRIGHTRED]); house[0].x=hleft; house[0].y=high; house[1].x=hleft; house[1].y=hup; house[2].x=hright; house[2].y=hup; house[3].x=hright; house[3].y=high; gdImageFilledPolygon(img, house, 4, color[TAN]); windoffx=hwide/6; windoffy=hhigh/(ro+1); for(ic=0; ic<col; ic++) //make windows using polygon functions { windx=(ic*(hwide-2*windoffx))/(col-1)+windoffx+hleft; for(ir=0; ir<ro; ir++) { if(ir==2&&ic==1) { createPol(img, hleft+(hwide/2), hup+5*hhigh/6, hwide/5, 2*hup/3, 4, M_PI/4, color[BRIGHTRED]); } else { windy=windoffy+ir*(hhigh-2*windoffy)/(ro-1)+hup; createPol(img, windx, windy, hwide/8, hup/6, 6, M_PI/6, color[BLUE]); } } } clockx=wide-(wide-hright)/2; //set middle of clock clocky=(wide-hright)/2; gdImageFilledEllipse(img, clockx, clocky, wide-hright, wide-hright, color[BLACK]); //body of clock radx=(wide-hright)/24; rady=radx; for(a=0; a<12; a++) //create string of numbers 1 to 12 { b=0; if(a<9) c=a+49; else c='1'; num[a][b]=c; b++; if(a<9) c='\0'; else c=a+39; num[a][b]=c; b++; c='\0'; num[a][b]=c; printf("%s\n", num[a]); } a=0; while(angle<2*M_PI) //put clock face on { printf("%d %f", a, angle); sleft=clockx+(int)rint(handlen*sin(angle+M_PI/6.))-(strlen((const char *)num[a])*gdFontGetGiant()->w / 2); sup=clocky-(int)rint(handlen*cos(angle+M_PI/6.))-gdFontGetGiant()->h / 2; createPol( img, (int)rint(clockx+handlen*sin(angle+M_PI/6.)), (int)rint(clocky-handlen*cos(angle+M_PI/6.)), radx, rady, 8, M_PI/8, color[WHITE] ); gdImageString(img, gdFontGetGiant(), sleft, sup, *(num+a), color[BLACK]); angle+=M_PI/6; a++; } time(&rawtime); //get time struct info=localtime(&rawtime); hour=info->tm_hour; minute=info->tm_min; sec=info->tm_sec; sangle=sec*M_PI/30.; //calculate angles of hands mangle=M_PI*(minute+sec/60.)/30.; hangle=M_PI*(hour+(minute+sec/60.)/60.)/6.; gdPoint p={clockx, clocky}; createHands(img, p, 2*handlen/3, hangle, M_PI/6., color[BRIGHTRED]); //place the hands createHands(img, p, handlen, mangle, M_PI/9., color[BRIGHTRED]); createHands(img, p, handlen, sangle, M_PI/24, color[BLUE]); outfile=imgPath(); out=fopen(outfile,"wb"); gdImagePngEx(img, out, -1); fclose(out); gdImageDestroy(img); return(0); }
We took a test knowledge assessment this week. In preparation for the knowledge asessment we became completely sidetracked and learned about header files and typedefs! Typedefs are preprocessor commands which can give an alternate name to data types.
A struct is a heterogeneous composite type. It can contain variables of different types. gdPoint from the GD library is an example of a struct with a member named x and a member named y. A struct can be defined, declared, and initialized in the following way.
struct awesomestruct //defining a struct { int something; char somethingelse; }; awesomestruct instanceofstruct; //declare instance of the struct instanceofstruct.something=48; //initialize member of struct
A “.” is used to access a variable member of a struct and a “→” is used to access a pointer member of a struct.
C++ is a language closely related to C. Almost everything that compiles with a C compiler will compile with a C++ compiler. However C++ is an object oriented language. This means it uses objects very similar to structs to organize code. These objects are called classes. Classes are essentially structs that can have functions as members rather than just pointers to functions. Classes are not the best solution to every problem but can be very useful in some situations such as when an abstract link can be made between various “objects” in a piece of code. If god had created people using object oriented principles instead of procedural ones things could have been a lot simpler for all of us.
A class is defined, declared, and used in the same way as a struct is. Another important difference however is the private, public and protected distinction between members of the class. Members that are declared as private can only be accessed from within the class. Protected members can only be accessed from within the class and by classes inheriting from that class. Public members can be accessed by anyone. This allows for the important inner machinery of the class to be kept away from meddling users of the class.
Code is often organized between three different file types. A “.h” file contains the prototypes for all classes, structs and function. There is also a file that contains the source code for said functions, classes, and structs which can be compiled but not linked with any other files. The third file type is the file that contains the main function which calls and uses the classes and functions and structs and controls the program flow. the main file and source code file both must include the “.h”, or header, file. The main file is then compiled and linked to the already compiled source files.
It is good practice to put #ifndef statements in header files. The prevent the content of the header file from being defined more than once.
In class we wrote a program that returns the area of a square, rectangle, and triangle given the length of the sides.
#ifndef _SQUARE_H #define _SQUARE_H class rectangle { public: rectangle(); void setside(int, int); int getside(int index); int area(); int perimeter(); private: int sides[2]; }; class triangle { public: triangle(); void setside(int, int, int); int getside(int); float area(); int perimeter(); private: bool tricheck(); float sides[3]; float lside; float arsides[2]; }; class square { public: square(); void setside(int); int getside(); int area(); int perimeter(); private: int x; }; #endif
#include <cstdio> #include <cmath> #include "square.h" rectangle::rectangle() { } void rectangle::setside(int side1, int side2) { sides[0]=side1; sides[1]=side2; } int rectangle::getside(int index) { return(sides[index]); } int rectangle::area() { return(sides[0]*sides[1]); } int rectangle::perimeter() { return(2*sides[0]+2*sides[1]); } triangle::triangle() { } bool triangle::tricheck() //check if sides make up valid triangle { bool c1=false, c2=false, c3=false; if(sides[0]+sides[1]>sides[2]) c1=true; if(sides[1]+sides[2]>sides[0]) c2=true; if(sides[2]+sides[0]>sides[1]) c3=true; return(c1&&c2&&c3); } void triangle::setside(int side1, int side2, int side3) //set side members of the triangles based on user input { int i, j, k=0; bool t; sides[0]=(float)side1; sides[1]=(float)side2; sides[2]=(float)side3; t=tricheck(); if(t==true) { lside=0; for(i=0; i<3; i++) { if(sides[i]>=lside) lside=sides[i]; j=i; } for(i=0; i<3; i++) { if(i==j) continue; arsides[k]=sides[i]; k++; } } else { printf("that is not a valid triangle\n"); } } int triangle::getside(int index) { return(sides[index]); } float triangle::area() //calculate area using heron's formula { float theta; float h; float a; theta=acos((pow(arsides[0], 2)-pow(arsides[1], 2)-pow(lside, 2))/(-2*lside*arsides[1])); h=arsides[1]*sin(theta); a=0.5*h*lside; return(a); } int triangle::perimeter() { return((int)(sides[0]+sides[1]+sides[2])); } square::square() { x=0; } void square::setside(int side) { x=side; } int square::getside() { return(x); } int square::area() { return(x*x); } int square::perimeter() { return(4*x); }
#include "square.h" #include <cstdio> int main() { square s1; //instantiate classes square s2; rectangle r1; rectangle r2; triangle t1; triangle t2; s1.setside(4); //set sides of squares s2.setside(12); printf("s1's side is %d\n", s1.getside()); //print sides of square printf("s1's area is %d\n", s1.area()); //calculate area printf("s1's perimeter is %d\n", s1.perimeter()); //calculate perimeter printf("s2's side is %d\n", s2.getside()); printf("s2's area is %d\n", s2.area()); printf("s2's perimeter is %d\n", s2.perimeter()); r1.setside(2, 4); r2.setside(5, 10); printf("r1's sides are %d, %d\n", r1.getside(0), r1.getside(1)); printf("r1's area is %d\n", r1.area()); printf("r1's perimeter is %d\n", r1.perimeter()); printf("r2's sides are %d, %d\n", r2.getside(0), r2.getside(1)); printf("r2's area is %d\n", r2.area()); printf("r2's perimeter is %d\n", r2.perimeter()); t1.setside(4, 3, 5); t2.setside(1, 1, 2); printf("t1's sides are %d, %d, %d\n", t1.getside(0), t1.getside(1), t1.getside(2)); printf("t1's area is %f\n", t1.area()); printf("t1's perimeter is %d\n", t1.perimeter()); printf("t2's sides are %d, %d, %d\n", t2.getside(0), t2.getside(1), t2.getside(2)); printf("t2's area is %f\n", t2.area()); printf("t2's perimeter is %d\n", t2.perimeter()); return(0); }
We have started working on a BigNum class. It is a user created datatype that allows manipulation of numbers that are larger than long long ints.
Matt showed us how to use the gdb this week. Where has this been all my life? Including a -g in the compile statement and then running the program with the command gdb runs the debugger. The debugger allows stepping through a program line by line and printing the values of variables at any point in the code. gdb has a lot of commands but the one I use the most is creating breakpoints. This stops the program in the middle of execution at a specified line. This has been extremely helpful in my BigNum programming which I am still working on.
One way of populating the members of a class is by copying them from another class. This makes the new class a child class and the old one a parent class. In C++ copying the members of a parent class is supported with the inheritance functionality. Inheritance is a way of organizing code that includes objects which are partial cases of other objects.
Makefiles are a way to get around the hell that is typing in compilation statements into the commanline. Makefiles contain a script that do the typing for you so that all the user has to type is “make”.
Matt provided us with a “storage” class and challenged us to implement a “tape” class which inherits from storage. A tape is a form of a storage device so the whole inheritance thing fits very well here.
#ifndef _STORAGE_H #define _STORAGE_H // // storage.h - class declaration for the storage class, used for covering // "Inheritance". // using namespace std; class storage { public: storage(); // constructor int getCapacity(); int getFree(); int getUsed(); protected: int load(); void store(int); bool pos(int); private: int data[256]; int used; int available; int loc; }; #endif
#include "storage.h" storage :: storage() { int i; used = 0; available = 255; for (i = 0; i < 256; i++) data[i] = 0; loc = 0; } int storage :: getCapacity() { return used + available + 1; } int storage :: getFree() { return available + 1; } int storage :: getUsed() { return used; } #include <iostream> int storage :: load() { return data[loc]; } void storage :: store(int value) { if (used < 255) { data[loc] = value; used++; available--; } else cout << "Error! Out of space!" << endl; if (value == 0) { used--; available++; if(used > 255) used = 255; if(used < 0) used = 0; if(available > 255) available = 255; if(available < 0) available = 0; } } bool storage :: pos(int location) { bool retval = true; if ((location >= 0) && (location <= 255)) loc = location; else retval = false; return retval; }
#ifndef _TAPE_H #define _TAPE_H // // tape.h - derived class declaration for the tape class // #include "storage.h" #include <iostream> class tape : public storage //inherit from storage { public: tape(); int read(); void write(int); void forward(); void backward(); void rewind(); void setlabel(string); string getlabel(); int getpos(); private: string label; int position; }; #endif
#include "storage.h" #include "tape.h" #include <cstdio> tape::tape() //initialize label and position { position=0; pos(position); label="unlabeled"; } int tape::read() //read using a function inherited from storage { return(load()); } void tape::write(int num) //write { store(num); } void tape::forward() //move forward { bool errcheck; position++; errcheck=pos(position); if(errcheck==false) { printf("End of tape!\n"); position--; pos(position); } } void tape::backward() { bool errcheck; position--; errcheck=pos(position); if(errcheck==false) { printf("End of tape!\n"); position++; pos(position); } } void tape::rewind() { while(position!=0) { position--; } pos(position); } void tape::setlabel(string lstr) { label=lstr; } string tape::getlabel() { return(label); } int tape::getpos() { return(position); }
#include <cstdio> #include "tape.h" #include <iostream> using namespace std; int main() { tape t; char ans; string l; int val; int i; cout << "This is a tape, would you like to label it? (y/n)" << endl; cin >> ans; if(ans==121) { cout << "What would you like to label it (no spaces)?" << endl; cin >> l; t.setlabel(l); cout << "The tape is now labeled " << t.getlabel() << endl; } cout << "The current position is " << t.getpos() << " and it contains " << t.read() << endl; while(ans!=55) { cout << "0 - forward" << endl; //menu cout << "1 - backward" << endl; cout << "2 - rewind" << endl; cout << "3 - read" << endl; cout << "4 - write" << endl; cout << "5 - forward multiple positions" << endl; cout << "6 - backward multiple positions" << endl; cout << "7 - quit" << endl; cin >> ans; //wait for input switch(ans) { case 48: t.forward(); cout << "position is " << t.getpos() << endl; break; case 49: t.backward(); cout << "position is " << t.getpos() << endl; break; case 50: t.rewind(); cout << "position is " << t.getpos() << endl; break; case 51: cout << "value is " << t.read() << endl; break; case 52: cout << "please enter value" << endl; cin >> val; t.write(val); break; case 53: cout << "how many spaces?" << endl; cin >> val; for(i=0; i<val; i++) { t.forward(); } cout << "position is " << t.getpos() << endl; break; case 54: cout << "how many spaces?" << endl; cin >> val; for(i=0; i<val; i++) { t.backward(); } cout << "position is " << t.getpos() << endl; break; case 55: return(0); } } }
We're spending the rest of the semester working on our end of course experience. Also I Finished BigNum. Well I did what I could. It has functionality for multiplication, addition, subtraction(kind of), increment, decrement, setting the value of the bignum, and lessthan(). The class is also supposed to work in any base up to 36 but I don't think I've tested it enough to say it does for sure. There's a lot of code.
#ifndef _BIGNUM_H #define _BIGNUM_H class BigNum { public: BigNum(); BigNum(unsigned char); unsigned char getBase(); unsigned char getLength(); unsigned char getSign(); void setBase(unsigned char); void setLength(unsigned char); void setSign(unsigned char); void setVal(unsigned char *, unsigned char, unsigned char l); void setVal(unsigned char *, unsigned char l); void zero(); void print(); int increment(signed int); BigNum add(BigNum, BigNum); bool lessthan(BigNum *, BigNum *); BigNum mult(BigNum, BigNum); private: unsigned char base; unsigned char length; unsigned char sign; unsigned char *data; void allocate(int); int lenadjust(BigNum, BigNum); }; #endif
#include "bignum.h" #include <cstdio> #include <climits> #include <cstring> #include <cstdlib> BigNum::BigNum() //constructor { BigNum(8); //calls other cobnstructor to set the length } BigNum::BigNum(unsigned char length) //other constructer { this->length=length; base=10; sign=0; data=new unsigned char(this->length); this->zero(); } unsigned char BigNum::getBase() { return(base); } void BigNum::setBase(unsigned char base) { this->base=base; } unsigned char BigNum::getLength() { return(length); } void BigNum::setLength(unsigned char length) { this->length=length; } void BigNum::print() //prints bignum { for(int i=0; i<length; i++) { if(*(data+i)>9) //account for bases larger than 10 printf("%c", *(data+i)+87); else printf("%hhu", *(data+i)); } } unsigned char BigNum::getSign() { return(sign); } void BigNum::setSign(unsigned char sign) { this->sign=sign; } void BigNum::zero() //set bignum to zero { for(int i=0; i<length; i++) { *(data+i)=0; } } int BigNum::increment(signed int n) { int i=1; if(n!=1&&n!=(-1)) //so that increment can also decrement return(1); *(data+(length-1))=*(data+(length-1))+n; //increment/decerement while(*(data+(length-i))!=0) //change digits based on carries { if(*(data+(length-i))==base) { *(data+(length-i))=0; *(data+(length-i-1))=*(data+(length-i-1))+n; i++; } else if(*(data+(length-i))==UCHAR_MAX) { *(data+(length-i))=base+n; *(data+(length-i-1))=*(data+(length-i-1))+n; i++; } else { break; } } return(0); } bool BigNum::lessthan(BigNum *bn1, BigNum *bn2) { int i; for(i=0; i<bn1->getLength(); i++) //compare every digit from left to right { if (*(bn1->data+i)==*(bn2->data+i)) continue; else return(*(bn1->data+i)<*(bn2->data+i)); } return(false); } BigNum BigNum::add(BigNum n1, BigNum n2) { unsigned char carry=0; int i; unsigned char nlen=n1.getLength(); char sfac1=1; char sfac2=1; bool n1n2; bool n2n1; if(n1.sign==45) //for subtraction functionality, not fully implemented sfac1=-1; if(n2.sign==45) sfac2=-1; if(n1.length!=n2.length) lenadjust(n1, n2); BigNum r(nlen); r.setBase(n1.base); if(n1.sign==n2.sign) //if signs are same then just add digits together normally { for(i=n1.length-1; i>-1; i--) { *(r.data+i)=(*(n1.data+i))+(*(n2.data+i))+carry; //add normally if(*(r.data+i)>=r.base) { *(r.data+i)=*(r.data+i)-r.base; carry=1; } else { carry=0; } } r.setSign(n1.sign); } else //if they are opposite then account for case when absolute value of one is larger than the other { if(n1.sign==45) sfac1=-1; if(n2.sign==45) sfac2=-1; for(i=n1.length-1; i>-1; i--) { *(r.data+i)=(*(n1.data+i))*sfac1+(*(n2.data+i))*sfac2; //add with sign factors if(*(r.data+i)>=UCHAR_MAX-r.base) { *(r.data+i)=UCHAR_MAX-(*(r.data+i))+1; *(r.data+i-1)=(*(r.data+i-1))-1; } } n1n2=lessthan(&n1, &n2); n2n1=lessthan(&n2, &n1); if((n1n2 && n1.sign==0)||(n2n1 && n1.sign==45)) r.setSign(45); else r.setSign(0); } return(r); } void BigNum::setVal(unsigned char *indata, unsigned char baseval, unsigned char l) { int i; this->setLength(l); if(l!=this->getLength()) this->allocate(l); this->setBase(baseval); memcpy((void *)this->data, (const void *)indata, l*sizeof(unsigned char)); //copy array to BigNum array for(i=0; i<l; i++) { if(*(data+i)>=48&&*(data+i)<=57) //account for various bases *(data+i)=*(data+i)-48; if(*(data+i)>=97&&*(data+i)<=122) *(data+i)=*(data+i)-87; } } void BigNum::setVal(unsigned char *indata, unsigned char l) { setVal(indata, this->base, l); } void BigNum::allocate(int len) { delete this->data; this->data=new unsigned char(len); this->zero(); } BigNum BigNum::mult(BigNum num1, BigNum num2) { BigNum numr(num1.length*num2.length); BigNum numa(num1.length*num2.length); numr.base=numa.base=num1.base; int i, j; int carry=0; unsigned char **addends; //double pointer for addends int a, b; int addlen=num1.length+num2.length; if(num1.length!=num2.length) lenadjust(num1, num2); addends=(unsigned char **)malloc(sizeof(unsigned char *)*num1.length); for(i=0; i<num1.length; i++) { *(addends+i)=(unsigned char *)malloc(sizeof(unsigned char)*(int)(addlen)); //allocate memory for addends } for(i=0; i<num2.length; i++) { b=*(num2.data+num2.length-1-i); //current digit of one BigNum for(j=0; j<num1.length+1; j++) { a=*(num1.data+num1.length-1-j); //current digit of other BigNum *(*(addends+i)+addlen-1-j-i)=(unsigned char)(((a*b)%(int)base)+carry); //multiply and use mod division to get most significant digit carry=(a*b)/(int)(base); } for(j=0; j<i; j++) { *(*(addends+i)+addlen-1-j)=0; //put zeros in placeholders } numa.setVal(*(addends+i), numa.base, (unsigned char)addlen); //add addends together numr=numr.add(numr, numa); } return(numr); } int BigNum::lenadjust(BigNum a, BigNum b) { unsigned char *temp; int i; if(a.length==b.length) return(1); if(a.length>b.length) { temp=new unsigned char(a.length); for(i=0; i<b.length; i++) { *(temp+a.length-i)=*(b.data+b.length-i); } delete b.data; b.data=new unsigned char(a.length); memcpy(temp, b.data, b.length); } else { temp=new unsigned char(b.length); for(i=0; i<a.length; i++) { *(temp+b.length-i)=*(a.data+a.length-i); } delete a.data; a.data=new unsigned char(b.length); memcpy(temp, a.data, a.length); } return(0); }