[Solved] CSCE 121 Lab 9-The relationship between pointers and arrays

$25

File Name: CSCE_121_Lab_9-The_relationship_between_pointers_and_arrays.zip
File Size: 555.78 KB

SKU: [Solved] CSCE 121 Lab 9-The relationship between pointers and arrays Category: Tag:
5/5 - (1 vote)

The purpose of this lab is to help clarify the relationship between pointers and arrays; you will look at arrays of pointers, pointers to arrays, and the C/C++ treatment of multi-dimensional arrays.

This lab provides example code and youre expected to work through it, poking at it to try make sense of whats going on. The text should guide you in that process. By make sense I mean that you should be able to draw a diagram showing blocks in memory, and arrows for pointers like Ive done in the lectures.

Pointers to elements within an array

Copy and paste this into your editor, then build the code and run the result.

This program has an array of chars that stores a string. That string is passed to two functions, which are effectively identical: they print their sole argument. The functions differ only in the type that they expect that argument to be.

#include <iostream>using namespace std; void bracket_function(char str[]){ // This line will print out what is passed on the call-stack to the function: //C1: cout << str = << (void *)str << endl; cout << Bracket Function: ; cout << str << endl;} void star_function(char *str){ // This line will print out what is passed on the call-stack to the function: //C2: cout << str = << (void *)str << endl; cout << Star Function: ; cout << str << endl;} int main(){ char lyric[] = theres a Spirit can neer be told; star_function(lyric); // L1: Maybe this is a trifle surprising? bracket_function(lyric); star_function(&lyric[0]); bracket_function(&lyric[0]); // L2: And also this? // These two show how it can actually be rather useful: // C3: star_function(&lyric[32]); // C4: bracket_function(&lyric[32]); return 0;}

As weve seen in class, arrays degrade to pointers, so the functions are equivalent.

  1. The array can be passed to the function expecting a pointer (see line L1).
  2. A pointer can be passed the function expecting an array (see line L2). (The pointer is just the address of the first element of the array.)
  3. Uncomment C1 and C2, and see what it does. The input is cast (like weve seen for ints and floats) in order to lose the typing information. We do this because cout, by default, will show what is at the address when you give it a char[] or char *. Put another way: if cout receives a string, it will automatically dereference it. To print the actual address, not what is at that address, we pretend that it doesnt contain chars. (If you find the void weird, you can make it an int or some other type, too.)
  4. Next, uncomment C3. Before you run the result, think about the addresses being passed and form an hypothesis of what you think itll do. Did you get it?
  5. Finally, uncomment C4. Will that compile?

If any of the preceding is troubling to you, try to draw a memory diagram. Look at the memory addresses; does the numerical difference make sense to you? How would it differ if the arrays were of ints, floats, or some sort of struct?

Arrays with pointers to arrays

Copy and paste the following code into your editor, then build the code and run the result.

In class, we (briefly) examined an example of a 2D array. Unlike many other languages C/C++ does not allocate a sequential block for a multi-dimensional array. Instead, in the innermost level it has standard 1D arrays. The second dimension is a 1D array of pointers. The following code is intended to help clarify how this works.

#include <iostream>using namespace std; int main(){ float row_one[2] = {3.0, 1.4}; float row_two[3] = {4.5, 7.2, 5.6}; float row_three[4] = {15.6, 18.4, 22.2, 105.0}; float *different_sized[3] = {row_one, row_two, row_three}; // D1 cout << different_sized := << endl; cout << t << different_sized[0][0] << t << different_sized[0][1] << endl; cout << t << different_sized[1][0] << t << different_sized[1][1] << t << different_sized[1][2] << endl; cout << t << different_sized[2][0] << t << different_sized[2][1] << t << different_sized[2][2] << t << different_sized[2][3] << endl << endl; float **synonym = different_sized; // thats also a pointer to a pointer cout << synonym := << endl; cout << t << synonym[0][0] << t << synonym[0][1] << endl; cout << t << synonym[1][0] << t << synonym[1][1] << t << synonym[1][2] << endl; cout << t << synonym[2][0] << t << synonym[2][1] << t << synonym[2][2] << t << synonym[2][3] << endl << endl; return 0;}

An advantage of the C/C++ method is that all the elements within a certain dimension neednt be of the same size. This is illustrated by with 1D variables named row_one, row_two, and row_three. The 2D array different_sized is declared to have 3 elements, each of which we set up to point to each row. It is useful to draw a memory diagram, the rows should just be data stored linearly, and the different_sized elements should have three arrows departing it.

We can see that indexing works left to right: different_sized[i][j] first accesses the pointer stored in the ith entry of different_sized. The pointer is followed, giving an array. In that array, the jth element is accessed. (It might be useful to follow this two-step process on your diagram.)

In the previous question, we saw that a char[] is equivalent to a char *. That is general, so for any type T we have that T[] = T*. Now consider the definition on line D1 which reads float *different_sized[3]. If we think of that as (float *) different_sized[3], then we can think of a type float **. That is why the code defining synonym works similarly. The two layers of indexing essentially become a double dereferencing operation.

You might find it helpful to print different_sized and synonym to check their memory addresses. You can also check the addresses after one level of indexing. But note that &different_sized &synonym, which are of type float ***.

? HINT
This is how I did that:cout << &different_sized t= << &different_sized<< endl;cout << &synonym tt= << &synonym << endl;cout << different_sized t= << different_sized<< endl;cout << synonym tt= << synonym << endl;cout << different_sized[1] t= << different_sized[1] << endl;cout << synonym[1] tt= << synonym[1] << endl;

Arrays of pointers

Your job in this question is to do a bit of detective work to understand how this program operates. Start with the following code, which should compile and run out of the box. It provides an example of how thinking of arrays as pointers can actually be rather handy.

#include <iostream>using namespace std; bool valid_word_char(char ch){ if ((A <= ch) && (Z >= ch)) return true; if ((a <= ch) && (z >= ch)) return true; if ((0 <= ch) && (9 >= ch)) return true; if (( == ch) || (. == ch)) return true; return false;} void print_single_word(char str[]){ int i = 0; while (valid_word_char(str[i])) cout << str[i++];} int calc_word_length(char str[]){ int i = 0; while (valid_word_char(str[i])) i++; return i;} char *increment_word(char str[]){ int i = 0; while (valid_word_char(str[i])) i++; // Pass through word while ((str[i] != ) && (!valid_word_char(str[i]))) i++; // To next word return &str[i]; // This is a pointer to the next word} int main(){ const int max = 200; char sentence[max] = The rhino is a homely beast,
For human eyes hes not a feast.
Farewell, farewell, you old rhinoceros,
Ill stare at something less prepoceros.; // (of Ogden Nash) char *words[max]; cout << sentence << endl; int w = 0; words[0] = sentence; while (words[w][0] != ) { words[w+1] = increment_word(words[w]); w++; } cout << – Total words w = << w << – << endl; for (int i = 0; i < w; i++) { print_single_word(words[i]); cout << endl; } return 0;}

If you run it, youll see what it does.

  1. To understand how it does what its doing, first look at the function print_single_word. I wrote that rather than just calling cout, can you see why? (If not, put cout in the code and see what it does.)
  2. Though the calc_word_length function isnt called, looking at it can help see how the string is being processed.
  3. It can help to draw a diagram. Mine has a series of characters for sentence and then another with a series of boxes, each as the source for an arrow, for words. If you step through a short example, youll get the gist of how those arrows get set.

Understanding arguments passed to your program

When I run most commands from the console/shell, I typically provide them with command line arguments. Those might be files to operate on, or flags to control the programs behavior, or other such things. Thus far, weve not actually been declaring our codes main function in a way that allows processing of those arguments.

We should write our main function like this (and from now on we will):

int main(int argc, char *argv[]){ }

or, equivalently:

int main(int argc, char **argv){ }

The first argument, usually called argc, tells the program how many command line arguments were passed to the program on its invocation. The second argument, argv, is an array of strings containing the arguments themselves.

Write a main which prints out the arguments passed to the program. For example, when I run my program like this:

./prog apples bananas oranges

it outputs:

Argument #0 is ./progArgument #1 is appleArgument #2 is bananasArgument #3 is oranges

Reviews

There are no reviews yet.

Only logged in customers who have purchased this product may leave a review.

Shopping Cart
[Solved] CSCE 121 Lab 9-The relationship between pointers and arrays
$25