Academic Integrity: tutoring, explanations, and feedback — we don’t complete graded work or submit on a student’s behalf.

This lab will explore the use of pointers in several ways. Pointers will be used

ID: 1929268 • Letter: T

Question

This lab will explore the use of pointers in several ways. Pointers will be used to dynamically allocate memory for new class objects on demand from the user, and they will be used to access class-member functions. Pointer arithmetic will be used to access and sort class objects according to criteria explained in the lab.

Pointers are, essentially, address variables, or variables that hold as their value the address of other variables. In terms of memory management, they are very powerful devices, and they more closely and efficiently use the actual internal hardware registers of the microprocessor that the program operates on.

Pointers also have the requirement that the pointer type must be of the same data type as the variable, or the data that it points to or holds the address of. The power of pointers also hints at the potential complexity of their use, which is why this lab is focused almost entirely on several different aspects and uses of pointers. The lab also introduces pointer arrays and pointers to pointers.

The Resistor class created in the Week 2 lab will be used as the class that the pointer operations will be used upon. The lab also requires the use of accessor functions and static data members, which may need to be added to the Resistor class definition and implementation.

STEP 1: Create a Multifile Project
Create a new multifile project using the Resistor class developed in Week 1, and include a new main() test function.

STEP 2: Modify the Resistor-Class Definition
1. Add a static data member of the class Resistor to keep track of the number of Resistor objects that are dynamically created. This will also be used to limit the number of objects that are dynamically created to the maximum array size of the pointer array in the test function main().
2. In the Resistor constructor, use a random-number generator to randomly assign a nominal resistance value to the object between 1,000 and 10,000 ohms. The resistance values are not required to be standard resistance values.

STEP 3: Create the Test Function Main() and the Support Function
1. Create an array of pointers of type Resistor.
2. Use elements of the pointer array to allow the user to dynamically allocate memory and to instantiate objects of the Resistor
3. Use the indirect member-selection operator (pointer) in the test routine to access function members of the Resistor
4. Write a new, nonclass function called in function main() to sort the pointers to the Resistor objects in order from lowest nominal resistance value to highest, passing a pointer to the Resistor-object pointer as the only passed data
5. Display the sorted Resistor objects according to the nominal resistance value, from lowest to highest.
6. Within the sorting function, use pointer arithmetic to access the individual Resistor objects.
7. Function main() should also ensure that there are no memory leaks when the program ends.

THIS IS THE GIVEN OUTPUT FROM PROFESSOR:

Enter name for resistor object: Res1

Resistor being edited: Res1

Current resistance tolerance = 10 %
Valid tolerances are 1%, 2%, 5% or 10%

Enter 1, 2, 5 or 10: 5

Tolerance set to 5 %

Current nomimal resistance = 1000 ohms
Standard 10% Resistance Values, First Three Digits


100 110 120 130 150 160 180 200 220 240
270 300 330 360 390 430 470 510 560 620
680 750 820 910

Enter first three digits: 820
You entered 820
Valid EIA value entered

Enter a power of ten multiplier between -2 (0.01) and 3 (1000): 3
You entered 3

Enter name for resistor object: Res3


Resistor being edited: Res3

Current resistance tolerance = 10 %
Valid tolerances are 1%, 2%, 5% or 10%

Enter 1, 2, 5 or 10: 2

Tolerance set to 2 %

Current nomimal resistance = 1000 ohms
Standard 10% Resistance Values, First Three Digits


100 105 110 115 121 127 133 140 147 154
162 169 178 187 196 205 215 226 237 249
261 274 287 301 316 332 348 365 383 402
422 442 464 487 511 536 562 590 619 649
681 715 750 787 825 866 909 953

Enter first three digits: 536
You entered 536
Valid EIA value entered

Enter a power of ten multiplier between -2 (0.01) and 3 (1000): -1
You entered -1

Enter name for resistor object: Res3


Resistor being edited: Res3

Current resistance tolerance = 10 %
Valid tolerances are 1%, 2%, 5% or 10%

Enter 1, 2, 5 or 10: 10

Tolerance set to 10 %

Current nomimal resistance = 1000 ohms
Standard 10% Resistance Values, First Three Digits


100 120 150 180 220 270 330 390 470 560
680 820

Enter first three digits: 470
You entered 470
Valid EIA value entered

Enter a power of ten multiplier between -2 (0.01) and 3 (1000): 1
You entered 1


Resistor object name is Res1

Nominal resistance value = 820000.000 ohms
Tolerance = 5.000 %
Minimum Resistance = 779000.000 ohms
Maximum Resistance = 861000.000 ohms



Resistor object name is Res3

Nominal resistance value = 53.600 ohms
Tolerance = 2.000 %
Minimum Resistance = 52.528 ohms
Maximum Resistance = 54.672 ohms



Resistor object name is Res3

Nominal resistance value = 4700.000 ohms
Tolerance = 10.000 %
Minimum Resistance = 4230.000 ohms
Maximum Resistance = 5170.000 ohms


820000.000
53.600
4700.000

Resistor object name is Res3

Nominal resistance value = 53.600 ohms
Tolerance = 2.000 %
Minimum Resistance = 52.528 ohms
Maximum Resistance = 54.672 ohms



Resistor object name is Res3

Nominal resistance value = 4700.000 ohms
Tolerance = 10.000 %
Minimum Resistance = 4230.000 ohms
Maximum Resistance = 5170.000 ohms



Resistor object name is Res1

Nominal resistance value = 820000.000 ohms
Tolerance = 5.000 %
Minimum Resistance = 779000.000 ohms
Maximum Resistance = 861000.000 ohms


Explanation / Answer

There comes a time when a project has outgrown the scope of a single file. Perhaps it's the point at with you need to add more RAM to your computer just to open your project, or when you realize you've just spent 45 minutes tracking down the timeout function you swore you wrote two weeks ago. Whatever the reason, it's time to split your project up into several manageable files, which you can then keep better track of. This tutorial will give several pointers about the intricacies of how to accomplish such a task. Step one - identify common routines First of all, it makes sense to group all the common routines into their own files - eg. one for USART management, one for your protocol layer handler, one for your main code. You should determine which functions can be moved into a separate files while still retaining some connection with one another. Let's take the following example of routines: Code: GetUSARTByte() TurnOnStatusLed() SetupSpeaker() TurnOffStatusLed() SetupUSART() main() CheckTempSensorVal() ProcessByte() Beep() EnableUSART() SleepMode() CheckADCChanel() We can split these routines up into several small files - one for the USART, one for the main (and misc) routines, one for the speaker and one for the ADC (and related processing). Let's take a look at our proposed new structure: USART.c Code: SetupUSART() EnableUSART() GetUSARTByte() ProcessByte() Speaker.c Code: SetupSpeaker() Beep() ADC.c Code: CheckADCChanel() CheckTempSensorVal() Main.c Code: main() SleepMode() TurnOnStatusLed() TurnOffStatusLed() Ok, looks pretty good! We'll cut and paste those routines into the appropriate files in the same project directory, so now we have a bunch of C files containing related functions. Adding the new files to your makefile Even though you've made no functional changes to your code outside moving certain routines to a different file, you still need to tell the compiler, linker and associated GCC tools where everything is now located. Open up your makefile, and you should find some lines similar to the following (if your makefile is based off the WinAVR template): Code: # List C source files here. (C dependencies are automatically generated.) SRC = $(TARGET).c What we now need to do is add the file names of the newly created files. We'll take our above example here again for consistency. Our new extra files are called "ADC.c", "Speaker.c" and "USART.c", so we need to add those to the SRC line of the makefile. Code: # List C source files here. (C dependencies are automatically generated.) SRC = $(TARGET).c ADC.c USART.c Speaker.c Now, that'll work, but it's a real pain for future expansion. To make our life easier, we'll place the filenames on their own line in alphabetical order. To indicate a line continuation in a makefile, we need to place a "" at the end of the continued lines: Code: # List C source files here. (C dependencies are automatically generated.) SRC = $(TARGET).c ADC.c Speaker.c USART.c NB: Watch the file case! To GCC and its related utilities, "MAIN.C" is not the same as "Main.c". Make sure you put down the file names in the exact same case as they appear inside explorer, or you'll get build errors! Naming the routines One problem with our multi-file setup remains; routines are still hard to find across the files. One might easily identify the file location of our mythical "CheckADCChanel()" routine, but what about "SleepMode()"? Obviously a naming convention becomes important. Now, this is where it gets tricky. There's really no set standard for function names, and every one prefers something different. It is important to choose which one you prefer, but it is ten times more important to remain consistent in your scheme across your entire project. The first word, symbol or acronym in your function name should indicate the file it is located in. For example, all the ADC functions will have "ADC" at their start, and all the speaker-related functions in Speaker.c would have "Speaker" at their start. You can eliminate repetition in a name as it becomes self-explanatory what the function is referring to due to the prefix - thus "CheckADCChanel()" would become "ADCCheckChannel()" (or similar), rather than the superfluous "ADCCheckADCChanel()". I'll use our example again and put here a possible function naming scheme. Note that the "main()" function's name remains unchanged as it is mandated by the C standard: USART.c Code: USARTSetup() USARTEnable() USARTGetByte() USARTProcessByte() Speaker.c Code: SpeakerSetup() SpeakerBeep() ADC.c Code: ADCCheckChanel() ADCCheckTempSensorVal() Main.c Code: main() MainSleepMode() MainTurnOnStatusLed() MainTurnOffStatusLed() This new scheme makes finding the location of a routine quick and easy, without the need for a multi-file search utility. Don't forget to change the function prototypes in your header file to the match your new function names! Making functions static Static functions is possibly something you've never heard of up to now. The process of declaring a function to be static indicates to the compiler that its scope is limited to the source file in which it is contained - in essence it makes the function private, only accessible by other function in the same C file. This is good practice from two standpoints; one, it prevents outside code from calling module-internal functions (and reduces the number of functions exposed by the file) and two, it gives the compiler a better chance to optimize the function in a better way that if it was assumed to be able to be called by any other source file. Identify which of your functions are module-internal, and add in the static keyword. In our example, let's say that the "USARTEnable()" function was only called by "USARTSetup()", and never by any other source file. Assume that the USARTEnable function is declared as the following: Code: void USARTSetup(void) We'll make the function static to reduce its scope to inside USART.c: Code: static void USARTEnable(void) Note that the static keyword should be added to both the prototype in the header file, as well as to the function in the C source file. Global variables Your project probably has quite a few global variables declared at the top of your main source file. You need to cut-and-paste them each into the most appropriate source file. Don't worry if it's referenced by more than one file; dealing with that case will be handled later in the tutorial. For now, just put it in the C file you deem to be the best for it. Just in case you've done this, remember the following golden rule: header files should declare, not define. A header file should not itself result directly in generated code - it is there to help the compiler and yourself link together your C code, located in C files. If you've put any globals inside your header file, move them out now. Splitting the header file This is where the hard part begins. So far we've successfully split up the contents of our project into several C files, but we're still stuck with one large header file containing all our definitions. We need to break our header file up into separate files for each of our C modules. First, we'll create a bunch of .h header files of the same names as our .c files. Next, we'll move the obvious things from the master header file, the function prototypes. Copy each of the prototypes into the respective header files. Next, the macros. Again, move the macros into the header file where they are used the most. If you have any generic macros that are used in the majority of your source files, create a new "GlobalDefinitions.h" header file and place them there. Do the same for any typedefs you may have in your header file. Let's assume our above example has the following original header file: Code: #define StatusLedRed (1
Hire Me For All Your Tutoring Needs
Integrity-first tutoring: clear explanations, guidance, and feedback.
Drop an Email at
drjack9650@gmail.com
Chat Now And Get Quote