This shows you the differences between two versions of the page.
Both sides previous revisionPrevious revisionNext revision | Previous revision | ||
haas:summer2017:cprog:projects:sfa0 [2017/07/20 14:29] – [structures] wedge | haas:summer2017:cprog:projects:sfa0 [2017/07/26 15:59] (current) – [Methods of file access] wedge | ||
---|---|---|---|
Line 132: | Line 132: | ||
</ | </ | ||
- | The structure pointer just makes the code look cleaner, so it is the recommended way of accessing elements (when the structured variable has been declared as a pointer). | + | The structure pointer just makes the code look cleaner, so it is the recommended way of accessing elements (when the structured variable has been declared as a pointer, that is). |
- | =====What is a function?===== | + | ====Files==== |
- | In a way, functions are like evolved variables - they have a data (return) type, they are given a symbolic name, and they contain | + | While information is unique down to bits, and the computer accesses |
- | Functions are like sub-programs - small subroutines that perform some specific task that is relevant to the larger program (or other functions). | + | Like a structure, there is no stipulation on what sort of data goes in a generic file; although like an array, a file can be accessed as a sequence of bytes, from a starting index or offset. |
- | So, instead of storing some numeric value like variables do, functions contain a group of instructions | + | C and other production-oriented programming languages provide file I/O functionality, which can greatly increase the usability of the programs we write. |
- | That group of functions, which performs a task, is given a name. That will allow your function to be called from wherever it is needed, and can be used to prevent | + | From reading in external data sets to loading/ |
- | The data type assigned | + | ====Point of access: pointer or descriptor==== |
+ | C provides two streamlined ways of accessing a file, and various groups of C library functions | ||
- | ====Why should I use functions? | + | |
- | As I've said, the absolute minimal number of functions required in a C program is 1: **main()** | + | |
- | **main()** is a regular ordinary function with one notable difference-- it is the one function the system looks for to start executing your program. Aside from that, it is as real and normal | + | FILE pointers are just that: a pointer |
- | Why can't I just put everything in **main()**? | + | File descriptors are perhaps slightly more polished, abstracting away more of the low-level details of file access, instead creating an interface around a unique numeric value (somewhat like a "take a number" |
- | Nothing is preventing you from exclusively using **main()**. However, your program may become unnecessarily long and difficult to debug should there be problems. Functions allow you to modularize your code- so you can break it up into little pieces. Not only can this lead to increased efficiency from less duplicated code, but your code will be significantly more organized. | + | For the purposes of this project |
- | For this course, I will expect you to use functions | + | ====Methods of file access==== |
+ | To interact with a file, we must do so in accordance with a fixed set of actions (which are woven into the various C library file functions), some common ones of which are: | ||
- | ====Where do I put functions in my program? | + | * create |
- | There are two aspects to functions, which are concepts shared with that of variables: | + | * open |
+ | * read | ||
+ | * write | ||
+ | * append | ||
+ | * execute | ||
+ | * remove | ||
+ | * close | ||
- | * declaration / prototyping | + | We'll be specifically focusing on opening, reading, writing, and closing files for this project. |
- | * definition / initialization | + | |
- | In order to avoid compiler errors, and allow your code to work seamlessly with your functions, ANY functions must be **declared** prior to any other function that makes use of them. | + | A point of distinction on " |
- | Once the function is declared, the definition could then immediately | + | ====Declaring a FILE pointer==== |
+ | To access a file, we must first have an instance of the file access interface to interact with. As indicated above, this comes in the form of a FILE pointer, which for us will take the form of a variable: | ||
- | ====When do I use functions? | + | <code c> |
- | Programming is more of an art, so there is no clear-cut answer to this. However, here are a couple of guidelines you should keep in mind as good indications for needing a function: | + | FILE *fp |
+ | </ | ||
- | * you find yourself duplicating | + | There' |
- | | + | |
- | | + | |
- | Some thoughts | + | ====Opening a file==== |
+ | To gain access | ||
+ | - PATH and name of the file (location) | ||
+ | - means of access (mode) | ||
- | * a function typically performs a single task (such as taking input from the keyboard, OR processing something, OR displaying output). Don't try to do all of this in a single function, else you may end up defeating the purpose of using a function | + | If no extensive path information is given, |
- | * if you have similar, but not exactly identical, tasks to implement, see if your resulting function can't somehow be created | + | |
- | ====How do I implement a funtion? | + | As for modes, there are 3 main modes we will be focusing on (there are other combinations, |
- | A function consists of the following: | + | |
- | * **__return type__**: this can be any valid data type available to you in C, with the addition of **void**. | + | * read: " |
+ | | ||
+ | | ||
- | * **__function name__**: | + | Both the location and mode of the parameters are strings (arrays of char, with a terminating NULL terminator). |
- | * **__parameters__**: | + | If we wanted to open the file " |
- | * **__function body__**: the bulk of the function. This is the code you implement that accomplishes a particular task. | + | <code c> |
+ | fopen(" | ||
+ | </ | ||
- | ====Function vs. Procedure==== | + | **fopen()** returns a FILE pointer, so in order to make use of it, we need to connect its return value with our FILE pointer, as follows: |
- | Technically, | + | <code c> |
+ | fp = fopen(" | ||
+ | </ | ||
- | But what if we want to return nothing? Well, even though it is possible with the use of the **void** data type, it is generally not good practice. If you are not returning | + | If there was a problem opening |
- | For example: | + | ====Writing to a file==== |
- | * If your function was successful, you should return a 0. | + | At this point, we can write (or output) to this " |
- | * If your function was unsuccessful, | + | |
- | Ok, so if we're allowed only one return statement, how can we return more than one value? The simple answer is- we cheat. By employing | + | Output can be done with a familiar function |
- | So, by using pointers in our function' | + | This would write "hello, world!\n" to our output file: |
- | + | ||
- | ====Pass by value / Pass by address==== | + | |
- | In many programming text books, you will see reference to "pass by value" and "pass by reference" | + | |
- | + | ||
- | ===Pass by value=== | + | |
- | When we pass by value, a copy of a variable is made, and is entirely independent (aside from the initial value of the data) of the source data. | + | |
- | + | ||
- | Any changes made to that variable within the function remain within the function-- no changes are reflected back in the original variable (unless otherwise manipulated). | + | |
- | + | ||
- | Passing by value is easy, we just declare variables within the parenthesis as normal: | + | |
<code c> | <code c> | ||
- | int funcname(int var1, int var2) | + | fprintf(fp, " |
- | { | + | |
</ | </ | ||
- | In this case, the function | + | This is why I've been having us use **fprintf()** all along (instead |
+ | |||
+ | ====Reading from a file==== | ||
+ | If we had instead opened our file for reading, we could read from it the same way we obtain keyboard input: **fscanf()** | ||
- | So, to **call** | + | For example, this will read an unsigned short integer from the file pointed |
<code c> | <code c> | ||
- | result = funcname(value1, value2); | + | fscanf(fp, " |
</ | </ | ||
- | In this case, **value1** gets sent in as the first parameter (and **var1** is declared and set equal to **value1**). Similar case for **value2**/ | + | ====When the data ends: End of File checking==== |
+ | When you are reading from a file and have exhausted its contents, the last character read from the file should be a special EOF symbol, | ||
- | ===Pass by address=== | + | A good function to use is **feof()**, which takes a FILE pointer |
- | When we pass by address, we use pointers | + | |
- | We do this by using the < | + | ====Responsible file access==== |
+ | Doing any digging you will see that it is entirely within our ability to open files for reading AND writing; I would caution you against | ||
- | A sample | + | ====closing a file==== |
+ | Just as you are the highly responsible and respectful individual when returning rented VHS tapes to the rental store, or loaned cassettes or 8-tracks from the library (WHAT?), you have been kind and put the media in a state where it is no longer connected to your processing environment (you ejected it). | ||
+ | |||
+ | In the case of file access in C, that means remembering to **CLOSE** the file when we are done with it, and that can be done with the **fclose()** | ||
<code c> | <code c> | ||
- | int funcname(int *val1, int *val2) | + | fclose(fp); |
- | { | + | |
</ | </ | ||
- | And then, to call this function, we do as follows: | + | Having a file open allocates additional resources. Forgetting to close the file when done keeps those resources in use. Granted, while they will be deallocated on program exit (and our programs are all quick to execute at this point), it is a good habit to perform proper file management by closing files when we are done with them, so when our programs are more complex, that won't be a bug that needs tracking down. |
- | + | ||
- | <code c> | + | |
- | result = funcname(& | + | |
- | </ | + | |
=====Program===== | =====Program===== | ||
- | Using functions, we are going to implement the classic "Fox, Chicken, Corn" game. | + | For this project, mixing together all the skills |
- | ====Rules==== | + | In **/ |
- | The premise | + | |
- | The boat, unfortunately, | + | < |
+ | NAME # 1S 1T 2S 2T 3S 3T ... #S #T | ||
+ | </ | ||
- | There exists the following relationship with the items: | + | Where: |
- | * The fox, left alone with the chicken, will eat the chicken. | + | * the first 8 characters correspond to an ALL UPPERCASE name of an individual (name doesn' |
- | * The chicken, left alone with the corn, will eat the corn. | + | * the # refers to the number of score pairs associated with that individual (will not exceed 127) |
+ | * then a set of number pairs (labeled S and T, for Score and Total), that are associated with that individual (individual numbers | ||
- | So one needs to craft a careful means of transporting | + | It will be your task to write a program that: |
+ | * opens that file: | ||
+ | * via its absolute path | ||
+ | * for reading | ||
+ | * load the data for each line into a custom struct you've made that contains the following elements: | ||
+ | * place to store the person' | ||
+ | * store the person' | ||
+ | * array to store the person' | ||
+ | * array to store the corresponding totals for each score | ||
+ | * array to store the average of each score:total pair | ||
+ | * element to store the tally of all the scores | ||
+ | * element to store the tally of all the totals | ||
+ | * element to store the average of the averages | ||
+ | * element to store the average | ||
+ | * opens the local file: **sfa0.out** for **writing** | ||
+ | * stores the processed results you have in memory (in your structs), in the following format: | ||
- | ====Programming Considerations==== | + | < |
+ | Name:#: | ||
+ | </ | ||
- | * Your program should display the current scene (using textual characters) | + | Of particular note: |
- | * visualize the location of the farmer, fox, chicken, corn, river, and boat | + | |
- | * Do not worry about " | + | |
- | * At the start of the game, prompt the user for a display of the game rules and instructions | + | |
- | * At the conclusion of the game: | + | |
- | * display the total number of turns taken before the game reached its end (successful or otherwise) state | + | |
- | * prompt the user if they would like to play again | + | |
- | * Create, populate, and use the following functions: | + | |
- | * **intro(); | + | |
- | * **display(); | + | |
- | * **chkmove(); | + | |
- | * There are to be **NO** global variables used in your program. Pass any needed variables by value or address between functions | + | |
- | * Of your variables and functions, you are to pass **at least** one variable by address and manipulate it within the called function (so the changed value is reflected outside the called function as well). | + | |
- | * You are also to pass **at least** one variable by value and utilize it with the called function. | + | |
- | * Implement your code in a single .c file- **fcc0.c** | + | |
- | =====Programming Assumptions===== | + | * Name of individual is that changed Uppercase lead-in letter followed by all lowercase |
- | A couple things | + | * category fields are separated by colons ':' |
+ | * averages should be truncated 2 places after the decimal point | ||
+ | * if rounding occurs, so be it; if not, don't worry about it | ||
+ | * the written out score pairs are done so in reverse order (last to first, although score still precedes total) | ||
+ | * the score is separated from the tally by a comma ',' | ||
+ | * the field separators | ||
- | * be creative in your design and implementation of this game. | + | For example, if the source data was: |
- | * consistently indent your code so that it is readable! | + | |
- | * document your code so I know you know what you're doing | + | |
- | * and, weeks from now, so will you. | + | |
- | * Polish your output so it appears consistent to the end user | + | |
- | =====Contemplations===== | + | < |
- | Perhaps things that could be incorporated into your weekly journal entry... | + | KRIS 2 13 17 9 18 |
+ | </ | ||
- | | + | The corresponding line written out to **sfa0.out** would be: |
- | | + | |
- | * Show me the code that calls the following function: **int sample(int *, int);** | + | <code> |
+ | Kris:2: | ||
+ | </ | ||
+ | Additional constraints: | ||
+ | * use FILE pointers and FILE pointer-oriented C library functions (fopen(), fprintf(), fscanf(), fclose()) | ||
+ | * close all open files when done | ||
+ | * you must have and use 2 FILE pointers | ||
=====Review of Compiling/ | =====Review of Compiling/ | ||
Just to review the compilation/ | Just to review the compilation/ | ||
Line 340: | Line 357: | ||
<cli> | <cli> | ||
- | $ submit cprog fcc0 fcc0.c | + | $ submit cprog sfa0 sfa0.c sfa0.out |
- | Submitting cprog project "fcc0": | + | Submitting cprog project "sfa0": |
- | -> fcc0.c(OK) | + | -> sfa0.c(OK) |
+ | -> sfa0.out(OK) | ||
SUCCESSFULLY SUBMITTED | SUCCESSFULLY SUBMITTED | ||
Line 348: | Line 366: | ||
You should get some sort of confirmation indicating successful submission if all went according to plan. If not, check for typos and or locational mismatches. | You should get some sort of confirmation indicating successful submission if all went according to plan. If not, check for typos and or locational mismatches. | ||
- | |||
- | What I'll be looking for: | ||
- | |||
- | < | ||
- | 78: | ||
- | *: | ||
- | *:fcc0:FCC game adequately implemented [6/6] | ||
- | *: | ||
- | *: | ||
- | *: | ||
- | *: | ||
- | *: | ||
- | *: | ||
- | *: | ||
- | *: | ||
- | *: | ||
- | *: | ||
- | *: | ||
- | </ |