Link to home
Start Free TrialLog in
Avatar of puji
puji

asked on

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
Avatar of newmang
newmang

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
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....
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.
Avatar of puji

ASKER

Thanks for the response, one more thing regarding strncat,
Does strncat add a '\n' at the end of the
string?
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.

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.
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.
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.
Avatar of puji

ASKER

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
Yes
Yes, because that's how the strcat() function is defined and written in all cases.
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.
osnat -

Your answer adds absolutely nothing to the discussion - why did you even bother to post this as an answer instead of a comment?
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.
Avatar of puji

ASKER

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
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...
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
Avatar of puji

ASKER

Hi

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

ASKER CERTIFIED SOLUTION
Avatar of nebeker
nebeker

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of puji

ASKER

Thanks To All of You, But I would like to give points to
nebeker since it clarified my doubt.

Thanks
Puji
Avatar of puji

ASKER

Thanks nebeker

Bye