0

I'm trying to take in a simple command line argument in a C++ program to trigger different program behavior - when you include a "y" (or any string starting with y - I don't really care) the program displays some intermeadiate results.
When I run with

ccal pix.txt

everything works fine.

When I use

ccal pix.txt yes

It runs OK, shows my pix and crashes at the very end.

Also,

ccal pix.txt no

runs everything OK without showing pix (like it should), and still crashes at the very end.

Here's the relevant code - what am I doing wrong?

void dumpFloatMatrix(Mat m){
for(int i = 0; i < m.cols; i++){
    for(int j = 0; j < m.rows; j++){
        char *buff = new char[10];
        sprintf(buff, "%5.1f ", m.at<float>(i,j));
        cout << buff;
        delete buff;
    }
    cout << endl;
}
 }
int main(int argc, char *argv[]){
char* outFile;
bool showPix = false;

// Take in command line args
switch(argc){
case 3:
    if(strncmp(argv[2], "y", 1) == 0)
        showPix = true;
    outFile = argv[1];
    break;
case 2:
    outFile = argv[1];
    break;
default:
    cout << "Usage: ccal INPUT_LIST_FILE" << endl;
    return -1;
}
Mat cameraMatrix(3, 3, CV_32FC1);
dumpFloatMatrix(cameraMatrix);
return 0;
}

The weird thing is that even when I switch the test in case 3 to something like this:

        if(argv[2][0] == 'y')

I still get the same behavior. I can't for the life of me figure out why.

fatman
  • 65
  • 6
  • 6
    The problem is probably elsewhere in your code; please construct a [minimal test-case](http://sscce.org). – Oliver Charlesworth Jan 12 '13 at 20:20
  • So far, nothing that looks buggy. We probably need more code. –  Jan 12 '13 at 20:21
  • 3
    You could use a debugger to find out where the crash really is. – Some programmer dude Jan 12 '13 at 20:22
  • 2
    At the very end of *what*. There is nothing after the switch, and no write operations presented that could cause corruption. You wanna show the code that *uses* these data values?? The lack of a closing brace for `main()` suggests your problem is *after* this. – WhozCraig Jan 12 '13 at 20:22
  • fatman, follow the direction @WhozCraig is pointing you in. I.e., we need to see the code that comes after the switch. – DWright Jan 12 '13 at 20:28
  • 1
    @Griwes: I'd love to not deal with char* - how do I bring in a command line argument with a string? – fatman Jan 12 '13 at 20:28
  • The actual arguments to the `main` function can't be changed, however all strings you fetch from the `argv` array (like `outFile` in this case) could be `std::string` instances. – Some programmer dude Jan 12 '13 at 20:31
  • 1
    is that really everything? i can't see how you use the `outFile` and `showPix` variables – Andy Prowl Jan 12 '13 at 20:40
  • `std::vector args; for (int i = 0; i < argc; ++i) args.emplace_back(argv[i]);` – Griwes Jan 12 '13 at 20:47
  • @DWright: this is the minimal test-case that reproduces the error, per Oli Charlesworth 's comment. The rest is a whole lot of almost certainly irrelevant OpenCV code. – fatman Jan 12 '13 at 20:53
  • @ Griwes - i don't have C11 support, can I use push_back() instead? – fatman Jan 12 '13 at 20:54
  • Also, this: `case 3:{ string answer = argv[2]; if(answer == "y") showPix = true; outFile = argv[1]; break; }` doesn't work either – fatman Jan 12 '13 at 20:55

2 Answers2

1

The fixed-size buffer is a warning sign to me.

As a troubleshooting step, change

sprintf(buff, "%5.1f ", m.at<float>(i,j));

to

int const used = sprintf(buff, "%5.1f ", m.at<float>(i,j));
assert(used < 10);

Besides that, using dynamic allocation there is plain ridiculous. If a fixed-size buffer is enough, just use a local automatic array variable. While you're at it, stack space is cheap, so head off overflows by making the buffer plenty big.

void dumpFloatMatrix( Mat m )
{
    char buff[400];
    for(int i = 0; i < m.cols; i++){
        for(int j = 0; j < m.rows; j++){
            int const used = sprintf(buff, "%5.1f ", m.at<float>(i,j));
            assert(used * sizeof *buff < sizeof buff);
            cout << buff;
        }
        cout << endl;
    }
}
Ben Voigt
  • 277,958
  • 43
  • 419
  • 720
1

Sorry, but this is pure lunacy:

for(int j = 0; j < m.rows; j++){
    char *buff = new char[10];
    sprintf(buff, "%5.1f ", m.at<float>(i,j));
    cout << buff;
    delete buff;
}

Calling new/delete for a 10 byte array will cost 16-32 bytes of memory plus the ten bytes you wanted [probably rounded to 16, 32 or 64 bytes]. And the call to new and delete respectively. Yes, I'm sure cout << buff will take a lot more cycles, but those are in some way necessary.

Either use:

for(int j = 0; j < m.rows; j++){
    char buff[10];
    sprintf(buff, "%5.1f ", m.at<float>(i,j));
    cout << buff;
}

Or use C++ style formatting:

for(int j = 0; j < m.rows; j++){
    cout << precision(1) << setw(5) << m.at<float>(i,j);
}

If the array is very large, you may prefer to move these out of the loop:

cout.precision(1); 
cout.setw(5);

I prefer the last method - as it won't overflow if your calculation got 1210121281.9 as the result [your layout will look a bit funny].

Mats Petersson
  • 126,704
  • 14
  • 140
  • 227
  • Unfortunately the last method is really slow and not really suitable to put in a nested loop (where it gets called many many times). Here it looks like the matrix isn't very big, so it shouldn't be a problem. – Ben Voigt Jan 12 '13 at 21:03
  • Also balance your parentheses. – Ben Voigt Jan 12 '13 at 21:03
  • Slow compared to printing thousands of floating point numbers? – Mats Petersson Jan 12 '13 at 21:09
  • Your first suggestion fixes it - thank you. The matrix is tiny (3X3), so I'm not worried about memory size or speed even a little bit, but why was it crashing? Also, I can't compile the second suggestion - it can't find the precision or setw functions. And the suggestion above from @Grimes fixes it independently. `std::vector args; for (int i = 0; i < argc; ++i) args.push_back(argv[i]);` I'd love to know why. – fatman Jan 12 '13 at 21:13
  • I'm pretty sure my first "fix" fixes nothing - it probably just doesn't crash any longer because you are overwriting something on your own stack, rather than writing beyond the end of an allocated pointer. I would suggest that you go for a solution where you don't rely on fixed size buffer simply to print a number. Use the functions provided in C++ to print floating point numbers. – Mats Petersson Jan 12 '13 at 21:19
  • @Mats: Yes, `cout` formatting operations are very slow compared to file writes, under every standard library I've seen. http://stackoverflow.com/q/4340396/103167 – Ben Voigt Jan 12 '13 at 21:22
  • Yes, I'm sure that `cout` isn't ideal, but then you wouldn't want to print a really huge array anyways... :) – Mats Petersson Jan 12 '13 at 21:29
  • Tried to switch to answer 2 `ostream has no member named setw`? Also now i get scientific notation on large/small numbers – fatman Jan 12 '13 at 21:32
  • You may need to `#include ` and use `cout << fixed ` to avoid scientific notation. – Mats Petersson Jan 12 '13 at 21:39