Sign in to follow this  
senelebe

UBound checks - C++

Recommended Posts

testMethod(const double array[])
{
	int x = 0;
	for(int i = 0; i < 4; i++)
	{
		if (array[i] > 0)
			x++;
	}
        
        //.... rest of code using x as ubound for array[]
}





While this isn't exactly what I'm doing I think it expresses my intent. I've got a situation where an array could have 1 to 4 unsigned doubles in it, instead of having to manually pass the ubound to the intended function, I use the for statement to check the array for positive numbers. The problem is that it's erratic, sometimes it returns the correct ubound of the array, sometimes it doesn't...after debugging it seems that sometimes the memory being accessed outside the array is positive hence throwing my if array[i] > 0 check into a false positive. Is there a good way to check dynamic bounds? Any thoughts are appreciated as always. [Edited by - senelebe on April 17, 2006 10:40:34 AM]

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
Use a vector :)


#include <vector>

void testMethod(const std::vector<double> &array)
{
for(int i = 0; i < array.size(); i++)
{
//...
}

//.... array.size() is ubound
}



A const double array[] is basically a pointer and as such, contains no information about the size of the memory it points to.

A vector on the other hand is basically a pointer and an upper bound tied together.

See this page for more information
http://www.sgi.com/tech/stl/Vector.html

Share this post


Link to post
Share on other sites
Unless you happen to be in the same function that created the array, it's impossible to get the size of said array. You're just referring to random points in memory that might be positive or negative after your allocated segment.

Use a vector instead, raw arrays are evil.

Share this post


Link to post
Share on other sites
Gotcha, I'm just now getting the feel for strings over const chars, I suspect it's time to get the feel for vectors as well.

I didn't want to cut my array learning short, but from the sounds of it there is little use for them... would that be an accurate statement?

When is an array not an array? When you're in C++ and it's a vector! lol, Coming from higher level languages to C++ has been a learning experience to say the least.

I appreciate the help greatly and I'll dive into vectors, I kind of thought that would be the solution, but I hate just skipping over arrays.

Share this post


Link to post
Share on other sites
I believe the answer is no. My c++ book here says an array passed to a function decays into a pointer, which means you lose all type information of the array. So you can't know inside a function what size the array was.
Besides passing the size anyway, boost::array may be an option. (I haven't used it myself, but I assume it's good.)

edit1: I need to learn how to type faster!
edit2: yes vectors rule, arrays suck.

Share this post


Link to post
Share on other sites
The vector did a fine job, had to play around with it for awhile but it seems to be working quite well now. There's still a ton to learn about vectors, one thing I was curious about that I didn't see, is there a way to instantiate vectors like you do arrays...

string teams[5] = {"Astros", "Braves", "Mets", "Cubs", "Cardinals"};
vector<string> teams(5) = <~~~ throws an error about right side =

Anyways, this was the finished product of the method using the vector. I realize alot of those for/if's should probably be private methods. The main reason I needed the dynamic index was because of a default ctor that collected data (via cin) then passed to this ctor, some Sales objects will be passed with all 4 quarters of sales complete (past), whereas current sales figures will be of variable quarter length.

Thanks again for the suggestions, I'll probably spend the majority of tommorow working through vectors, At this point it's probably a greater priority then continuing my oop practice.



//Static ctor
Sales::Sales(string name, const vector<double> &sales)
{
//get the dynamic ubound of sales
int iUbound = sales.size();

m_name = name;

//set our internal array field m_sales
for(int iter = 0; iter < iUbound; iter++)
{
m_sales[iter] = sales[iter];
}

//set our internal double field m_max
m_max = m_sales[0];
for(int iter = 1; iter < iUbound; iter++)
{
if (m_max < m_sales[iter])
{
m_max = m_sales[iter];
}
}

//set our internal double field m_min
m_min = m_sales[0];
for(int iter = 1; iter < iUbound; iter++)
{
if(m_min > m_sales[iter])
{
m_min = m_sales[iter];
}
}

//set our internal double field m_totalSales
m_totalSales = m_sales[0];
for(int iter = 1; iter < iUbound; iter++)
{
m_totalSales += m_sales[iter];
}

//only calculate double average from quarters (iUbound) passed
m_average = m_totalSales / iUbound;

//set projected sales for year if quarters (iUbound) not 4
//internal field saved regardless, show method filters.
m_projectedSales = m_average * 4;

//Fill our m_sales array with 0.00 for unfinished quarters.
for(int iter = 0; iter < (4 - iUbound); iter++)
{
int y = iUbound + iter;
m_sales[y] = 0.00;
}
}


Share this post


Link to post
Share on other sites
Short answer: No.

You can of course make a function to populate it, or if you need a repetition of values you could use this constructor: vector(size_type count, const Ty& val);, which creates count repetitions of val

If you pass a single number to the constructor it tells it to create a vector of that size, which saves you time in allocation if you're expecting to populate it with that many elements. Less resizes and all.

Share this post


Link to post
Share on other sites
Time for some clean-up :) I'll let the code speak for itself, to the best of its ability... if you don't understand something, just ask :)


#include <algorithm>
#include <iterator>

// I will assume m_sales is also a vector<double>.
// The strategy will be to copy across the elements, then later pad it to a
// length that is a multiple of 4. Except we don't need to copy elements: we
// can copy-construct the member itself, because vectors know how to do that :)

//Static ctor
Sales::Sales(string name, const vector<double> &sales) :
m_name(name),
m_sales(sales),
m_max(*max_element(sales.begin(), sales.end())),
m_min(*min_element(sales.begin(), sales.end())),
m_totalSales(accumulate(sales.begin(), sales.end(), 0.0)),
m_average(m_totalSales / sales.size()),
m_projectedSales(m_average * 4) {

// Fill our m_sales array with 0.00 for unfinished quarters.
// This also allows for the 'sales' to cover more than one year.
int remainingQuarters = 4 - (m_sales.size() % 4);
if (remainingQuarters != 4) {
for (int i = 0; i < remainingQuarters; ++i) {
m_sales.push_back(0.0);
}
}
}

Share this post


Link to post
Share on other sites
Quote:

Time for some clean-up :)


Wow, that is pretty slick. Private methods my ass... lol.

#include <algorithm>
#include <iterator>

I'm assuming the iterator header is used in conjunction with vector to get it to do some of the fancier sorting *max_element, *min_element;

What are you using in the algorithm header though?


also this line...

int remainingQuarters = 4 - (m_sales.size() % 4);

I'd assume (m_sale.size() % 4) would return 0 on a full vector(4 quarters) [giving us the statment 4 - (4 % 4)] since we're checking for != 4 below, I'm curious as to why the modulus instead of just 4 - m_salesize();


[Edited by - senelebe on April 17, 2006 8:15:28 AM]

Share this post


Link to post
Share on other sites
Alright, first off sorry for double post, not a self-loving bump.

m_average(m_totalSales / sales.size()),

Is returning erroneous results. I cannot put a break on the line, but m_totalSales is correct, and breaking after shows that sales.size() is correct...

It's returning huge negative doubles, that look like :

-23222922849289000000000000000000000000000000000000000000000000000000000.00

while that might not be the exact return it's similiar. As a side note it's also throwing off the m_projectedSales, but that's expected.

Share this post


Link to post
Share on other sites
Quote:

I'm assuming the iterator header is used in conjunction with vector to get it to do some of the fancier sorting *max_element, *min_element;

What are you using in the algorithm header though?


"iterator" provides the type names for the vector iterators. Actually I don't think it's needed here, but it probably would be if you wanted to assign sales.begin() or sales.end() to variables (which would then be of type std::vector<double>::iterator).

"algorithm" provides the max_element, min_element and accumulate functions. No actual sorting takes place (unless you meant that in the informal sense of "figuring out") :) Basically, they are "generic" code that replace the loops you were writing by hand. It keeps things a lot shorter because you end up not having to worry about the types of variables (the compiler will basically generate code for you from a template, according to the types of what you put in), and because it collapses a fragment of code into a single expression - which then allows for using the initializer list.

Quote:

int remainingQuarters = 4 - (m_sales.size() % 4);

I'd assume (m_sale.size() % 4) would return 0 on a full vector(4 quarters) [giving us the statment 4 - (4 % 4)] since we're checking for != 4 below, I'm curious as to why the modulus instead of just 4 - m_salesize();


To allow for multiple-year results. For example, 7 quarters of input will yield 4 - (7 % 4) = 4 - 3 = 1 for 'remainingQuarters', and the internal vector gets padded to a length of 8.

Since 0.0 is the 'default' value for doubles, you should also be able to get the same effect by resize()ing the vector rather than making the push_back calls. But then, since you can push_back later when you actually have the other data, maybe you don't really need to do anything in the constructor at all

Quote:

m_average(m_totalSales / sales.size()),

Is returning erroneous results. I cannot put a break on the line, but m_totalSales is correct, and breaking after shows that sales.size() is correct...

It's returning huge negative doubles


Class members are IIRC initialized in the order that they're declared in the class, not the order listed in the initializer list. So if you've got m_average declared first in the data members, then m_totalSales is some garbage value at that point (depending on your compiler, it might be zeroed out in debug mode but left garbage in release). Your compiler should give you a warning about a mismatch.

Share this post


Link to post
Share on other sites
Quote:
Original post by Zahlman
Your compiler should give you a warning about a mismatch.


I don't know how different IDE's handle it, but this surely is very handy. Turn on -enable all compiler warnings, -pedantic or whatever compiler option in your IDE complains the most without being too annoying (about libraries you include for example). It saved my ass many times, and what's better, you'll get into the habit of coding more safely.
(At least code::blocks doesn't enable any warnings by default, you have to enable them)

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this