tags:

views:

730

answers:

8

I don't get why I get 0 when I use printf and %d to get the size of my vector:

vector<long long> sieve;
int size;
...
//add stuff to vector
...
size = sieve.size();
printf("printf sieve size: %d \n", size); //prints "printf sieve size: 0"
std::cout << "cout sieve size: ";
std::cout << size;
std::cout << " \n ";
//prints "cout sieve size: 5 (or whatever the correct sieve size is)"

If I iterate through the vector via

if(i=0;i<sieve.size();i++)

I get the correct number of iterations.

What am I doing wrong or what is up with printf? size() returns an int right??


Here's my entire little script:

#include <iostream>
#include <vector>
#include <stack>
#include <math.h>

int main (int argc, char * const argv[]) {
    unsigned long long answer = 0;
    unsigned long long cur = 2;
    std::vector<long long> sieve;
    unsigned long long limit;
    unsigned long long value;
    unsigned int i;
    int size;
    bool isPrime;
    std::cout << "Provide a value to find its largest prime factor: ";
    std::cin >> value;
    limit = ceil(sqrt(value));
    sieve.push_back(2);
    while(cur++ < limit){
      isPrime = true;
      sieve.begin();
      for(i=0; i<sieve.size();i++){
        if(!(cur % sieve[i])){
          isPrime = false;
          break;
        }
      }
      if(isPrime){  
        if(!(value % cur)){
          std::printf("Is prime factor: %d\n", cur);
          sieve.push_back(cur);
          answer = sieve[sieve.size() - 1];
          size = sieve.size();
          std::printf("current last: %d sieve size: %ld\n", answer, size);
          for(i=0; i<sieve.size();i++){
            std::printf("sieve iter: %d sieve val: %d\n", i, sieve[i]);
            std::cout << size;
            std::cout << " wtf\n";
          }
        }
      }
    }
    answer = sieve[sieve.size() - 1];
    size = sieve.size();
    std::printf("Limit: %d Answer: %d sieve size: %ld\n", limit, answer, size);
    return 0;
}
+1  A: 

vector sizes are size_t, which I believe is usually a long...

Couldn't say why printf isn't working, though.

dmckee
Isn't size_t usually unsigned?
Mitch Wheat
That is what I think... in his snippet, he declares size as int, that should be Ok with printf("%d"); but if he is calling sieve.size() inside printf() directly that would be incompatible with "%d".
Juliano
Yeah. Bother right. I didn't really read his code...
dmckee
+1  A: 

What's the hardware you're running on? Odds are that size is a different type than you think. Print sizeof(size) and check, or try a %ld. If you have a big-endian machine like a PPC, size is a long, and you print a %d, you get the all-zeros end of the long.

update

Okay, this is what I get with an Intel Mac mini, 10.5:

$ cat trySize.C 
#include <iostream>
#include <vector>

int main(){
    std::cout << "sizeof(size_t): " 
        << sizeof(size_t) 
        << std::endl ;
    std::vector<long long> sieve ;
    std::cout << "sizeof(sieve.size()): " 
        << sizeof(sieve.size()) 
        << std::endl;
    printf("sizeof(sieve.size()) (printf): %d\n", sizeof(sieve.size()));
    return 0;
}
$ g++ trySize.C
$ ./a.out
sizeof(size_t): 4
sizeof(sieve.size()): 4
sizeof(sieve.size()) (printf): 4
$

You probably should start breaking the code up into smaller pieces and trying them; there's something hinky here.

Charlie Martin
I think the code says "int size" than "%d" corresponds to int. So I can't see how the size issue matters. The same int prints correctly with cout<<!
antti.huima
I added my entire script source, I'm running on an intel macbook pro
apphacker
+1  A: 

The size() method returns size_t, which depends on your c++ implementation. When you try to printf("%d"), you're telling the library to expect an int, which isn't necessarily the case; it then takes an int from the call stack, which is taking only the high-order bytes of the size_t.

What you'll need to do is force the return value size() to a known data type with casting: printf("%d", (int) size)

lacqui
casting didn't work either
apphacker
+2  A: 

Looks crazy. Because size is declared as "int size", printf("...%d") is definitely correct. It can't be about size_t being different than "int" in size, because you explicitly declare "size" as int, and cout << ... size ... works correctly.

Have you checked that you have included ? It might be that without proper declaration on your system printf works "wrong".

antti.huima
Without the right include, you'd expect it to compile but not link. Still, I had the same thought...
dmckee
I think this is what's happening. He's not including cstdio, so I'm betting you're right and printf is pushing things on the stack wrong.
tgamblin
including cstdio doesn't work either, I added my source code
apphacker
I'm compiling with xcode 3.1.2 on an intel macbook pro running leopard
apphacker
What do you input when the program runs to get the error?
tgamblin
I'm using the number 13195
apphacker
Ok see my answer below. You're just using the wrong format strings.
tgamblin
yes that is correct, thanks.
apphacker
+2  A: 

Your problem is that answer is defined as a long long and you only printf it with a %d.

printf is a varargs function and in C that means the compiler doesn't know what arguments you passed into the function. It cannot do its normal type conversions and it has to trust its user to get the format arguments right, or the arguments will not be pulled off the call stack properly.

You didn't get it right.

Zan Lynx
+5  A: 

Now, with the complete source, it is clear.

You declared:

int size;

Then you used:

std::printf("current last: %d sieve size: %ld\n", answer, size);
std::printf("Limit: %d Answer: %d sieve size: %ld\n", limit, answer, size);

If size is int, you should use "%d", not "%ld". A good compiler would have warned you about this. GCC gives these warnings for your original version:

test.cpp: In function ‘int main(int, char* const*)’:
test.cpp:17: warning: converting to ‘long long unsigned int’ from ‘double’
test.cpp:30: warning: format ‘%d’ expects type ‘int’, but argument 2 has type ‘long long unsigned int’
test.cpp:34: warning: format ‘%d’ expects type ‘int’, but argument 2 has type ‘long long unsigned int’
test.cpp:34: warning: format ‘%ld’ expects type ‘long int’, but argument 3 has type ‘int’
test.cpp:36: warning: format ‘%d’ expects type ‘int’, but argument 3 has type ‘long long int’
test.cpp:45: warning: format ‘%d’ expects type ‘int’, but argument 2 has type ‘long long unsigned int’
test.cpp:45: warning: format ‘%d’ expects type ‘int’, but argument 3 has type ‘long long unsigned int’
test.cpp:45: warning: format ‘%ld’ expects type ‘long int’, but argument 4 has type ‘int’

This tells a lot.

You should declare size as:

std::vector<long long>::size_type size;

Then you should use it as:

std::printf("current last: %llu sieve size: %llu\n", (unsigned long long) answer, (unsigned long long) size);
std::printf("Limit: %llu Answer: %llu sieve size: %llu\n", (unsigned long long) limit, (unsigned long long) answer, (unsigned long long) size);

Of course, using iostream avoids you these problems, specially the ugly casting in printf() to transform size to a type known to printf.

Juliano
hrm, actually I had %d at first, when I copied my code it was after I tried following the advice from answers here. Using the std::vector<long long>::size_type size; declaration and %llu only ended up with nonsensical numbers like 21474836480
apphacker
The other arguments were messing the stack. Added proper conversions to all arguments. Now it should work as expected (I tested). There are other printf()s that you should review. Remember that printf() doesn't do type conversion, you should do it explicitly.
Juliano
Aha. Awesome, thanks!
apphacker
Hrm, I'm not getting any of the warnings, I must change settings somewhere I guess
apphacker
You are welcome! To enable warnings, pass -Wall to the compiler, it is ALWAYS a good idea.
Juliano
+5  A: 

This is screwing up because you've got:

unsigned long long answer = 0;
int size;

and you call printf with:

std::printf("current last: %d sieve size: %ld\n", answer, size);

Both of your format strings are wrong:

  1. You're passing answer to printf and formatting it %d, but it should be %lld, since it's declared unsigned long long.

  2. You're passing size with %d instead of %ld. Since size is and int, it should be %d.

When those args get passed to printf, it's printing the first 32 bits of answer for the first %d and the second 32 bits (or more, past the end!) of answer for the %ld. This is not what you want.

If you compile with -Wall your compiler should warn you about this kind of thing. Pay very close attention to the warnings!

tgamblin
A: 

This will work:

std::printf("current last: %**lld** sieve size: %ld\n", answer, size);

The problem is that answer is a long long (a 64 bit integer) and %d expects a 32bit integer. So size doesn't get printed. You will need to use %lld.

For more information on format strings for printf check out: http://en.wikipedia.org/wiki/Printf

m-sharp