Question
Programming Assignment #1: Varg1 Table of Contents Abstract........................................................................................................2 1. Overview.................................................................................................3 2. Important Note: Test Case Files Look Wonky in Notepad......................3 3. Adopting a Growth Mindset....................................................................3
Programming Assignment #1: Varg1
Table of Contents
Abstract........................................................................................................2
1. Overview.................................................................................................3
2. Important Note: Test Case Files Look Wonky in Notepad......................3
3. Adopting a Growth Mindset....................................................................3
4. Writing Variadic Functions......................................................................4
5. Varg.h.......................................................................................................4
6. Test Cases and the test-all.sh Script.........................................................5
7. Output......................................................................................................5
8. Function Requirements............................................................................5
9. Input Specifications Are a Contract.........................................................7
10. ASCII Character Values.........................................................................7
11. Compilation and Testing (CodeBlocks).................................................8
12. Compilation and Testing (Linux/Mac Command Line)........................9
13. Getting Started: A Guide for the Overwhelmed..................................10
14. Deliverables.........................................................................................11
15. Grading................................................................................................12
1 Varg is not a real word. Its a portmanteau of var and arg, which in this case stand for variable number of
arguments. The correct technical term for functions that take a variable number of arguments is variadic.
Abstract
You have encountered many functions such as printf() that were capable of taking a different
number of arguments every time you call them. However, the functions
you wrote in that class probably never had that ability; instead, they were
always restricted to taking the same number of arguments each time they
were called.
In this programming assignment, you will write two variadic function s
that is, functions that take a variable number of arguments. By
completing this assignment, you will acquire a new, advanced C
programming skill. Because of one of the restrictions placed on the
functions, you will also gain a small amount of experience developing an
algorithm with a focus on runtime efficiency.
On the software engineering side of things, you will learn to construct
programs that use multiple source files and custom header (.h) files. This
assignment will also help you hone your ability to acquire new
knowledge by reading technical specifications. If you end up pursing a
career as a software developer, the ability to rapidly digest technical
documentation and work with new software libraries will be absolutely
critical to your work, and this assignment will provide you with a gentle
exercise in doing just that.
Finally, this assignment is specifically designed to require relatively few
lines of code so that you can make your first foray into the world of
Linux without a huge, unwieldy, and intimidating program to debug. As
the semester progresses, the programming assignments will become more
lengthy and complex, but for now, this assignment should provide you
with a gentle introduction to debugging in a foreign development
environment.
Attachments
Varg.h, varsum.c
Varg.c
(Note! Capitalization and spelling of your filename matters!)
1. Overview
In this assignment, youll write two variadic functions functions that take variable numbers of
arguments, just like printf() is capable of doing. (There are also two other functions for you to write.
A complete list of required functions, including their functional prototypes, is given below in Section 8,
Function Requirements.)
You will submit a single source file, named Varg.c, that contains all required function definitions, as
well as any auxiliary functions you deem necessary. In Varg.c, you will have to #include any header
files necessary for your functions to work, including the custom Varg.h file we have distributed with
this assignment (see Section 5, Varg.h).
Note: You will not write a main() function in the source file you submit! Rather, we will compile
your source file with our own main() function(s) in order to test your code. We have attached example
source files that have main() functions, which you can use to test your code. You can write your own
main() functions for testing purposes, but the code you submit must not have a main() function. We
realize this is completely new territory for most of you, so dont panic. Weve included instructions for
compiling multiple source files into a single executable (e.g., mixing your Varg.c with our Varg.h and
testcaseXX.c files) in Sections 11 and 12 of this PDF.
Although we have included test cases with sample main() functions to get you started with testing the
functionality of your code, we encourage you to develop your own test cases, as well. Ours are by no
means comprehensive. We will use much more elaborate test cases when grading your submission.
4. Writing Variadic Functions
One of the trickiest things about writing a variadic function is that you must somehow tell the function
how many arguments youre passing to it. When you call printf(), you do this implicitly, because
printf() goes through your first argument (a string), and every time it sees a conversion code (such as
%d or %c), it knows there is another input argument waiting to be processed. By reading the
format string, the function figures out how many arguments to read after the initial one.
Included with this assignment is a file called varsum.c, which I wrote to show you how to implement a
simple function to add up an arbitrary number of integer arguments passed to a function. The file has
two versions of that function: mySum() and myOtherSum(). The only difference between the two
implementations is how each function figures out how many integers it will be processing.
From that source file, youll see that when writing a variadic function, all the magic happens with the
va_list data type and the va_start and va_arg functions. In order to use va_list, va_start, and
va_arg, you must include stdarg.h at the top of your source code, like so:
#include
Note that stdarg.h is a standard system library, just like stdio.h and string.h.
5. Varg.h
Included with this assignment is a customer header file that includes functional prototypes for all the
functions you will be implementing. You should #include this file from your Varg.c file, like so:
#include "Varg.h"
The quotes (as opposed to
same directory as your source, not a system directory.
You should not modify Varg.h in any way, and you should not send Varg.h when you submit your
assignment. We will use our own unmodified copy of Varg.h when compiling your program.
If you write auxiliary functions (helper functions) in your Varg.c file (which is strongly
encouraged!), you should not add those functional prototypes to Varg.h. Our test case programs will
not call your helper functions directly, so they do not need any awareness of the fact that your helper
functions even exist. (We only list functional prototypes in a header file if we want multiple source files
to be able to call those functions.) So, just put the functional prototypes for any helper functions you
write at the top of your Varg.c file.
Think of Varg.h as a bridge between source files. It contains functional prototypes for functions that
might be defined in one source file (such as your Varg.c file) and called from a different source file
(such as the testcaseXX.c files we have provided with this assignment).
6. Test Cases and the test-all.sh Script
Weve included multiple test cases with this assignment, which show some ways in which we might
test your code. These test cases are not comprehensive. You should also create your own test cases if
you want to test your code comprehensively. In creating your own test cases, you should always ask
yourself, How could these functions be called in ways that dont violate the program specification, but
which havent already been covered in the test cases included with the assignment?
7. Output
The functions you write for this assignment should not produce any output. If your functions cause
anything to print to the screen, it will interfere with our test case evaluation.
Please be sure to disable or remove any printf() statements you have in your code before submitting
this assignment.
8. Function Requirements
In the source file you submit, Varg.c, you must implement the following functions. You may
implement auxiliary functions (helper functions) to make these work, as well, although that is probably
unnecessary for this assignment. Please be sure the spelling, capitalization, and return types of your
functions match these prototypes exactly.
char mostFrequentChar(int n, ...);
Description: This function takes a single non-negative integer, n, followed by a list of exactly n
lowercase, alphabetic characters (any characters on the range a through z), and returns the
most frequently occurring character it received as input. If multiple characters are tied for the
distinction of most frequently occurring, you should return the first one that occurred that
number of times when processing the argument list from left to right. For example, when
processing the input to the function call mostFrequentChar(5, 'a', 'b', 'b', 'a', 'c'),
both a and b are tied (with two occurrences each), but the first character to rack up two
occurrences when reading the list in order (from left to right) is b. (For further examples, see
the test cases included with this assignment.)
Special Restriction: As you read the list of input arguments, you are not allowed to store that
list anywhere in memory (for example, in a linked list or a string). In other words, you can read
the list of arguments passed to your function exactly once. You should not try to save that list in
memory so that you can re-read it multiple times within your function.
Output: This function should not print anything to the screen.
Return Value: The most frequently occurring character in the argument list. (See the
description above for an explanation of how to handle ties.) If n is equal to zero, your function
should return the \0 character, which is Cs null sentinel.
char fancyMostFrequentChar(char c, ...);
Description: This function takes as its input a list of characters. The function is guaranteed to
receive at least one argument. The last argument passed to the function will always be the \0
character, which is Cs null sentinel. All other characters in the list will be lowercase, alphabetic
characters (any characters on the range a through z). Your function should return the most
frequently occurring character in the list. In the event of ties, you should handle them in the
same way that the mostFrequentChar() function handles ties (described above). Note that its
possible for \0 to be the only argument given, in which case you should return \0.
Special Restriction: This function is subject to the same special restriction listed above for the
mostFrequentChar() function.
Output: This function should not print anything to the screen.
Return Value: The most frequently occurring character in the argument list. (See the
description above for an explanation of how to handle ties.) If \0 is the only argument passed
to this function, then you should return \0.
double difficultyRating(void);
Output: This function should not print anything to the screen.
Return Value: A double indicating how difficult you found this assignment on a scale of 1.0
(ridiculously easy) through 5.0 (insanely difficult).
double hoursSpent(void);
Output: This function should not print anything to the screen.
Return Value: An estimate (greater than zero) of the number of hours you spent on this
assignment.
9. Input Specifications Are a Contract
In testing, you can rest assured that we will only call your functions in ways that jive with the function
descriptions above. For example, we will never call mostFrequentChar() without specifying an
integer as the first argument, and that integer is always guaranteed to correctly indicate the number of
arguments that follow. Similarly, we will never call fancyMostFrequentChar() without ending the list
of parameters with a null sentinel (\0), and neither function will receive unexpected characters in the
argument list (such as a capital Q or punctuation marks such as !).
10. ASCII Character Values
Note: If you havent thought about how to solve this problem yet, it might not be immediately obvious
why the information in this section might be useful to you in this assignment.
In C, each character has an underlying integer value called its ASCII value. (ASCII is an international
standard for character numbering. If you want to read more about the topic, see the ASCII article on
Wikipedia. For this assignment, however, you dont need to know any more about ASCII than what
Ive written up in this section.)
To see a characters underlying integer value, you can always just print it as an integer, like so:
printf("%d", 'a');
The ASCII value for a is 97, so the above line of code should print out 97.
Lowercase letters are numbered sequentially: a is 97, b is 98, c is 99, and so on. If for some reason
you wanted to convert the characters a through z to integers 0 through 25 (maybe so you could use
them to access indices in an array of length 26?), you could just subtract 97 from those characters. For
example:
printf("%d", 'a' - 97); // 'a' - 97 = 97 97 = 0
printf("%d", 'b' - 97); // 'b' - 97 = 98 97 = 1
printf("%d", 'c' - 97); // 'c' - 97 = 99 97 = 2
Personally, I never hard-code the value 97 when converting characters to integers (partly because I
never used to be able to remember it off the top of my head). Instead, I just use a in place of 97,
because the math will always work out:
printf("%d", 'a' - 'a'); // 'a' - 'a' = 97 97 = 0
printf("%d", 'b' - 'a'); // 'b' - 'a' = 98 97 = 1
printf("%d", 'c' - 'a'); // 'c' - 'a' = 99 97 = 2
Continued on the following page...
11. Compilation and Testing (CodeBlocks)
The key to getting multiple files to compile into a single program in CodeBlocks (or any IDE) is to
create a project. Here are the step-by-step instructions for creating a project in CodeBlocks, which
involves importing Varg.h, testcase01.c, and the Varg.c file youve created (even if its just an
empty file so far).
1. Start CodeBlocks.
2. Create a New Project (File -> New -> Project).
3. Choose Empty Project and click Go.
4. In the Project Wizard that opens, click Next.
5. Input a title for your project (e.g., Varg).
6. Choose a folder (e.g., Desktop) where CodeBlocks can create a subdirectory for the project.
7. Click Finish.
Now you need to import your files. You have two options:
1. Drag your source and header files into CodeBlocks. Then right click the tab for each file and
choose Add file to active project.
or
2. Go to Project -> Add Files.... Browse to the directory with the source and header files you want
to import. Select the files from the list (using CTRL-click to select multiple files). Click
Open. In the dialog box that pops up, click OK.
You should now be good to go. Try to build and run the project (F9).
Note that if you import both testcase01.c and testcase02.c, the compiler will complain that you
have multiple definitions for main(). You can only have one of those in there at a time. Youll have to
swap them out as you test your code.
!
14. Deliverables
Your source file must not contain a main() function. Do not submit additional source files, and do not
submit a modified Varg.h header file. Your source file (without a main() function) should compile at
the command line using the following command:
gcc -c Varg.c
It must also compile at the command line if you place it in a directory with Varg.h and a test case file
(for example, testcase01.c) and compile like so:
gcc Varg.c testcase01.c
Contents of Varg.h
#ifndef __VARG_H #define __VARG_H
// Functional Prototypes
char mostFrequentChar(int n, ...);
char fancyMostFrequentChar(char c, ...);
double difficultyRating(void);
double hoursSpent(void);
#endif
Contents of varsum.c
// ============== // Varg: varsum.c // ============== // A program to illustrate the creation of variadic functions (functions that // can take a variable number of parameters). // // SEE ALSO: // http://www.lysator.liu.se/c/c-faq/c-7.html#7-1
#include
// mySum() takes any number of integers as its arguments, with the following // restriction: the first argument MUST be the number of integers to follow. // For example, to sum 1, 2, and 3, the proper function call would be: // // mySum(3, 1, 2, 3); // // Notice that since there are three integers to be summed, the first argument // to the function is 3.
int mySum(int first, ...);
// myOtherSum() takes any number of integers as its arguments, but has a // different restriction: the last integer to be summed will be zero, and zero // cannot occur anywhere else in the list of arguments. That is to say, the // function will know to stop summing as soon as it encounters a zero. // // For example, the following two functional calls will have the same result: // // myOtherSum(1, 2, 3, 0); // myOtherSum(1, 2, 3, 0, 6, 2, 7, 4, 8, 0);
int myOtherSum(int first, ...);
int main(void) { int d;
// Recall that mySum() requires us to tell it how many integers it is // summing up. So in the function call below, the first 5 says, "You're // about to see five integers. Sum them up!"
d = mySum(5, 1, 2, 3, 4, 5); printf("Result of mySum(): %d ", d);
// myOtherSum, on the other hand, will keep reading integers until it // encounters zero. That is why we terminate the following list of arguments // with a zero. Otherwise, the function would keep on summing, accessing // unpredictable parts of memory in a dangerous attempt to read more // integers!
d = myOtherSum(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 0); printf("Result of myOtherSum(): %d ", d);
return 0; }
// First and foremost: when dealing with an arbitrary number of arguments to a // function, we always capture the first argument explicitly into a variable, // and then shuttle the rest off to a list, using elipses. Here, we know that // the first argument to mySum() will always be an integer, so we capture it in // a variable of type int called "first."
int mySum(int first, ...) { // We're going to hold the sum in a variable called "total," which we // initialize to zero. We're also going to use p and i to hold integers // later in the function. int total = 0; int p, i;
// Now this is where things get crazy. We're declaring a variable of type // va_list, called "argp." Basically, argp, is going to hold our list of // arguments to this function! To be clear: va_list is a data type, just // like int, char, float, and so on. va_list argp;
// This is how we initialize argp. The line basically means, "Okay, argp is // a list of arguments to this function. But where does it start? Well, it // starts with the first variable passed to this function, which we // conveniently named "first." If we had captured that variable under a // different name, we would use that name below. va_start(argp, first);
// Now we're ready to get our arguments, one by one, using a loop. Remember // that the variable "first" tells us how many there are, so we want to loop // "first" number of times.
for (i = 0; i < first; i++) { // The line below tells us to get the value of the next argument from // the list. (This will start by pulling the variable after "first," // because "first" itself isn't included in the "..." portion of the // list.) // // We have to tell the va_arg() function where to look for these // arguments, as well as what type of data we are pulling. We've got all // the information we need about our arguments stored in the variable // called "argp," so that's our first argument to the va_arg() function. // We also know that we're only dealing with integers, so the second // argument to va_arg() is int -- the type of data we're reading. If we // were reading a different type of data, we would replace "int" with // that data type (e.g., "double"). There are some exceptions here, // though, which your compiler might warn you about if you encounter // them. ;) // // The resulting value is stored in p. // // After we pull an integer out of argp, it is removed from the list, // and the next time we call the va_arg function, it will give us the // next integer in the list.
p = va_arg(argp, int);
// And of course, we want to add p to total in order to keep track of // the sum as we go. Recall that "total" was intialized to zero at the // beginning of the program.
total += p; }
// This frees up any lingering memory associated with the argp variable and // helps ensure that we don't have any memory leaks emanating from this // function. va_end(argp);
// Finally, the loop has terminated and we now return the value of "total," // which should be the sum of all the arguments passed to mySum() (except // for the first argument, which was just an argument count).
return total; }
int myOtherSum(int first, ...) { // These first lines are the same as above, except that we initialize // "total" to the value of "first," since in this function, the first // argument is actually part of the sequence of integers that we want to // sum. We also don't need the variable "i" that was used in the mySum() // function, because we don't use a for-loop in this one. int total = first; int p; va_list argp;
// If the first argument was zero, then we don't even look for more // arguments, because the function is supposed to stop summing as soon as we // see a zero. if (total == 0) return 0;
// Our list setup is the same as before. va_start(argp, first);
// Here we just keep pulling integers off of the argp list until we see a // zero. Recall that the zero is our cue to stop. while ((p = va_arg(argp, int)) != 0) total += p;
// This frees up any lingering memory associated with the argp variable and // helps ensure that we don't have any memory leaks emanating from this // function. va_end(argp);
// And finally, return the sum. return total; }
Contents of testcase01.c
// ================== // Varg: testcase01.c // ================== // Boundary check to make sure your difficultyRating() and hoursSpent() // functions are implemented correctly.
#include
int main(void) { int success = 1;
if (difficultyRating() < 1.0 || difficultyRating() > 5.0) success = 0; if (hoursSpent() <= 0.0) success = 0;
printf("%s ", success ? "Hooray!" : "fail whale :(");
return 0; }
contents of testcase02.c
// ================== // Varg: testcase02.c // ================== // A simple test of the mostFrequentChar() function.
#include
int main(void) { char c = mostFrequentChar(7, 'a', 'b', 'c', 'd', 'd', 'b', 'a');
if (c == 'd') printf("Hooray! "); else printf("fail whale :( ");
return 0; }
Step by Step Solution
There are 3 Steps involved in it
Step: 1
Get Instant Access to Expert-Tailored Solutions
See step-by-step solutions with expert insights and AI powered tools for academic success
Step: 2
Step: 3
Ace Your Homework with AI
Get the answers you need in no time with our AI-driven, step-by-step assistance
Get Started