tags:

views:

2807

answers:

7

Hi guys. I have to use a dynamic length int array in my program, and want to be able to get the number of objects in it at various points in my code. I am not that familiar with C++, but here is what I have. Why is it not giving me the right length? Thanks.

<#include <iostream>
Using Namespace std;
int length(int*);


void main()
{
  int temp[0];
  temp[0] = 7;
  temp [1] = 10;
  temp[2] = '\0';

  cout << length(temp) << endl;
}

int length(int* temp)
{
    int i = 0;
    int count = 0;

    while (*temp + i != '\0')
    {
          count++;
          i++;
    }
    return count;
}

currently it just goes into an endless loop ;_;

+4  A: 

You could try:

while (*(temp + i) != '\0')

Your current solution is calculating temp[0] + i (equals 7+i), which apparently is not what you want.

Pukku
+13  A: 

In C++ arrays are not dynamic. Your temp array has zero length, and attempting to write to members beyond its length is undefined behaviour. It's most likely not working as it will be writing over some part of the stack.

Either create a fixed size array with enough space to put everything you want to in it, or use a std::vector<int> which is a dynamic data structure.

#include <iostream>
#include <vector>
using namespace std;
int length(int*);


int main ()  //  error: ‘::main’ must return ‘int’
{
    int temp[3];
    temp[0] = 7;
    temp[1] = 10;
    // don't use char constants for int values without reason
    temp[2] = 0; 

    cout << length(temp) << endl;

    vector<int> vec_temp;

    vec_temp.push_back(7);
    vec_temp.push_back(10);

    cout << vec_temp.size() << endl;

}

int length(int* temp)
{
    int i = 0;
    int count = 0;

    while (*(temp + i) != 0) // *temp + i == (*temp) + i
    {
          count++;
          i++; // don't really need both i and count
    }
    return count;
}

For the vector, there's no need to specify the size at the start, and you can put a zero in, and finding the length is a simple operation rather than requiring a loop.

Another bug inside your loop was that you were looking at the first member of the array and adding i to that value, rather than incrementing the pointer by i. You don't really need both i and count, so could write that a couple of other ways, either incrementing temp directly:

int length(int* temp)
{
    int count = 0;

    while (*temp != 0)
    {
          ++count;
          ++temp;
    }

    return count;
}

or using count to index temp:

int length(int* temp)
{
    int count = 0;

    while (temp[count] != 0)
          ++count;

    return count;
}
Pete Kirkham
A: 

To get dynamic behavior in arrays, use a std::vector, or fall back on the old school c style using int * with manual memory allocation (new and delete)[*]

[*] C implementations (discussed in the context of character arrays as http://stackoverflow.com/questions/671593/c-dynamic-string-length) used malloc, realloc, and free, but these should be avoided in c++ code.

dmckee
anon
@Neil: Good point. I was thinking of c. But if he's doing it c++ style, there is rarely a case for choosing the int * approach over std::vector...
dmckee
+4  A: 

This approach is a bad idea for a couple of reasons, but first here's some problems:

int temp[0];

This is an array of 0 items, which I don't even think is permitted for stack elements. When declaring an array like this you must specify the maximum number of values you will ever use: E.g. int temp[10];

This is super important! - if you do specify a number less (e.g. [10] and you use [11]) then you will cause a memory overwrite which at best crashes and at worst causes strange bugs that are a nightmare to track down.

The next problem is this line:

while (*temp + i != '\0')

That this line does is take the value stores in the address specified by 'temp' and add i. What you want is to get the value at nth element of the address specified by temp, like so:

while (*(temp + i) != '\0')

So that's what's wrong, but you should take five minutes to think about a better way to do this.

The reasons I mentioned it's a bad idea are:

  • You need to iterate over the entire array anytime you require its length
  • You can never store the terminating element (in this case 0) in the array

Instead I would suggest you maintain a separate value that stores the number of elements in the array. A very common way of doing this is to create a class that wraps this concept (a block of elements and the current size).

The C++ standard library comes with a template class named "vector" which can be used for this purpose. It's not quite the same as an array (you must add items first before indexing) but it's very similar. It also provides support for copying/resizing which is handy too.

Here's your program written to use std::vector. Instead of the 'length' function I've added something to print out the values:

#include <vector>
#include <iostream>

void print(std::vector<int> const& vec)
{
    using namespace std;

    for (size_t i = 0; i < vec.size(); i++)
    {
     cout << vec[i] << " ";
    }

    cout << endl;
}

int main()
{
    std::vector<int> temp;
    temp.push_back(7);
    temp.push_back(10);

    print(temp);

    return 0;
}
Andrew Grant
`int temp[0]` is permitted. It simply requires that a valid address exists for the array, not that it actually points to anything.
greyfade
+3  A: 

Not only C++ arrays are not dynamic as Pete points out, but only strings (char *) terminate with '\0'. (This is not to say that you can't use a similar convention for other types, but it's rather unusual, and for good reasons: in particular, relying on a terminator symbol requires you to loop through an array to find its size!)

In cases like yours it's better to use the standard library.

#include <vector>
#include <iostream>

int main()
{    
    std::vector<int> v;
    v.push_back(7);
    v.push_back(10);
    std::cout << v.size() << std::endl;
    return 0;
}
UncleZeiv
Why couldn't you decide on a convention to use '\0' as a sentinel for other data types? (even if it's not a commonly used one)
Pukku
(and even though assigning '\0' to an int is misleading... but it anyway ends up being 0 and if you know that valid data never contains a zero, then this approach should work, even though it still isn't the best way to do it)
Pukku
@Pukku: I never said that you can't decide on such a convention. For strings is not only a convention enforced by libraries: for instance a string literal will automatically include a '\0' in the end. That's not true for array int literals for instance.
UncleZeiv
There is no append member function on vector. I think you meant "push_back".
Brian Neal
@Brian: thanks... too much Python coding ;)
UncleZeiv
A: 

Because you only allocate space for an array of zero elements. The following lines

  temp [1] = 10;
  temp[2] = '\0';

do not allocate more memory or resize the array. You are simply writing data outside the array, corrupting some other part of the application state. Don't do that. ;)

If you want a resizable array, you can use std::vector (and use the push_back member function to insert new values)

A vector also has the size() member function which tells you the current size.

If you want to use the primitive array, you have to track the size yourself. (and, when resizing the array is necessary, copy all elements from the old array to the new, larger one)

jalf
A: 

The most common way to get the size of a fixed-length array is something like this:

int temp[256];
int len = sizeof (temp) / sizeof (temp[0]);
// len == 256 * 4 / 4 == 256 on many platforms.

This doesn't work for dynamic arrays because they're actually pointers.

int* temp = new int[256];
int len = sizeof (temp) / sizeof (temp[0]);
// len == 4 / 4 == 1 on many platforms.

For a dynamic-length array if you care about the size, you're best off storing it somewhere when you allocate the array.

The problem with your loop, as pointed out by many is that you have an operator precedence problem here:

  *temp + i

should be:

  *(temp + i)

But the bigger problem, also pointed out above, is that you don't appear to understand pointers versus fixed-length arrays and are writing off the end of your array.

Dan Olson