LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Programming (http://www.linuxquestions.org/questions/programming-9/)
-   -   C++ - "snprintf" inside "for" doesn't work as expected. (int to char*) (http://www.linuxquestions.org/questions/programming-9/c-snprintf-inside-for-doesnt-work-as-expected-int-to-char%2A-829371/)

Repgahroll 08-30-2010 02:42 PM

C++ - "snprintf" inside "for" doesn't work as expected. (int to char*)
 
I need to convert an int array into a char* array.
I'm using the following code:
Code:

    for (int x = 0; x < 8; x++) {
        snprintf(buffer,32,"%d\0", x);
        y[x]=buffer;
    }

    for (int x = 0; x < 8; x++) {
        cout<<y[x]<<endl;
    }

but it returns me
Code:

7
7
7
7
7
7
7
7

and I can't fix it.
Can someone help me please?
Thanks in advance.

Sergei Steshenko 08-30-2010 03:12 PM

Quote:

Originally Posted by Repgahroll (Post 4082713)
I need to convert an int array into a char* array.
I'm using the following code:
Code:

    for (int x = 0; x < 8; x++) {
        snprintf(buffer,32,"%d\0", x);
        y[x]=buffer;
    }

    for (int x = 0; x < 8; x++) {
        cout<<y[x]<<endl;
    }

but it returns me
Code:

7
7
7
7
7
7
7
7

and I can't fix it.
Can someone help me please?
Thanks in advance.

What did you mean to do by the item in red ? How about seeing the whole code ? Did you use '-Wall -Wextra -Wformat=2 -O2' during compilation ? If yes, were there any warnings ?

jf.argentino 08-30-2010 03:31 PM

snprintf change the content of "buffer": it fill each case with the string representation of "x" (i'm assuming buffer is defined as "char buffer[32]" or equivalent).
so each round of your "for" loop, "buffer" is over written _AND_ "y[x]=buffer;" just copy the address of the "buffer" array (the position of its 1st char in memory), i'm assuming here that "y" is defined as "char* y[8]" or similar. This address doesn't change, its content does.
Then the 2nd "for" loop just display the content of the x'th address "y[x]" (="buffer" content).

REMARK: if your coding in C++, use C++ string object and methods. If you're sing pure C, use "printf" not "cout". MixingC and C++ is a bad habbit.

JohnGraham 08-30-2010 03:32 PM

Quote:

Originally Posted by Repgahroll (Post 4082713)
I'm using the following code:
Code:

    for (int x = 0; x < 8; x++) {
        snprintf(buffer,32,"%d\0", x);
        y[x]=buffer;
    }

    for (int x = 0; x < 8; x++) {
        cout<<y[x]<<endl;
    }


I think there are some fundamental flaws in the way you're using arrays. For example, "snprintf(buffer,32,"%d\0", x);" is always printing to the first element of buffer (you probably want "buffer[x]") and similarly "y[x]=buffer;" is always reading from the first element of the buffer (again, you probably want "buffer[x]") giving the (correct) printed result.

By making these two changes, your code will probably work, but if you don't understand why then you really need to read-up on arrays and pointers.

Repgahroll 08-30-2010 03:32 PM

Quote:

What did you mean to do by the item in red ? How about seeing the whole code ? Did you use '-Wall -Wextra -Wformat=2 -O2' during compilation ? If yes, were there any warnings ?
It is meant to copy the buffer value into different items of the y array (of chars).
Code:

#include <ncurses.h>
#include <menu.h>
#include <iostream>

using namespace std;

char buffer [16];
char *y[32];

int main() {

    for (int x = 0; x < 8; x++) {
        snprintf(buffer,32,"%d\0", x);
        y[x]=buffer;
    }

    for (int x = 0; x < 8; x++) {
        cout<<y[x]<<endl;
    }
}

Command: g++ -o bin main.cpp -Wall -Wextra -Wformat=2 -O2
Output:
Code:

main.cpp: In function ‘int main()’:
main.cpp:13: warning: embedded ‘\0’ in format
main.cpp:13: warning: embedded ‘\0’ in format
In file included from /usr/include/stdio.h:910,
                from /usr/include/ncurses.h:141,
                from main.cpp:1:
In function ‘int snprintf(char*, size_t, const char*, ...)’,
    inlined from ‘int main()’ at main.cpp:13:
/usr/include/bits/stdio2.h:66: warning: call to int __builtin___snprintf_chk(char*, unsigned int, int, unsigned int, const char*, ...) will always overflow destination buffer

Thank you.

Sergei Steshenko 08-30-2010 03:37 PM

Quote:

Originally Posted by Repgahroll (Post 4082760)
It is meant to copy the buffer value ...

How do you define the "buffer value" ? I.e. you describe 'buffer' as

Code:

char buffer [16];
- in "C" this means an array of 16 elements, each element type is 'char'. So, how do you define the "buffer value" in terms of the array and its elements ?

jf.argentino 08-30-2010 03:43 PM

Quote:

It is meant to copy the buffer value into different items of the y array (of chars).
So what is the "buffer" purpose?
Did you understand my 1st post?

Repgahroll 08-30-2010 03:49 PM

Quote:

Originally Posted by jf.argentino (Post 4082758)
snprintf change the content of "buffer": it fill each case with the string representation of "x" (i'm assuming buffer is defined as "char buffer[32]" or equivalent).
so each round of your "for" loop, "buffer" is over written _AND_ "y[x]=buffer;" just copy the address of the "buffer" array (the position of its 1st char in memory), i'm assuming here that "y" is defined as "char* y[8]" or similar. This address doesn't change, its content does.
Then the 2nd "for" loop just display the content of the x'th address "y[x]" (="buffer" content).

REMARK: if your coding in C++, use C++ string object and methods. If you're sing pure C, use "printf" not "cout". MixingC and C++ is a bad habbit.

So... why the last -not the first- value of x is displayed for the first y that was set when x was 0?
Quote:

Originally Posted by JohnGraham (Post 4082759)
I think there are some fundamental flaws in the way you're using arrays. For example, "snprintf(buffer,32,"%d\0", x);" is always printing to the first element of buffer (you probably want "buffer[x]") and similarly "y[x]=buffer;" is always reading from the first element of the buffer (again, you probably want "buffer[x]") giving the (correct) printed result.

By making these two changes, your code will probably work, but if you don't understand why then you really need to read-up on arrays and pointers.

I understand, however, if the buffer isn't set as array, i get segfault, even if i use something like "sprintf(y[x], "%d", x);" i get segfaults.

I just want to convert an array of integers into an array of chars so i can use it on ncurses menus (i'm learning ncurses).I though it was going to be a very simple thing.

Thanks.

Sergei Steshenko 08-30-2010 03:58 PM

Quote:

Originally Posted by Repgahroll (Post 4082779)
So... why the last -not the first- value of x is displayed for the first y that was set when x was 0?
...

'buffer' is all the time the same, and as such it holds the data it got after the last modification.

I suggest to answer my question in http://www.linuxquestions.org/questi...1/#post4082765 - it will help you to understand what you understand/do wrong.

Sergei Steshenko 08-30-2010 04:00 PM

Quote:

Originally Posted by Repgahroll (Post 4082760)
...
Command: g++ -o bin main.cpp -Wall -Wextra -Wformat=2 -O2
Output:
Code:

main.cpp: In function ‘int main()’:
main.cpp:13: warning: embedded ‘\0’ in format
main.cpp:13: warning: embedded ‘\0’ in format
In file included from /usr/include/stdio.h:910,
                from /usr/include/ncurses.h:141,
                from main.cpp:1:
In function ‘int snprintf(char*, size_t, const char*, ...)’,
    inlined from ‘int main()’ at main.cpp:13:
/usr/include/bits/stdio2.h:66: warning: call to int __builtin___snprintf_chk(char*, unsigned int, int, unsigned int, const char*, ...) will always overflow destination buffer

Thank you.

You need to make your code such it produces no warnings. The item in red is really grave.

Repgahroll 08-30-2010 04:05 PM

Okay, but even a simple code like this:
Code:

#include <iostream>
#include <stdio.h>

using namespace std;

char *y;
int x = 32;

int main() {
        sprintf(y, "%d", x);
        cout<<y<<endl;
}

is returning segfault. what's wrong with it?

jf.argentino 08-30-2010 04:07 PM

"char *y;"
You didn't allocate any space for a char array, you're allocating space for an address pointing to a (or many) char(s)

johnsfine 08-30-2010 04:21 PM

C beginners usually get confused by the lack of support in C for strings.

In C, you typically use arrays of characters instead of strings. But an array of characters is nowhere near as easy to use as a string. You need to understand all the basic concepts of arrays and pointers in C.

This is one thing that makes C++ a better beginner language. Beginners tend to write things that need strings before they learn enough to understand pointers and arrays. C++ has a string class.

Quote:

Originally Posted by Repgahroll (Post 4082760)
It is meant to copy the buffer value into different items of the y array (of chars).
Code:

char buffer [16];
char *y[32];


Because buffer is an array, its name does not refer to its contents (the array of characters). Its name refers to the address of the first character.

The y you declared is not an array of characters. It is an array of character pointers.

Code:

        y[x]=buffer;
So that doesn't copy the contents of the buffer. It copies the address of the buffer.

Since you said "C++" not "C". Maybe you don't need to learn so much about using character arrays instead of strings. Maybe you can mostly use strings.

snprintf would still need a character array for its destination. I'm not sure whether it is worth looking for a more C++ appropriate substitute for snprintf.

You mentioned your target is ncurses, which is based on a C interface. I don't know whether its C++ bindings make it support C++ well (strings etc.) or whether you still need char arrays there.

But even if you need char arrays at the start and end of the life of each string, you still might be less confused if you use strings in between.

Instead of
char *y[32];
try
std::string y[32];
(You'll need #include <string> at the top of your file)
Then when you do
y[x]=buffer;
it would really mean copy the contents of the buffer as you intend, rather than store the address.

Sergei Steshenko 08-30-2010 04:41 PM

Quote:

Originally Posted by Repgahroll (Post 4082799)
Okay, but even a simple code like this:
Code:

#include <iostream>
#include <stdio.h>

using namespace std;

char *y;
int x = 32;

int main() {
        sprintf(y, "%d", x);
        cout<<y<<endl;
}

is returning segfault. what's wrong with it?

The word "pointer" in programming originates from the verb "to point to".

The wrong thing with the program is that you haven't asked yourself the question: "Where does the 'char *y' pointer point to ?".

Had you used 'Wall -Wextra -Wformat=2 -O2' during compilation, you would have seen warnings about 'y' being uninitialized. 'y' has a random/garbage value and thus points to a random memory location, and that causes segmentation fault.

I suggest to pick any C/C++ tutorial and learn about pointers first.

Repgahroll 08-31-2010 08:27 AM

Okay guys. Learning pointers was the key.
Thank you very much! :D


All times are GMT -5. The time now is 05:08 AM.