This lab will explore the use of pointers in several ways. Pointers will be used
ID: 1800785 • 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.
Create a new project using the Resistor class developed in Week 4, and include a new main() test function.
STEP 2: Modify the Resistor-Class Definition
Add a static data member of the class Resistor in the constructor to keep track of the number of Resistor objects that are dynamically created.
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.
STEP 3: Create the Test Function Main() and the Support Function
Create an array of pointers of type Resistor.
Use elements of the pointer array to allow the user to dynamically allocate memory and to instantiate objects of the Resistor class.
Use the indirect member-selection operator (pointer) in the test routine to set values of members of the Resistor class.
Display the Resistor objects according to the nominal resistance value.
Use pointer arithmetic to access the individual Resistor objects.
Function main() should also ensure that there are no memory leaks when the program ends.
This is the resistor class i created in week 4:
#include<iostream>
#include<string>
using namespace std;
class resistor{
public:
resistor()
{
resistance=0;
tolerance=0;
min=0;
max=0;
}
void display()
{
cout << "resistance:" << resistance << endl;
cout << "tolerance:" << tolerance << endl;
cout << "min:" << min << endl;
cout << "max:" << max << endl;
}
void change()
{
cout << "Enter resistance:";
cin >> resistance;
cout << " Enter tolerance:";
cin >> tolerance;
min = resistance - (resistance * tolerance/100);
max = resistance + (resistance * tolerance/100);
}
public:
float resistance,tolerance,min,max;
};
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 (1Related Questions
Hire Me For All Your Tutoring Needs
Integrity-first tutoring: clear explanations, guidance, and feedback.
Drop an Email at
drjack9650@gmail.com
drjack9650@gmail.com
Navigate
Integrity-first tutoring: explanations and feedback only — we do not complete graded work. Learn more.