Improve company productivity with a Business Account.Sign Up

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 298
  • Last Modified:

String Handling in "C"

Hello

# include<stdio.h>
# include<string.h>

int main (void)
{
     char str[9] = "hello";
     char str1[]=  "world";
     
     strcat(str, str1);
     printf("%s", str);
}

I expected the above program to give "Application Error"
since str can hold only 9 characters, but we try to
have 10 chars (helloworld) after doing strcat. But to
my surprise the program ran successfully without any error. I used Microsoft visual c++  on win NT to test
this. Can you explain why it didn't give error?


b)Is it possible to use strcat for a variable that is
declared as char *x="test" using pointers (or)
is strcat always used with array of characters declared using [] rather than character pointer.


Thanks
Sridhar
0
puji
Asked:
puji
  • 6
  • 6
  • 4
  • +3
1 Solution
 
newmangCommented:
Sridhar

This behaviour is one of the downsides of the freedoms provided by C. There is no concept of length checking so when you did your strcat the data in str1 would have been copied into the memory area allocated to str and would have written past the end of the area allocated into str, in the process overwriting whatever happened to be there.

The printf worked because a string is an array of characters terminated by a null (0x00). You were lucky in this case because there was obviously nothing of consequence in the memory area following str but if there had been significant information there then you r program may have crashed or exhibited odd behaviour.

This is a frequent cause of strange behaviour in programs as a strcat at one place in the application may over-write a variable used somewhere else in the program. It is also a classic cause of program cracking and is very dangerous.

You really should use the strncat() function where you define both the source string, the destination string and the number of characters to copy - strncat(source, dest, sizeof(dest)-1) to avoid this problem.

The answer to b) is yes. In fact when you typed strcat(str, str1) you were passing to the strcat function the address of str and the address of str1 which is what iy would do if you used explicit pointers. So the following are valid.

char str[10]="xxxx";
char str1[10]="yyyy"
strncat(str,str1,9);

char str[10]="xxxx";
char str1[10]="yyyy"
strncat(&str[0], &str1[0],9);

char * pstr;
char * pstr1;
pstr=(char *)malloc(10);
pstr=(char *)malloc(10);
strcpy(pstr,"xxxx");
strcpy(pstr1,"yyyy");
strncpy(pstr,pstr1,9);
.
.
free(pstr);
free(pstr1);

I hope this helps - Gavin Newman
0
 
nebekerCommented:
One of the reasons it worked is because when you allocated the 9 characters for the 'str[9]', you really got more than 9 characters :)

Behind the scenes, the memory manager that handles malloc and the list of free pages generally trys to return memory on even 4 byte (or multiples of 4 byte) boundaries.

For example, consider this simple program:
---------------------------------------------------------

#include <stdio.h>

int main( void )
{
    char *p1 = (char *) malloc( 1 );
    char *p2 = (char *) malloc( 1 );

    printf( "p1 = %p, p2 = %p\n", p1, p2 );
    return 0;
}
---------------------------------------------------------

At first glance, you might think that the memory allocated for pointer "p2" is going to be 1 byte after pointer "p1".  But when I ran this program, I got the following output:

p1 = 0xa010320, p2 = 0xa010330

which shows a difference of 0x10, which tells me that malloc is aligning things on a 16 byte boundary.  This means that I could write an extra 15 bytes to pointer "p1" and not blow up my program.

Of course, you can't always rely on this, since you have no idea where the boundaries will be....
0
 
pjknibbsCommented:
nebeker: However, malloc() has nothing to do with this situation because malloc() is not used to allocate memory for a declaration like char str[9]. In this case, since str[9] is a local variable, the compiler will simply assign 9 extra bytes on the stack when entering the function by shifting the stack pointer, which is a LOT faster than allocating stuff using malloc(). (You should remember that malloc() is a C run-time library function, whereas array variables are a much lower-level part of the C language).

puji: newmang gave a perfect explanation. I'd be willing to bet that if you inspect the value of str1 after doing your strcat() you'll find it's changed, because the end of the concatenated string has overwritten the start of it.
0
What Kind of Coding Program is Right for You?

There are many ways to learn to code these days. From coding bootcamps like Flatiron School to online courses to totally free beginner resources. The best way to learn to code depends on many factors, but the most important one is you. See what course is best for you.

 
pujiAuthor Commented:
Thanks for the response, one more thing regarding strncat,
Does strncat add a '\n' at the end of the
string?
0
 
nebekerCommented:
Well, the compiler may *assign* 9 bytes, but the NEXT variable on the stack will be aligned on a 4 byte boundary, which gives pretty much the same effect, since you can easily write another 3 bytes into that char[9] variable without blowing anything up.

By the way, array variables aren't a lower part of C.  C doesn't know anything about arrays, period.  It treats them as a base pointer + an offset, that's it.

0
 
nebekerCommented:
puji -

strncat will never append a \n character at the end of the string (strcat won't either).  I think you're confusing this with the '\0' (nul) character, which strncat will append to the destination string.
0
 
pjknibbsCommented:
nebeker: True, but pointers are still a much lower level part of the language than malloc() is. If you try compiling a simple C program to assembly code you will NOT find any calls to malloc() in the part of the code which allocates local variables.

As for stack items being aligned on four byte boundaries, there's absolutely no reason why the compiler needs to do this. If you're using PUSH and POP to set and retrieve stack values you're limited to four byte boundaries, true, but the compiler will access local variables by reading from a direct offset to the EBP register--no PUSH or POP operations are involved. It might well be that the compiler WILL doubleword-align the variables for faster access, but there's absolutely nothing forcing it to do so.
0
 
rpatnaCommented:
if u see the code of strcat();
then u can understand urself only
why it not give "Application Error"
and why it run successfully without any error.
0
 
pujiAuthor Commented:
To nebeker
>>strncat will never append a \n character at the end of >>the string (strcat won't either).  I think you're
>>confusing this with the '\0' (nul) character, which >>strncat will append to the destination string.


Hi nebeker

I just wrongly typed as '\n'. But I meant '\0', null character.

So Is it true that all c compilers, (or atleast the one MSVC uses) adds a '\0' to the destination string after doing a concatenation.

Thanks
puji
0
 
newmangCommented:
Yes
0
 
pjknibbsCommented:
Yes, because that's how the strcat() function is defined and written in all cases.
0
 
osnatCommented:
a) The program does not check run-time errors. U can also use free on a pointer and then use it. U can do what ever u want with pointers, but it is your responsibility ! If the memory is not used by the OS of any other application, then your program will run. BUT this is a chance u, as a programmer, can not take.

b)regarding strcat: since strcat add str2 at the end of str1, u can not define str1 as char*. and why not?!
when u define char* str1 = "test"; u are allocating 5 chars for str1 (strlen("test") + 1 for null terminator).
And str1 shoule be long enough to hold the combination of str1 and str2. there for: the compiler will have no problems with it, since strcat takes (char* str1, const char*str2), but in run-time your program will crash.
0
 
nebekerCommented:
osnat -

Your answer adds absolutely nothing to the discussion - why did you even bother to post this as an answer instead of a comment?
0
 
pjknibbsCommented:
nebeker: Because he's seen there's been no activity in this thread for three days and he thinks he can camp out in it and get an automatic answer awarded to him, I imagine.
0
 
pujiAuthor Commented:
Hello All,

Thanks for your repsonses.
I believe I haven't worded by question .
Actually I wanted to know
Is there any difference in the '\0' null character
getting appended with respect to strcat and strncat().

Why Iam specific about this case is I came across a
program where STRNCAT function worked when I added a
null character to it, but it did NOT work (gave an error)
without the explicit additon of '\0'.

Thanks
puji
0
 
nebekerCommented:
puji -

What platform and compiler are you using?  It is possible that strncat doesn't append a null in some cases -- depending on your particular compiler, that is...
0
 
newmangCommented:
puji

It would be simple for you to add the trailing null anyway as follows

len=strlen(str1);
len+=strlen(str2);
strncat(str1,str2,sizeof(str1));
if(len<sizeof(str1))
    str1[len-1]=0x00;
else
    str1[sizeof(str1)-1]=0x00;

Cheers - Gavin
0
 
pujiAuthor Commented:
Hi

Iam using MSVC that comes with Visual Studio 6.0 on
Windows NT 4.0 Platform.

0
 
nebekerCommented:
As long as both strings are null terminated, you won't have a problem with strncat.

Here's the reference page from Microsoft on strncat:

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vclib/html/_crt_strncmp.2c_.wcsncmp.2c_._mbsncmp.asp

It says:

The strncat function appends, at most, the first count characters of strSource to strDest. The initial character of strSource overwrites the terminating null character of strDest. If a null character appears in strSource before count characters are appended, strncat appends all characters from strSource, up to the null character. If count is greater than the length of strSource, the length of strSource is used in place of count. The resulting string is terminated with a null character. If copying takes place between strings that overlap, the behavior is undefined.


If you've run into a problem with this before, it most likely happened because the 2nd string wasn't null terminated...
0
 
pujiAuthor Commented:
Thanks To All of You, But I would like to give points to
nebeker since it clarified my doubt.

Thanks
Puji
0
 
pujiAuthor Commented:
Thanks nebeker

Bye
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

Join & Write a Comment

Featured Post

What Kind of Coding Program is Right for You?

There are many ways to learn to code these days. From coding bootcamps like Flatiron School to online courses to totally free beginner resources. The best way to learn to code depends on many factors, but the most important one is you. See what course is best for you.

  • 6
  • 6
  • 4
  • +3
Tackle projects and never again get stuck behind a technical roadblock.
Join Now