• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 509
  • Last Modified:

sprintf: same variable for source and target

Using C....

I have a varible containing a 7-digit phone number e.g. 5551212 that can hold up to 10 chars. My system has a default area code of 3 digits e.g. 631.  I need to prefix the phone number with the areacode, giving me a resultant string of 6315551212.

Is the following legal

sprintf(phonenum, %3.3s%7.7s, default_area_code, phonenum);

in other words having phonenum as both the source and target.

Or, doI need to use an intermediate variable e.g.

sprintf(temp_phonenum, %3.3s%7.7s, default_area_code, phonenum);
strcpy(phonenum_temp_phonenum);

Please advise.
Thanks.



0
Stephen Kairys
Asked:
Stephen Kairys
  • 7
  • 7
  • 2
  • +1
1 Solution
 
phoffricCommented:
Below is my preference to avoid any possibility about overwriting phonenum. You probably know about the extra terminating null byte so that phonenum has to be a 10+1 char array.
sprintf(temp_phonenum, "%3s%7s", default_area_code, phonenum);
strcpy(phonenum, temp_phonenum);

Open in new window

0
 
Stephen KairysTechnical Writer - ConsultantAuthor Commented:
Phoffric-
phonenum is indeed declaed as
char phonenum[11];

Gvein that, do you still have the same concern about possibly overwriting phonenum?
Thanks.


0
 
phoffricCommented:
>> do you still have the same concern about possibly overwriting phonenum?
With the temp_phonenum variable, you are definitely safe.

With your first choice, it appears to me that default_area_code gets written into the first 3 chars of phonenum, thereby clobbering phonenum. However, it will only take you a minute to verify. The temp approach is definitely cleaner looking to me.

Except for certain cases I try to avoid having the same variable used in one statement. Know good cases are statements like:  a = a+ y (or equivalently, a+= y).
0
Free tool for managing users' photos in Office 365

Easily upload multiple users’ photos to Office 365. Manage them with an intuitive GUI and use handy built-in cropping and resizing options. Link photos with users based on Azure AD attributes. Free tool!

 
phoffricCommented:
On a side topic, I don't think you need the precision .3 in the sprintf format, but if you think a string could have a leading 0, you should have "%03s%07s".
0
 
Stephen KairysTechnical Writer - ConsultantAuthor Commented:
Just to be safe, I prefer using %3.3s and %7.7s. That way there is no risk of string overflow.
I want to accept your solution with the %3s%7s but would feel more comfortable if the 3.3 and 7.7 were used. Wouild you be willing to repost that solution with my ammendment to it? Then, I can close out this question andwe can both move on to other things. :)

Thanks
0
 
phoffricCommented:
Well, OK, but overflows? Hopefully your area code and your 7 digit phone numbers could never have overflows, and if they ever could, I would hope that you would have a way to identify this before going into the sprintf call. So, before the sprintf, you should have assertions about the length of the two variables to protect against hiding extra digits in the numbers. Since the precision does prevent buffer overflow, I can see why you want to keep the precision in the format.

// add assertions to verify that the area code and phonenum strings
//   have the correct string lengths
sprintf(temp_phonenum, "%03.3s%07.7s", default_area_code, phonenum);
strcpy(phonenum, temp_phonenum);

Open in new window

0
 
Stephen KairysTechnical Writer - ConsultantAuthor Commented:
Better, but my data never would have leading zeroes. (And when I tried %03.3s, it did not display with a leading zero for the value "12"; rather, it displayed "<blank>12".  I'm guesing that the leading 0 does notg work for strings, so maybe we should take it out and just go with 3.3s and 7.7s. Thanks.
0
 
Infinity08Commented:
Just to be absolutely clear :

>> sprintf(phonenum, "%3.3s%7.7s", default_area_code, phonenum);

has undefined behavior, and will very likely not do what you intended, due to the way the sprintf function commonly works internally.
Don't do this :)

What you can do instead, is this :
memmove(phonenum + 3, phonenum, 8);
strncpy(phonenum, default_area_code, 3);

/* or alternatively (without using a temporary buffer) : */
int i = 0;
for (i = 7; i >= 0; --i) {
  phonenum[i + 3] = phonenum[i];
}
strncpy(phonenum, default_area_code, 3);

Open in new window

0
 
phoffricCommented:
OK,
Here's the output if I intentionally try to overflow. So, you are protected.

1231234567

   char temp_phonenum[11];
   char default_area_code[] = "1234";
   char phonenum[] = "123456789";
   sprintf(temp_phonenum, "%3.3s%7.7s", default_area_code, phonenum);
   strcpy(phonenum, temp_phonenum);
   printf(phonenum);

Open in new window

0
 
phoffricCommented:
Make that:
   char temp_phonenum[11];
   char default_area_code[11] = "1234";
   char phonenum[11] = "123456789";
   sprintf(temp_phonenum, "%3.3s%7.7s", default_area_code, phonenum);
   strcpy(phonenum, temp_phonenum);
   printf(phonenum);

Open in new window

0
 
itsmeandnobodyelseCommented:
If you made sure that the lengths of the input strings are ok, you could do

  if (strlen(phonenum) <= 7 && strlen(default_area_code) == 3)
  {
      memmove(&phonenum[3], phonenum, 8);
      memcpy(phonenum,  default_area_code, 3);
  }

Note, with memmove you can copy within one buffer while with memcpy the buffers may not overlap.
0
 
Stephen KairysTechnical Writer - ConsultantAuthor Commented:
Phoffric - this looks good; I was surprised that you did not include a format specifier for the final printf, but it seems to work....I never knew that you could get away w/o havinga format specifier. What's the deal with that? Thanks.
0
 
phoffricCommented:
>> I never knew that you could get away w/o having a format specifier. What's the deal with that?
No magic. The format specifier is a required field. It is defined to be a string with option translation tokens beginning with % that correspond to optional parameters to be embedded in the output stream, right?

printf("Hello World\n");
The format specifier is "Hello World\n".

char hiThere[ ]  = "Hello World\n";
printf( hiThere );

No difference. Either way the string format specifier is provided. This means that you can dynamically create format specifiers, if need be.
0
 
Stephen KairysTechnical Writer - ConsultantAuthor Commented:
OK, phoffric. I am going to accept your solution, while noting that printf(phonenum(; will not include a new line (\n).

itsmeandnobodyelse: and Infinity08 - thanks for the input, but as you guys came in after phoffric, and I don't have time to try out your soln's,, I'm going with phoffric. Thanks for your efforts to help,though.

0
 
Infinity08Commented:
>> itsmeandnobodyelse: and Infinity08 - thanks for the input, but as you guys came in after phoffric, and I don't have time to try out your soln's,, I'm going with phoffric. Thanks for your efforts to help,though.

No worries. The only reason I posted, was to make it clear beyond doubt that the code from the question has undefined behavior, and should thus not be used.
In case you were interested in a solution without a temporary buffer, I also included alternative approaches.
0
 
Stephen KairysTechnical Writer - ConsultantAuthor Commented:
Thanks, Infinity08. I apprecaite it.
0
 
itsmeandnobodyelseCommented:
No worries from my side either.

The sprintf is a valid (and commonly used) solution. My code using memmove and memcpy only should make clear that the operations made by sprintf would not allow to use the same buffer for input and output and that the only way to achieve that is to manipulate the phonenum buffer yourself.
0
 
Stephen KairysTechnical Writer - ConsultantAuthor Commented:
OK - thanks for the input.
0

Featured Post

SMB Security Just Got a Layer Stronger

WatchGuard acquires Percipient Networks to extend protection to the DNS layer, further increasing the value of Total Security Suite.  Learn more about what this means for you and how you can improve your security with WatchGuard today!

  • 7
  • 7
  • 2
  • +1
Tackle projects and never again get stuck behind a technical roadblock.
Join Now