*************************** Arrays, Structs, Pointers *************************** Purpose ******* This activity introduces "more advanced" features of the C language; useful in building programs or implementing TI DriverLib functions. Hardware and Tools ****************** * [Optional] |devboard_long| or |rslk_long| Preparation *********** Review the website descriptions for :ref:`Arrays `, :ref:`Structs `, and :ref:`Pointers `. Instructions ************ The following steps will guide you through implementing and using arrays and structs. Pointers are also used, but to a much more limited extent. Let's first take a look at arrays. Arrays ------ This task will build a multiplication table from the numbers contained in two arrays. #. First, download and import the course template project: :download:`TemplateProject.zip <../_static/ccs_projects/TemplateProject.zip>`. You should rename the imported project to something like "Activity-Arrays." * Alternatively: use the default template for an online C-Compiler. You may need to add `#include` to the top of the default template for it to recognize the :code:`[u]intN_t` types. #. Let's create an array full of numbers. Copy and paste the below line such that the array variable, :code:`array1`, will be a global variable. .. code-block:: C uint32_t array1[] = {1,2,3,4,5,6,7,8,9,10}; This code will create an array of length 10 with the shown values. #. Let's ensure that the array is created appropriately. Add the below :code:`for` loop to print out each element of the array within the :code:`main` function, just prior to the :code:`while(1)`. Compile and run the code to test (ensure the terminal is connected). .. code-block:: C uint8_t i; // Loop count variable for(i=0;i<10;i++){ // Loop through the indices of the array printf("Element %u is:\t%u\r\n",i,array1[i]); } #. Now we need a second array. Create an empty second array of length 10 and then fill the array with random values between 0 and 20. You can use the :code:`for` loop in the previous step to accomplish this. You should use the function :ref:`rand() ` to generate the random values. #. Modify the :code:`printf` statement to print out the values stored into the second array after they are generated. Compile and run the code to test. #. Now build out the multiplication table formed by our two arrays. We'll need a 2D array to store the values into. Create an empty 2D array that is 10x10 (same size as each array). A 2D array may be created by using the format :code:` var[m][n]`, where :code:`m` and :code:`n` are the dimension sizes. #. The easiest way to do fill the table is with two nested :code:`for` loops, something like: .. code-block:: C uint8_t i,j; // Two loop variables for(i=0;i<10;i++){ // Outer loop for(j=0;j<10;j++){ // Inner loop // In here we can use i and j to loop through elements, // where i and j will be the row/column index of the 2d matrix } } #. Add code to print out the multiplication table. You may remove the previous :code:`printf` commands used. As this print is fairly complicated, the code to do so is provided below, with some portions missing, marked with :code:`???`. .. code-block:: C // This portion prints one of the input arrays column header (horizontal) printf("\n\n\t"); // Move down a couple lines and skip the first "column" for(i=0;i<10;i++){ printf("\t%u",???); // Print each element in the array, one each column (tab) } printf("\r\n"); // move to the next line to print the table // This portion prints the other input array as the row headers (vertical) // and the multiplication table (2D array) for(i=0;i<10;i++){ printf("\t%u",???); // Print the i-th element of the input array for(j=0;j<10;j++){ printf("\t%u",???); // print all the elements of the i-th row for the table } printf("\r\n"); // move to next line } If all is successful, you should see output like below; where the blue box marks a set of input array elements, the red box marks the other set of input array elements, and the green box is the calculated multiplication table 2D array. Of course, this output assumes that both input arrays have the values 1-10 instead of one being random. It must be ensured that the multiplication table matches that of the input arrays used and that the table is not flipped .. image:: ../_static/mult_table_output.png :align: center :scale: 75 #. Finally, modify the length of the randomly generated array to 15. This will require that several items (:code:`for` loop conditions) be adjusted as well to ensure the code still works appropriately. .. tip:: At this point, you may have noticed that the "random numbers" that are being generated to fill the array are always the same sequence and therefore not actually random. See :ref:`srand ` for information on how to avoid this situation. It is not necessary to fix this in this program. Structs ------- * This task will provide an example on how to use predefined structs in programming tasks. In this case, we will use a struct to store information about the set of homework grades below: .. list-table:: Homework Gradebook Statistics :widths: 20 16 16 16 16 16 :header-rows: 1 * - Homework - 1 - 2 - 3 - 4 - 5 * - Average - 94.2 - 76.7 - 84.5 - 92.1 - 66.3 * - Std. Dev. - 10.8 - 12.6 - 15.9 - 12.6 - 27.3 * - Minimum - 55 - 40 - 25 - 45 - 10 * - Maximum - 100 - 100 - 100 - 100 - 100 * - Submissions - 109 - 106 - 101 - 99 - 99 #. First, let's prepare another fresh template project: :download:`TemplateProject.zip <../_static/ccs_projects/TemplateProject.zip>`. You should rename the imported project to something like "Activity-Structs". * Alternatively: use the default template for an online C-Compiler. #. We don't expect students to know how to create a struct in this course, just how to use them; therefore, a struct definition is given below for storing the homework information. Copy and paste this code above where function prototypes would exist. .. code-block:: C // This is one implementation for creating a custom struct variable type named "homework_t" typedef struct _homework_t { float average; // The struct has a "field" for each value listed float stdev; // in the "Homework Gradebook" table. uint8_t min; // Note that the fields can be all different types uint8_t max; uint16_t subs; } homework_t; #. Now create a global variable and store the values of homework 1 from the table. The commands to store the values may be done within the :code:`main` function. .. tip:: The variable type to create the homework struct is :code:`homework_t`. This should be used the exact same way that you would use :code:`uint32_t`, etc. .. tip:: Dot notation is used to assign values to each struct field; for example: :code:`struct_name.field`. If |ccs| recognizes the type of the struct, then as you type the variable name followed by a period, |ccs| should pop up a list of the available fields. This features is extremely useful when using unfamiliar and/or complicated struct types. #. You may check if your work was correct by using the print statement below and replacing the :code:`???` instances with the variable name you used. The **Edit → Find/Replace...** function may be useful in doing this. .. code-block:: C printf("Homework 1 Stats\r\n" " Average: %.2f\r\n" " Std. Dev.: %.2f\r\n" " Minimum: %u\r\n" " Maximum: %u\r\n" "Submissions: %u\r\n", ???.average,???.stdev,???.min, ???.max,???.subs); #. We could make a new :code:`homework_t` variable for each homework; however, this implementation would be tedious and inflexible. Instead, it would make sense to make an array of :code:`homework_t` variables, where index 0 is homework 1, index 1 is homework 2, etc. Make this array now as a global variable and populate at least two of the indices with homework stats. Make sure to leave the non-array :code:`homework_t` variable created in step 3. .. tip:: Accessing fields of an array element works the same way as if it was a single variable: :code:`array[n].field = value;`. #. Modify the print statement such that all homework stats are printed consecutively. You'll want to wrap the print statement in a :code:`for` loop. You do not need to format the print statement to match the table format above, just print all of each homework's stats one at a time. Passing Structs as Pointers -------------------------------------- #. Add the following function to your struct program. This function calculates a homework average without the minimum grade included. .. code-block:: C // Prototype. Add above main function, below the homework_t definition. float remove_min_from_avg(homework_t *homework); // Declaration. Add below main function // This function calculates the average of a homework without the minimum grade. // The function will return the value of the new average. float remove_min_from_avg(homework_t *homework){ float homework_sum = homework->average*homework->subs; homework_sum -= homework->min; return homework_sum/(homework->subs-1); } #. Using this function, calculate the modified average of homework 1 new :code:`float` value. Use the single :code:`homework_t` variable created in step 3, not the array created in step 5. You will need to use the :code:`&` operated as discussed here: :ref:`Pointers `. #. Print out the value of the calculated average to verify it worked. #. Repeat the calculation for homework 2. This can be done using the homework array using the format :code:`&array[n]`. Submit Work ----------- Submit both final code files to the corresponding :xref:`Gradescope` activities. You should rename the files to an appropriate name prior to submission (e.g., arrays.c and structs.c).