Pages: [1]   Go Down
Author Topic: Problems with snprintf  (Read 830 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Newbie
*
Karma: 1
Posts: 46
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi, I'm trying to create a clock class that uses an rtc.

The rtc provides me the time date etc as a series of integers.

I have a method in my clock class called getTime(char theTimeAsACharArray[])

I would like this method to formulate the integers into an array of chars and return it to the caller.

I know I can't return a char array from a function per say, I have to pass it the array by reference, so that's what I'm trying to do.

This is ok except within my array I'm trying to use snprintf to formulate the char array.

This does not work. If I directly manipulate the char array(don't use snprintf), ie

theTimeAsACharArray[0] = '0';
theTimeAsACharArray[1] = '9'; etc it works fine.

This is my code for the function :
Code:
void getTime(char theTimeAsACharArray[])
{
     Time t;
     t = rtc.time();
     snprintf(theTimeAsACharArray, sizeof(theTimeAsACharArray), "%02d-%02d-%04d%02d:%02d:%02d",
           t.date, t.mon, t.yr, t.hr, t.min, t.sec);
}

//which I call like so :

char buf[20];
getTime(buf);
But buf is alway empty?

snprintf seems to do the job until it goes out of scope, I have played around with this till the cows come home, read up on pointers and apassing by ref ect but can't seem to nail it, I think it has something to do with me misunderstanding how snprintf works.

Please could someone help me smiley
Logged

Global Moderator
Dallas
Offline Offline
Shannon Member
*****
Karma: 200
Posts: 12782
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset


This will give you a hint...

Code:
void getTime(char theTimeAsACharArray[])
{
  Serial.println( sizeof(theTimeAsACharArray) );

/****** put this back after the test
     Time t;
     t = rtc.time();
     snprintf(theTimeAsACharArray, sizeof(theTimeAsACharArray), "%02d-%02d-%04d%02d:%02d:%02d",
           t.date, t.mon, t.yr, t.hr, t.min, t.sec);
******/
}
Logged

Offline Offline
Newbie
*
Karma: 1
Posts: 46
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hmm, it tells me that the size of the array is 2 with snprintf code commented out, and the same when I un-comment it.

I'm going to investigate further in order to try and 'get the hint', I'm having a blonde moment smiley-wink
Logged

Global Moderator
Dallas
Offline Offline
Shannon Member
*****
Karma: 200
Posts: 12782
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset


I hate to see a blonde suffer.  Maybe this will help...

Code:
void getTime(char * theTimeAsACharArray)
{
  Serial.println( sizeof(theTimeAsACharArray) );

/****** put this back after the test
     Time t;
     t = rtc.time();
     snprintf(theTimeAsACharArray, sizeof(theTimeAsACharArray), "%02d-%02d-%04d%02d:%02d:%02d",
           t.date, t.mon, t.yr, t.hr, t.min, t.sec);
******/
}
Logged

Offline Offline
Newbie
*
Karma: 1
Posts: 46
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Ok, so I get what's wrong now, the sizeof in the snprintf is not returning the size of the array.

Now I need to understand why, so here goes:

The use of the parameter

char theTimeAsACharArray[]

is exactly the same as

char * theTimeAsACharArray

In that c will treat both as a pointer onto the passed in array, it's just that one notation explicitly tells us it's a pointer we are passing.

So, it's my understanding that the sizeof function is only telling us the size of the pointer, not the size of the array.

If this is the case then I guess I need to add another parameter telling the function what size the array is.

Am I close?
Logged

New Jersey
Online Online
Faraday Member
**
Karma: 65
Posts: 3643
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
So, it's my understanding that the sizeof function is only telling us the size of the pointer, not the size of the array.

If this is the case then I guess I need to add another parameter telling the function what size the array is.

Am I close?
Right on target.
Logged

Offline Offline
Faraday Member
**
Karma: 61
Posts: 2895
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I have never seen a function like
Code:
getTime(  char  arrayName[] )
{
    // code
}


Not saying it's wrong,  but i've never seen it done that way.
Usually you would declare a sufficiently large array in the calling function,   and
pass a pointer to that array for the getTime() function to use.

Code:

void getTime( char* array )
{
    // code
}


char  bigEnoughArray[50] ;

getTime( bigEnoughArray );           //  this is the call to the function


where bigEnoughArray  in the function invocation is a pointer to char   and could also be written as

getTime ( &bigEnoughArray[0] ) ;

which makes it clear that the actual parameter is the address of the first element of the array.
Logged

Offline Offline
Faraday Member
**
Karma: 61
Posts: 2895
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

The way C stores array,   I don't thing the sizeof operator will be of any use to you at all.

If you want to use snprintf(),  you could

(i)  determine what value to use for the second parameter of snprintf() by actually adding up how many characters
your format string is going to put into it.

(ii)  pass the size of the array as an additional parameter to getTime()

(iii)  #define a value to represent the size of the array,   and then use that value to declare the array  and also as the
second parameter of the snprintf() call.
Logged

UK
Offline Offline
Shannon Member
****
Karma: 223
Posts: 12579
-
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

When you deal with the array itself (i.e. by its symbolic name) the compiler knows how big it is. However, your function's signature doesn't specify how big the array is (and couldn't ever specify that) so within the function, all you know about the argument is that it is an array of unknown size. In 'C' terms this is equivalent to a pointer; your code would produce exactly the same behaviour if you declared it like this:
Code:
void getTime(  char  *arrayName )

You need to change your API so that the caller specifies the buffer to receive the output via separate char* and length arguments. For example:

Code:
void getTime(  char  *time, int length )
Logged

I only provide help via the forum - please do not contact me for private consultancy.

Offline Offline
Newbie
*
Karma: 1
Posts: 46
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Wow, thanks for all the comments smiley

I now have a better understanding of an issue I have bumped into several times over the week since I started c and arduino, that of returning objects from functions.

I knew those pesky pointers were the answer but it's been a slow painful slog trying to get my head around them, all this referencing, de-referencing and the like!

I think, with the help given to me on this forum and a book by king on c, I have at last solidified my understanding of how this is done.

I come from c# where objects are thrown around without really considering the memory management aspects to what's going on so once again, thank you so much for your help guys smiley
Logged

Pages: [1]   Go Up
Jump to: