Anything means "nothing" in c++?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <iostream>
using namespace std;

class arrayops {
public:
	template <class T>
	T foreach(T a[30000]) {
		for (int i=0;i<30000;i++) {
			T value;
			value=a[i];
			cout << value;
		}
	return 0;
	}
};

int main() {
	int a[5] = {5,2,14,23,5};
	arrayops newinstance;
	newinstance.foreach(a);
}
	


I wanted to implement some code in the condition of the "for" loop. The condition would be: i<30000,a[i]!=nothing; For example. I tried using NULL, but it didn't work. Thanks in advance.
Unless T has anything like T::is_null(), or T is a pointer, no. There's no way to do what you want. Arrays just don't work that way.
Why not just pass the length of the array as a second parameter to foreach()?
How does that compile? You are asking for an array of 30000 elements (wtf) and passing it one of 5 elements. You also are returning 0 for some reason.

Anyway, you can't do that. You will have to have the use pass a size variable with it, or use something like an std::vector (HIGHLY preferred in this case), so that you can just use .size() or iterators.
Thanks for the answers, but I have do admit it, it is a good idea on what PanGalactic said (at least for me).

@firedraco: I made an array of 30000 elements because I couldn't find out how to make an array that would fit everyones needs, so I thought that no one would ever exceed 30000 chars... Anyways, about the return 0 thing: yeeahhhh... IDK why I did that... stupid mistake... Thanks for the answers.

@Helios: If so, how could I make this T::is_null(); That's what bites me ;/
no one would ever exceed 30000 chars.
Ahahaha! Ah... The C programmer's Disease.
http://catb.org/jargon/html/C/C-Programmers-Disease.html
The largest array I've ever used that actually contained text was over four million characters long. Loading text files with more than 30k characters is very common.

This is an exercise in futility. You can't define T::is_null() for every instance of T. You should use your time for more useful things, rather than trying to circumvent linguistic "limitations". Ironic quotes because not being able to tell how long an array is is not necessarily a limitation.

Just follow PG's advice or use an std::vector. Trust me, the only solutions to what you want to do either are so complicated that you'll end up never using them, are already implemented in std::vector, or involve passing the size of the array as a parameter.
Last edited on
I've seen this trick work with arrays of primitive types passed by value...
1
2
3
4
5
6
7
8
template <class T>
void foreach(T a[])
{
   for (int i=0;i<sizeof(a)/sizeof(a[0]);i++)
   {
      /* Do something with a[i] */
   }
}


But of course std::vector is still a better option.
That doesn't work.
helios wrote:
That doesn't work.


^This. Because arrays are passed as pointers to the first element, sizeof(a) is going to be sizeof(T*) if anything.

A template solution might look like this:

1
2
3
4
5
6
7
8
template<typename T, int SIZE>
void foreach(T (&array)[SIZE])
{
	for(int i = 0; i < SIZE; ++i)
	{
		array[i] = i; // do something useful here.
	}
}


But use std::vector. It is the right thing to do.


Sorry to say this, but your code is more confused than anyone here has told you. Please don't be offended. Just listen and learn.

First off, your naming stinks.
newinstance isn't a "new instance" of anything. Specifically, it doesn't tell you anything about the variable. A better name would be something that describes the meaning of the number sequence, like monthly_rainfall_in_inches or vernam_cipher_key or weekly_bonus_points. Likewise, a is a non-name -- it doesn't tell you anything.

Second, and you don't have to worry too much about this now (you'll learn better later), but you are abusing levels of abstraction. Don't name your function foreach(). That has a very standard meaning which does not exactly match what you are trying to do. Again, be more specific. Use the standard assign() or operator=() or just name it something specific, like initialize_with_array().

Third, you are missing variable scope. Line 9 declares a local variable -- local to the for loop. Each time through the loop you create a T, assign it a value, and then destroy it. When your function terminates you create and return another T with value zero.
Essentially, there is never more than one instance of a T (not counting any copy that may exist when returning). This isn't an array, because you cannot recall what previous elements in the sequence were -- you never save any!


If you stick to a standard vector (or deque or list), your program could look like this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <iostream>
#include <vector>
using namespace std;

int main() {

  int INITIAL_PRIMES[] = {2,3,5,7,11,13,17,21,23};
  vector <int> primes(
    INITIAL_PRIMES,
    INITIAL_PRIMES + (sizeof(INITIAL_PRIMES) / sizeof(INITIAL_PRIMES[0]))
    );

  cout << "prime numbers:\n";
  for (unsigned n = 0; n < primes.size(); n++)
    cout << primes[n] << endl;

  return 0;
}

This, however, is not what I think you are trying to do.

What exactly are you trying to accomplish? Perhaps we can steer you better.
Maybe I'm thinking of a different member (I know there was someone trying to do it), but I believe kibestar is in a quest to find some method of determining the size of any array with just a pointer.
Zhuge, helios,

You are quite right, the sizeof(a) information is lost the way I had written it. As Galik pointed out, if the array size is known at compile time it is able to be deduced as a template parameter.

I have seen the sizeof trick in some code written for logging the state of a numerical calculation at each iteration.

I have found and summarised the relevant parts here, purely for entertainment purposes. The dynamic array code is obviously implementation/compiler/operating system/phase-of-the-moon specific:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
#include <iostream>

template <class T, size_t I>
size_t GetStaticArraySize(T (&array)[I])
{
//    return sizeof(array)/sizeof(array[0]);
    return I;
}

template <class T, size_t I>
void PrintStaticArray(const T (&array)[I])
{
    for (size_t i = 0; i < GetStaticArraySize(array); i++)
    {
        std::cout << array[i] << " ";
    }
    std::cout << std::endl;
}

template <class T>
size_t GetDynamicArraySize(T *array)
{
    // FRAGILE: Handle with care
    
    // For Borland allocator
    return *((size_t*)array-1)/sizeof(*array);
    // For MSVCRT allocator
//    return (((size_t)*((char*)array-8) << 3) - (size_t)*((char*)array-2))/sizeof(*array);
}

template <class T>
void PrintDynamicArray(const T *array)
{
    for (size_t i = 0; i < GetDynamicArraySize(array); i++)
    {
        std::cout << array[i] << " ";
    }
    std::cout << std::endl;
}

template <class T>
void FillDynamicArray(T *array, T val)
{
    for (size_t i = 0; i < GetDynamicArraySize(array); i++)
    {
        array[i] = val;
    }
}

int main(int argc, char* argv[])
{
    // Array sizes deducible at compile-time
    int arrstai[] = {1,2,3,4};
    std::cout << GetStaticArraySize(arrstai) << std::endl;
    PrintStaticArray(arrstai);
                                                              
    double arrstad[] = {1.0,1.5,2.0};
    std::cout << GetStaticArraySize(arrstad) << std::endl;
    PrintStaticArray(arrstad);

    // Array sizes known at run-time
    char *arrdync = new char[16];
    std::cout << GetDynamicArraySize(arrdync) << std::endl;
    FillDynamicArray(arrdync, 'A');
    PrintDynamicArray(arrdync);
    delete[] arrdync;

    int *arrdyni = new int[5];
    std::cout << GetDynamicArraySize(arrdyni) << std::endl;
    FillDynamicArray(arrdyni, 13);
    PrintDynamicArray(arrdyni);
    delete[] arrdyni;

    float *arrdynf = new float[7];
    std::cout << GetDynamicArraySize(arrdynf) << std::endl;
    FillDynamicArray(arrdynf, 3.14f);
    PrintDynamicArray(arrdynf);
    delete[] arrdynf;

    double *arrdynd = new double[3];
    std::cout << GetDynamicArraySize(arrdynd) << std::endl;
    FillDynamicArray(arrdynd, 2.71);
    PrintDynamicArray(arrdynd);
    delete[] arrdynd;

    return 0;
}
Oh, God. Please don't tell me you're reading the header written by the malloc(). That's just awful.
Maybe I'm thinking of a different member (I know there was someone trying to do it), but I believe kibestar is in a quest to find some method of determining the size of any array with just a pointer.

Couldn't you divide sizeof(array) by sizeof(*array)?
Like this:
1
2
3
size_t arraysize(const void* ptr) {
    return (size_t)(sizeof(ptr) / sizeof(*ptr));
}

Or would that not work? Would sizeof not return the size, in bytes, of ptr? Or would it just return the size of the pointer to the first element?

I guess you could set up a sighandler for SIGSEGV and just keep incrementing the pointer until you hit a segfault, kinda like this:
1
2
3
4
5
6
7
8
9
size_t sz = 0;
boolean keepGoing = True;

while (keepGoing) {
    sz++;
    ptr++;
}

return sz;

and have sigaction() pass the sighandler a pointer to keepGoing?
Or would that not work?
For the last time, no!

I guess you could set up a sighandler for SIGSEGV and just keep incrementing the pointer until you hit a segfault
Not only is that horrible, it's not even guaranteed to work because a) some malloc() implementations can use the same allocated block for more than one requested pointers, and b) an OS doesn't necessarily implement memory protection, so the code will never actually fail. That's what "undefined behavior" means. Anything can happen.
Last edited on
Couldn't you divide sizeof(array) by sizeof(*array)?


provided 'array' is an array name (read: not a pointer), yes, that works. The problem is if you have a pointer, it doesn't work because sizeof(ptr) gives you the size of a pointer.

Also:

1
2
3
size_t arraysize(const void* ptr) {
    return (size_t)(sizeof(ptr) / sizeof(*ptr));
}


This doesn't work because:
1) 'ptr' is a pointer and therefore sizeof(ptr) will give you the size of a pointer (ie: probably 4 bytes on 32bit machines)

2) *ptr isn't a valid expression because it's a void pointer, so that will give you a compiler error.



This entire topic is rather silly. I realize SCSI 73fhwgads was just doing this for entertainment purposes, but blech. I feel like I need a shower after seeing all of this.
@helios,
sorry :(

@Disch
Thanks.
Topic archived. No new replies allowed.