• C

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.



LVL 4
Stephen KairysTechnical Writer - ConsultantAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

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
Powerful Yet Easy-to-Use Network Monitoring

Identify excessive bandwidth utilization or unexpected application traffic with SolarWinds Bandwidth Analyzer Pack.

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

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
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
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
C

From novice to tech pro — start learning today.