# Char array joining

## Recommended Posts

Hi, i cant find or remember how to join to char arrays, eg char first[] = "john"; char last[] = "smith"; char name[] = first + last; is it done like that? i'm programming a pic microcontroller so C++ string are out of the question.

##### Share on other sites
Quote:
 Original post by JasonL220char first[] = "john";char last[] = "smith";char name[] = first + last;is it done like that?

No, not even close... where did you come up with that? does that even compile on your compiler?

Quote:
 i'm programming a pic microcontroller so C++ string are out of the question.

...why? have you tried using them? what is the trouble? and what standard library implementation / compiler are you using?

##### Share on other sites
strcat() will append one string to another, but be careful you have enough space in the destination buffer.

##### Share on other sites
Quote:
 Original post by rip-offstrcat() will append one string to another, but be careful you have enough space in the destination buffer.

How about strncat? I guess buffer exploits aren't much of an issue on a PIC microcontroller, but it could help you avoid stack corruption and there's no harm in forming good habits.

##### Share on other sites
What kind of program could you be writing for a PIC that requires you to concatenate strings, anyway?

##### Share on other sites
strncat( name, first, sizeof(name)-1 );strncat( name, last, sizeof(name)-1 );

Thats if you have a strncat function. If not, then strcat, which is dangerous.

strcat( name, first );strcat( name, last );

If not, then you have to define it yourself.
char * strcat( char * to, const char * from ){  char * mid = to;  while (*mid) mid++;  while (*from) *(mid++)=*(from++);  return to;}

##### Share on other sites
Quote:
 Original post by Inmate2993strncat( name, first, sizeof(name)-1 );strncat( name, last, sizeof(name)-1 );

The correct version would need to create a correctly sized string buffer to store the entire concatenated strings, use strncpy for the first (unless you set the first character to nul) and add the nul terminator at the end in case you didn't manage to get the length right.:

int len = strlen(first) + strlen(last);char *name = malloc(len + 1);strncpy(name, first, len);strncat(name, last, len);name[len] = '\0';

##### Share on other sites
This little function I knocked up the other day will do the trick ...

Despite it being potentially unsafe, I'm quite pleased with the linear cost when compared to 'strcpy' then 'strcat' and find it quite useful when assembling filenames, etc.

char* strcpycat( char* dest, const char* src1, const char* src2 ){  while ( *src1 ) *dest++ = *src1++;  while ( *src2 ) *dest++ = *src2++;  *dest = NULL;  return dest;}

-----

char first[] = "john";
char last[] = "smith";

char name[ 100 ];
strcpycat( name, first, last );

>> 'name' is now: 'johnsmith\0'

----

NOTE, obviously you'll need to ensure that the 'dest' buffer is large enough (and that both source strings are null terminated, which they are in your example)

Hope this helps.

##### Share on other sites
Quote:
 *dest = NULL;

What the? I think someone is mixing up NULL (the invalid pointer) and NUL (the terminator character). The literal you're looking for is '\0'.

Your suggestion of avoiding unnecessary traversal stands (even though an strcpy + strcat approach is still linear, and you still have to do those strlen anyway). If I were to handle it as a clean function, I'd probably write:

char *concat(char *a, char *b){  int la, lb;  char *dest;   assert (a);  assert (b);  la = strlen(a);  lb = strlen(b);  dest = malloc(la + lb + 1);  strncpy(dest,a,la);  strncat(dest+a,b,lb);  dest[la+lb] = '\0';  return dest;}

This is, I believe, the safest you can get in C. In the end, I'd rather spend time getting std::string to work, than rewriting it myself in C...

##### Share on other sites
'\0' and NULL are identical here

##### Share on other sites
Quote:
 Original post by honnyjopper'\0' and NULL are identical here

No, NULL is only guaranteed to work as a pointer constant. In fact, some compilers even define NULL as ((void*)0), which is incompatible with the above usage.

##### Share on other sites
Quote:
 What the? I think someone is mixing up NULL (the invalid pointer) and NUL (the terminator character). The literal you're looking for is '\0'.
Well, I've never seen a compiler that's as pedantic as to complain about this... plus Visual Assist lights up the NULL macro in purple so I'll stick with my pretty code thank you.

I also think it reads better, people say 'null terminated string' right? *dest = 0 seems to imply some kind of intent here, like you want to set the character to zero not just wrap up the end of the string.

Quote:
 Your suggestion of avoiding unnecessary traversal stands (even though an strcpy + strcat approach is still linear, and you still have to do those strlen anyway). If I were to handle it as a clean function, I'd probably write:This is, I believe, the safest you can get in C. In the end, I'd rather spend time getting std::string to work, than rewriting it myself in C...

But this is for a PIC, I can't imagine that you'd care so much about safety that you'd sacrifice all that time doing strlen and malloc ... maybe some kind of stack alloc function would be a compromise?

I agree though that my strcypcat function isn't perfect, but it's got a cryptic name and does the job in a cheap and cheerful manner - which means it fits in pretty well along side the other C standard library functions :-)

##### Share on other sites
Quote:
 Original post by Hidden AsbestosWell, I've never seen a compiler that's as pedantic as to complain about this... plus Visual Assist lights up the NULL macro in purple so I'll stick with my pretty code thank you.I also think it reads better, people say 'null terminated string' right? *dest = 0 seems to imply some kind of intent here, like you want to set the character to zero not just wrap up the end of the string.

1° "I've never seen [X] which does [Y]" is an award-winning "famous last words" quote. Chances are, you will someday, when working on a strange architecture with a strange compiler, encounter this oddity.
2° These boards are not powered by Visual Assist. At least on my computer, your NULL is in a flashy black font on a white background. Or did you pull this function straight out of one of your projects?
3° In C, 'null' means a lot of things. NULL means one of these things, and null-terminated means another. The two are not interchangeable. A null pointer is yet another thing, and a null string is still another, and so on. Hence my question: since you use a 'null pointer constant' as a 'null terminator', why not use a 'null string' as a 'null pointer constant'? #define NULL "" ...
4° It does not read better. Any experienced C or C++ programmer will spend at least 10 seconds wondering why your array of characters has suddenly become an array of pointers, and only then realize that you're (against the C standard) using NULL as the NUL string terminator. And then, spend a few more seconds weeping (I sure did).
*dest ='\0'; cannot be interpreted as anything other than "null-terminate the string". Besides, it's a character literal, so it's also lit up by visual assist. It's also the same length as "null". Aside from anticonformist originality, I fail to see how NULL would have any advantage over the idiomatic, time-tested version.

Quote:
 But this is for a PIC, I can't imagine that you'd care so much about safety that you'd sacrifice all that time doing strlen and malloc ... maybe some kind of stack alloc function would be a compromise?

*Snicker* Sacrifice? My, what a big nasty word. If concatenating strings is so essential to the performance of a program that one or two strlen and malloc will cause such immense problems, then the original poster would be better off looking for better solutions than a generic concatenation function. My first reflex would be to get std::string going, which would save the strlen and malloc times for good (it stores its length and can have custom allocators and COW) far better than a handcrafted solution. Also look into PHP's ob_start, which is quite nifty if you handle it wel, whenever you need multiple concatenations.

In the end though, the main question is: how high is the performance/productivity ratio of string manipulation in your program? In short, why do you want to spend 10 hours increasing performance by 0.01% in a seldom-executed part of your program? The fundamental rule when optimizing a program is simple : write clean and safe code first, then profile, and optimize code where it will have the most effect.

Consider this slightly exaggerated parable: Ann spends 10 hours building a clean, safe and unoptimized string-manipulation program in C, then 30 hours profiling and optimizing the relevant parts. Ben, on the other hand ,spends 30 hours building a carefully hand-optimized C-string manipulation system, and 10 hours getting it to work because of the bugs introduced by higher intellectual complexity.

Assume that both Ann and Ben optimize at the same speed (which can be doubted, since Ben would have to write his code at the same time). We'll assume that every hour Ann and Bob spend on a line of code increases that line's performance by 100% of its initial performance.

Ann optimized the 20% of code that is run 80% of the time. That's 30 hours times 100% per line, so the performance gain is 0.8 * 3000 + 0.2 * 100 = 2420%.

Ben optimized 100% of the code. That's 30 hours times 100% per line, but Ben worked on five times as many lines as Ann, so where Ann spent 30 hours, Ben only spent only 6. So, the performance gain is only 600%. To get the same effect as Ann, Ben would have to work four times as much, or 120 hours of optimization.

##### Share on other sites
You can only program pics in c.

Well with the offical Complier anyway.

##### Share on other sites
Quote:
 Original post by Anonymous PosterYou can only program pics in c.Well with the offical Complier anyway.

WTF are you talking about? What official compiler and what PICs? I could use my own custom language to program PICs if I wanted to. Since most languages are turing-complete; assuming they have access to the same low-level facilities, you should be able to convert any piece of language code into C or the PIC's machine code.

##### Share on other sites
Most PIC microcontrollers have about 3.5k of Program Memory, and 128 bytes(yes bytes) of ram, with Clock of 20Mhz.

They have a speicial type of ASM language with about 20 Commands, and thats it.

Running c++ would be stupid.

I should know i study electronics.

You usually program them with official MPLAB ide and program adapter, in assembly and then pay extra for the c18 offical complier.

They don't have a c++ complier.

Unless you would like to write one?

##### Share on other sites
What i'm trying to say is ASM, and C are the only languages officially supported.

##### Share on other sites
Quote:
Original post by ToohrVyk
Quote:
 Original post by Inmate2993strncat( name, first, sizeof(name)-1 );strncat( name, last, sizeof(name)-1 );
...
int len = strlen(first) + strlen(last);char *name = malloc(len + 1);strncpy(name, first, len);strncat(name, last, len);name[len] = '\0';

Both of those are using strncat wrongly: the third parameter is the maximum number of characters to copy from the source - it's not the maximum length of the destination. It doesn't matter in ToohrVyk's code since the buffer is guaranteed to be long enough (and in that case strcpy/strcat would work just as well, and there's no need to set the last character to 0 anyway because strncat guarantees that); but in general, strncat doesn't do what any sane person would want it to do.

VC2005's strcat_s does do the sane thing (taking the size of the destination buffer as an argument), so it seems quite sensible to write your own version of that.

##### Share on other sites
Quote:
 Original post by ExcorsVC2005's strcat_s does do the sane thing (taking the size of the destination buffer as an argument), so it seems quite sensible to write your own version of that.

You're right, I was thinking of strcat_s as well. Serves me right for not using C string manipulation often enough. Although, now that I look at it, it seems that strncat doesn't null-terminate the output if it overflows.

##### Share on other sites
Quote:
 Original post by ToohrVykit seems that strncat doesn't null-terminate the output if it overflows.

They say "The strncat() function appends up to n characters from string s2 to string s1, and then appends a terminating null character" and "A terminating null byte is always appended to the result".

But, oddly, the online MSDN says "strncat only adds a trailing NULL if there is room left in the buffer, strDest" but that's totally impossible because it has no idea how much space is left in the buffer. The offline documentation from VS2005 says "The all cases [sic], the resulting string is terminated with a null character", which agrees with everybody else and with VS2005's CRT source code (since it does an unconditional *front = '\0'; at the end of strncat). So MSDN seems surprisingly wrong.

Edit: Oh, that's the Windows CE 5.0 version. At least one of the many other pages documenting the same function says the right thing.

Quote:
 Serves me right for not using C string manipulation often enough.
I think "never" is the optimum frequency at which to use C string manipulation [smile]

##### Share on other sites
Quote:
 Original post by Anonymous PosterMost PIC microcontrollers have about 3.5k of Program Memory, and 128 bytes(yes bytes) of ram, with Clock of 20Mhz.They have a speicial type of ASM language with about 20 Commands, and thats it.They don't have a c++ complier.

None of that prevents you from emulating the std::string type in C (although you still have to "call constructors and destructors" manually, you will get better code organization and a much saner way of handling string data, and safeguard to at least some extent against incorrect memory management).

Or, for that matter, using Cfront.

## Create an account

Register a new account

• ### Forum Statistics

• Total Topics
628312
• Total Posts
2981999

• 9
• 9
• 13
• 11
• 13