简体   繁体   中英

Allocating a fixed character array vs. a pointer for casting to string

I'm new to C, and trying to understand why the following works with a fixed-size character array but not with a pointer:

float number = 1245.12;

// allocate a character array for the buffer
char number_as_string[50];
sprintf(number_as_string, "%f", number);

But allocating a pointer (which I thought would point to a location in memory, and allow iterating to the next memory point, etc.) would not work:

float number = 1245.12;

// allocate a pointer
char * number_as_string;
sprintf(number_as_string, "%f", number);

I'm going to answer your question in two parts.

You wrote

float number = 1245.12;
char number_as_string[50];
sprintf(number_as_string, "%f", number);

That's fine and will work, although of course one problem with fixed-size buffers like these is that it's easy to overflow them, sometimes with catastrophic results. So a preferred alternative is

snprintf(number_as_string, sizeof(number_as_string), "%f", number);

snprintf is a variant of sprintf that lets you specify the size of the buffer. That way, snprintf can take care not to write more characters to the buffer than it will hold.

So now let's see about using snprintf with your second example:

char *number_as_string;
snprintf(number_as_string, ???, "%f", number);

But what size do we use? How big is the buffer pointed to by this second number_as_string ? We don't know, and this helps us realize that we haven't yet allocated a buffer for the second number_as_string to point to at all.

What you want to do is use malloc to allocate some memory for number_as_string to point to:

number_as_string = malloc(50);

Now, and assuming malloc succeeds, you know what number to hand to snprintf as the buffer size:

snprintf(number_as_string, 50, "%f", number);

Realistically, of course, we'd have a variable holding the allocated buffer size, rather than repeating the number "50" in multiple places. So here's the more realistic example, including the test to make sure malloc didn't fail:

int buffer_size = 50;
char *number_as_string = malloc(buffer_size);
if(number_as_string == NULL) {
    fprintf(stderr, "out of memory\n");
    exit(1);
}
snprintf(number_as_string, buffer_size, "%f", number);

Just make sure you don't do:

snprintf(number_as_string, sizeof(number_as_string), "%f", number);

when number_as_string is a pointer. In that case, you'll get the size of the pointer (typically 4 or 8 bytes, these days), not the size of the pointed-to buffer, which is what you want.

I like to understand memory allocation, and pointers, with little box-and-arrow diagrams. Here's char number_as_string[50] :

                  +--+--+--+--+--+--+--+--+--+--+--+--+--+   +--+--+
number_as_string: |  |  |  |  |  |  |  |  |  |  |  |  |  |...|  |  |
                  +--+--+--+--+--+--+--+--+--+--+--+--+--+   +--+--+

Here's char *number_as_string followed by a successful number_as_string = malloc(50) :

                  +-------+
number_as_string: |   *   |
                  +---|---+
                      |
                      v
                     +--+--+--+--+--+--+--+--+--+--+--+--+--+   +--+--+
                     |  |  |  |  |  |  |  |  |  |  |  |  |  |...|  |  |
                     +--+--+--+--+--+--+--+--+--+--+--+--+--+   +--+--+

But here's char *number_as_string all by itself:

                  +-------+
number_as_string: |   *--------> ???
                  +-------+

The arrow -- the pointer -- points "nowhere".

A pointer variable needs something to point to, and in your second example number_as_string doesn't point to anything. Attempting to dereference it via a call to sprintf invokes undefined behavior .

You need to either allocate space dynamically:

char * number_as_string = malloc(50);

Or make it point someplace valid:

char str[50];
char * number_as_string = str;

In the first case

char number_as_string[50];
sprintf(number_as_string, "%f", 123.456);

you have an automatic-storage variable that is an array of 50 char s. This array is usualy on the stack, so when you call sprintf() , you are "printing" on valid memory.

In the second case

char * number_as_string;
sprintf(number_as_string, "%f", 123.456);

you also have an automatic variable. However this variable is only a pointer. You did not ask the compiler for an array. Furthermore, you didn't initialize the pointer, so you cannot even tell whether sprintf() will even receive a memory location that belongs to your program.

This is what you are looking for:

char * number_as_string = malloc(50);
sprintf(number_as_string, "%f", 123.456);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM