Форум » C/C++ для начинающих (C/C++ for beginners) » (for Vlad from SO) » Ответить

(for Vlad from SO)

ScottyScott: Hi Vlad, The code is this: int main(void) { // initializing rainfall data for 2010 - 2014 const float rain[YEARS][MONTHS] = { { 4.3, 4.3, 4.3, 3.0, 2.0, 1.2, 0.2, 0.2, 0.4, 2.4, 3.5, 6.6 }, { 8.5, 8.2, 1.2, 1.6, 2.4, 0.0, 5.2, 0.9, 0.3, 0.9, 1.4, 7.3 }, { 9.1, 8.5, 6.7, 4.3, 2.1, 0.8, 0.2, 0.2, 1.1, 2.3, 6.1, 8.4 }, { 7.2, 9.9, 8.4, 3.3, 1.2, 0.8, 0.4, 0.0, 0.6, 1.7, 4.3, 6.2 }, { 7.6, 5.6, 3.8, 2.8, 3.8, 0.2, 0.0, 0.0, 0.0, 1.3, 2.6, 5.2 } }; int year, month; float subtot, total; printf(" YEAR RAINFALL (inches)\n"); for (year = 0, total = 0; year < YEARS; year++) { // for each year, sum rainfall for each month for (month = 0, subtot = 0; month < MONTHS; month++) { subtot += rain[year][month]; } printf("%5d %15.1f\n", 2010 + year, subtot); total += subtot; // tot al for all years } As an exercise the book asks the reader to change the above code so it uses pointers instead of subscripts. My attempt was to do the [....] float (* rainPointer)[2] rainPointer = rain; [....] for (year = 0, total = 0; year < YEARS; year++) { // for each year, sum rainfall for each month for (month = 0, subtot = 0; month < MONTHS; month++) { subtot += *(*(rainPointer + year) + month); } } [....] This would give the correct value for year 0, but year 1 (and subsequent) wouldn't. This confused me because the debugger was showing that rainPointer[year][month] held the correct values but it wasn't reading the correct float from the array. The book states the following: [quote] [...] Hence,pz must point to an array of two ints, not to a single int. Here is what you can do: int (* pz)[2]; // pz points to an array of 2 ints[/quote] In my case I changed pz to rainPointer. I learned that rainPointer is useless as I can just use rain. But if rainPointer points to rain, surely the following should be the same: const float rain[YEARS][MONTHS] = [....] float (* rainPointer)[2] rainPointer = rain; // the same? subtot += rain[year][month]; subtot += *(*(rain + year) + month); subtot += *(*(rainPointer + year) + month); the first one works, the second one works, the third one doesn't. I hope this is not too confusing.

Ответов - 12

ScottyScott: argh, I was meant to amend that topic title. sorry!

Сыроежка: It is not clear why you use a pointer declared like [pre2] float (* rainPointer)[2]; [/pre2] and assign it by rain while the element of the array has type [pre2] float [MONTHS] [/pre2] If you want to get equivalent results you have to use a pointer declared like [pre2] float (* rainPointer)[MONTHS]; [/pre2] Here is a demonstrative program. Also I appended it with a code block that shows the difference between these two pointer declarations. That is elements they point to have different sizes. [pre2] #include <stdio.h> #define YEARS 5 #define MONTHS 12 int main(void) { // initializing rainfall data for 2010 - 2014 const float rain[YEARS][MONTHS] = { { 4.3, 4.3, 4.3, 3.0, 2.0, 1.2, 0.2, 0.2, 0.4, 2.4, 3.5, 6.6 }, { 8.5, 8.2, 1.2, 1.6, 2.4, 0.0, 5.2, 0.9, 0.3, 0.9, 1.4, 7.3 }, { 9.1, 8.5, 6.7, 4.3, 2.1, 0.8, 0.2, 0.2, 1.1, 2.3, 6.1, 8.4 }, { 7.2, 9.9, 8.4, 3.3, 1.2, 0.8, 0.4, 0.0, 0.6, 1.7, 4.3, 6.2 }, { 7.6, 5.6, 3.8, 2.8, 3.8, 0.2, 0.0, 0.0, 0.0, 1.3, 2.6, 5.2 } }; const float ( * rainPointer )[MONTHS]; int year = 0; float total = 0.0f; printf(" YEAR RAINFALL (inches)\n"); for ( ; year < YEARS; year++ ) { // for each year, sum rainfall for each month float subtot = 0.0f; int month = 0; for ( ; month < MONTHS; month++ ) { subtot += rain[year][month]; } printf( "%5d %15.1f\n", 2010 + year, subtot ); total += subtot; // tot al for all years } printf( "\n" ); rainPointer = rain; for ( ; rainPointer != rain + YEARS; rainPointer++ ) { // for each year, sum rainfall for each month float subtot = 0.0f; const float *monthPointer = *rainPointer; for ( ; monthPointer != *rainPointer + MONTHS; monthPointer++ ) { subtot += *monthPointer; } printf( "%5d %15.1f\n", 2010 + year, subtot ); total += subtot; // tot al for all years } printf( "\n" ); { float (* rainPointer)[MONTHS]; float (* rainPointer2)[2]; printf( "sizeof( *rainPointer ) = %zu\n", sizeof( *rainPointer ) ); printf( "sizeof( *rainPointer2 ) = %zu\n", sizeof( *rainPointer2 ) ); } return 0; } [/pre2] The program output is [pre2] YEAR RAINFALL (inches) 2010 32.4 2011 37.9 2012 49.8 2013 44.0 2014 32.9 2015 32.4 2015 37.9 2015 49.8 2015 44.0 2015 32.9 sizeof( *rainPointer ) = 48 sizeof( *rainPointer2 ) = 8 [/pre2]

ScottyScott: thanks. I was misreading the book. It's still a little confusing but I certainly understand what I was doing wrong and how you fix it. a massive help!


Сыроежка: If to declare the pointer like [pre2] float (* rainPointer)[2] = rain; [/pre2] then the compiler should issue a diagnostic message like error: initialization from incompatible pointer type

ScottyScott: I hate to be a pain but could you point me in the right direction with this one? Write a program that initializes an array-of-double and then copies the contents of the array into three other arrays. (All four arrays should be declared in the main program.) To make the first copy, use a function with array notation. To make the second copy, use a function with pointer notation and pointer incrementing. Have the first two functions take as arguments the name of the target array, the name of the source array, and the number of elements to be copied. Have the third function take as arguments the name of the target, the name of the source, and a pointer to the element following the last element of the source. That is, the function calls would look like this, given the following declarations: double source[5] = {1.1, 2.2, 3.3, 4.4, 5.5}; double target1[5]; double target2[5]; double target3[5]; copy_arr(target1, source, 5); copy_ptr(target2, source, 5); copy_ptrs(target3, source, source + 5); I've done the first two, I cannot for the life of me, figure out how copy_ptrs is meant to work with source + 5. I thought maybe I have to do it backwards?

Сыроежка: The function can be written the following way [pre2] double * copy_ptrs( double *target, const double *first, const double *last ) { for ( ; first != last; ++first ) *target++ = *first; return target; } [/pre2] Or [pre2] double * copy_ptrs( double *target, const double *first, const double *last ) { for ( ; first != last; ++first, ++target ) *target = *first; return target; } [/pre2] Or one more equivalent implementation using while loop [pre2] double * copy_ptrs( double *target, const double *first, const double *last ) { while ( first != last ) *target++ = *first++; return target; } [/pre2] For all these three loops the compiler can generate the same object code.:) The same way except the parameter order there is defined standard template algorithm std::copy in C++. It looks the following way [pre2] template <typename InputIterator, typename OutputIterator> OutputIterator copy( InputIterator first, InputIterator last, OutputIterator result ) { for ( ; first != last; ++first, ++result ) *result = *first; return result; } [/pre2]

ScottyScott: okay, I'm kicking myself right now. I had the same idea in my head, my logic was just wrong and I couldn't get it out. I should've taken a break. you've been a major help!

Сыроежка: Here is a demonstrative program of using the function [pre2] #include <stdio.h> double * copy_ptrs( double *target, const double *first, const double *last ) { for ( ; first != last; ++first, ++target ) *target = *first; return target; } #define N 5 int main(void) { double a[N] = { 1.1, 2.2, 3.3, 4.4, 5.5 }; double b[N] = { 5.5, 4.4, 3.3, 2.2, 1.1 }; double c[2 * N]; int i; printf( "A: " ); for ( i = 0; i < N; i++ ) printf( "%1.1lf ", a ); printf( "\n" ); printf( "B: " ); for ( i = 0; i < N; i++ ) printf( "%1.1lf ", b ); printf( "\n" ); copy_ptrs( copy_ptrs( c, a, a + N ), b, b + N ); printf( "C: " ); for ( i = 0; i < 2 * N; i++ ) printf( "%1.1lf ", c ); printf( "\n" ); return 0; } [/pre2] The program output is [pre2] A: 1.1 2.2 3.3 4.4 5.5 B: 5.5 4.4 3.3 2.2 1.1 C: 1.1 2.2 3.3 4.4 5.5 5.5 4.4 3.3 2.2 1.1 [/pre2]

ScottyScott: Trying to understand your first example, stepping through the code with the debugger I notice it's going backwards when putting things into target I tried adding comments to help myself follow the logic here: void copy_ptrs(double *target, double *source, double *lastElement) { // go to source get what's there // go to lastElement get what's there // if they're not the same continue // (increment source) for (; *source != *lastElement; ++source) { // get whatever is at source // increase target location and get whatever is at target // assign whatever is at source to target // (increment source + repeat until source and lastElement are equal) *target++ = *source; } } how does target[4] end up being the first element to be filled? or am I reading my debugging window incorrectly?

Сыроежка: ScottyScott пишет: how does target[4] end up being the first element to be filled? I do not understand what you mean. The function sequantially fills elements pointed to by pointer target. For example after assigning the first element pointed to by target target is increased and so on.

ScottyScott: I understand, but when I step through with a debugger, target seems to pointing to the back? http://i.imgur.com/RfG97Wa.png so, target + 4 gets filled first, then moved down and target + 3 and so on. I thought target would be filled first, followed by target + 1 and etc. the debug window linked above shows what I mean. again, you're being super cool with this. thanks man.

Сыроежка: It looks strange. You should look through the generated assembler code.



полная версия страницы