char *
STRCAT(char *dest, const char *src)
{
strcpy(dest + strlen(dest), src);
return dest;
}
what's the meaning of the code :dest + strlen(dest)?
and when I use the code like below:
#include <stdio.h>
#include <string.h>
void main()
{
char s[10]= "123456789";
char str[10] = " 123456789";
strcat(s,str);
printf("%s\n",s);
printf("%d",sizeof(s));
}
why the string s didn't overflow and the sizeof(s) did not change?
what's the meaning of the code :dest + strlen(dest)
It calculates the pointer to the end of the dest because with strcat you want to append the second string to the end of the first. It similar to:
size_t l = strlen(dest);
char *p = &dest[l]; // dest + l pointer arithmetic.
strcpy(p, src);
why the string s didn't overflow and the sizeof(s) did not change?
s is overflowing, because after strcat is done, your string is now 20 characters long, while it holds only room for 10 characters. This invokes undefined behavior.
sizeof doesn't change, because it is determined at compile time, so it will always show the same value.
strcat and STRCAT are two different functions.:)
I think you mean the function name strcat instead of STRCAT in this declaration
char *
strcat(char *dest, const char *src)
{
strcpy(dest + strlen(dest), src);
return dest;
}
This function is designed to deal with strings that is with sequences of characters terminated by the zero character '\0'.
The function strlen returns the number of characters in a string before the terminating zero character '\0';.
So the expression dest + strlen(dest) points to the terminating zero character '\0' of the string contained in the destination character array. Thus the function strcat can append the source string to the string stored in the destination array starting from the terminating zero.
So for example if you have a character array declared like
char dest[3] = { '1', '0' };
and the source array declared like
char src[2] = { '2', '0' };
For the array dest the function strlen( dest ) will return the value 1.
As a result dest + strlen( dest ) points to the second character of the array dest that is the zero character '0'. And this call
strcpy(dest + strlen(dest), src);
will copy characters of the string stored in the array src in the array dest starting with this position and you will get the following content of the array dest
{ '1', '2', '\0' }
In your program the expression sizeof( s ) gives the number of elements with which the array s is declared
char s[10]= "123456789"
that is 10. This value specified in the declaration of the array does not depend on the content that the array will have and is calculated at the compile time.
Pay attention to that values returned by the operator sizeof have the type size_t. So to output them using the function printf you have to use the conversion specifier zu. For example
printf("%zu\n",sizeof(s));
In your program the array str
char str[10] = " 123456789";
does not contain a string because it does not have a space to accommodate the (eleventh ) terminating zero character of the string literal used as an initializer.
On the other hand, the array s does not have a space to be able to append another string to its tail.
So your program has undefined behavior.
A valid program can look like
#include <stdio.h>
#include <string.h>
int main( void )
{
char str[] = " 123456789";
char s[10 + sizeof( str ) - 1] = "123456789";
strcat( s, str );
printf( "%s\n", s);
printf( "%zu\n", strlen( s ) );
printf( "%zu\n", sizeof( s ) );
}
Pay attention to that according to the C Standard the function main without parameters shall be declared like
int main( void )
Related
I have a code
char str1[15];
char str2[15];
memcpy(str1,"abcdef",6);
memcpy(str2,"abcdef",6);
so str1 should have null termination at index 7.
but when I do printf("--%d--",strlen(str1)); it prints --9-- which is why its making me think that memcpy is not considering null termination when copy into str1 the string literal `"abcdef".
so shouldnt it also read null termination or is something I did in printf gives me print --9--?
memcpy just copy a number of bytes, whatever they are. In your case, it copies 6 bytes from a string of 6 characters and hence do not copy the null byte at the end of string.
Better code could be written.
Given:
char str1[15];
char str2[15];
char *p = "abcdef";
This will copy "abcdef" and the nul byte to str1 and str2:
memcpy(str1, p, strlen(p) + 1);
memcpy(str2, p, strlen(p) + 1);
But this is not very good because str1 and str2 array could be overflown if the string is to long!
It is much better to use strncpy which copies the string, taking account of the nul terminating byte, the length of the string and the maximum length of the destination:
strncpy(str1, p, sizeof(str1));
strncpy(str2, p, sizeof(str2));
Warning: If there is no null byte among the first n bytes of the source, the string placed in destination will not be null-terminated. See strncpy man page.
void * memcpy( void *destination, const void *source, size_t num ); just copies num bytes of memory, pointed by source, to another memory pointed by destination pointer.
The methods which deal with copying of null-terminated strings are
char * strcpy ( char *destination, const char *source);
char * strncpy ( char *destination, const char *source, size_t num);
Based on your example, you need to use strncpy:
char str1[15];
char str2[15];
strncpy(str1,"abcdef",7);
strncpy(str2,"abcdef",7);
str1 and str2 will hold "abcdef" at the end.
If you just want to copy the whole string up to the size of str1 or str2 then you can do the following
#define STR_LEN 15
char str1[STR_LEN];
char str2[STR_LEN];
strncpy(str1,"abcdef", STR_LEN);
strncpy(str2,"abcdef", STR_LEN);
NOTE:
As the documentation of strncpy states:
No null-character is implicitly appended at the end of destination if source is longer than num. Thus, in this case, destination shall not be considered a null terminated C string (reading it as such would overflow).
In this context, does the while loop work like a for loop? Also, what does the str1-str2 string subtraction result in?
#include <stdio.h>
int fun(char *str1) {
char *str2 = str1;
while (*++str1);
return (str1 - str2);
}
int main() {
char *str = "GeeksQuiz";
printf("%d", fun(str));
return 0;
}
Notice that you are working here with pointers and not strings, so starting from the end, str1-str2 is a pointers arithmetic.
As you know string should be ended with a null, so in the memory "GeeksQuiz" is actually an array of chars that has the next values: GeeksQuiz\0. In that way, while(*++str1); will run through the values of this array till it reaches \0.
To conclude, this function will return the number of chars in the string.
The purpose of the function is to calculate the length of a string. That is this while loop
while(*++str1);
iterates until the terminating zero character '\0' is encountered. It is supposed that after the while loop the pointer str1 will point to the terminating zero character '\0' while the pointer str2 will point to the beginning of the string due to the initial assignment
char *str2 = str1;
So the difference str1-str2 will yield the length of the string. The length of a string is determinate as the number of characters in the string before the terminating zero character '\0'.
However the function has a bug. If the user will pass an empty string "" that is internally represented as a character array with one element that is equal to the terminating zero character { '\0' } then the function invokes undefined behavior. So an empty string contains in its first character the terminating zero character '\0'. However in the while loop the pointer str1 at first incremented and then already the next character is checked whether it is the terminating zero character '\0'.
That is this while loop
while(*++str1);
may be rewritten the following way
while ( ( ++str1, *str1 != '\0' ) );
As it is seen at first the pointer str1 is incremented.
Apart from this defect the function parameter should have the qualifier const because within the function the passed string is not being changed. Also the return type of the function should be unsigned integer type as for example size_t (it is the return type of the standard C string function strlen that does the same task.)
The function can be declared an define the following way
size_t fun( const char *s )
{
const char *t = s;
while( *t ) ++t;
return t - s;
}
Here is a demonstrative program.
#include <stdio.h>
size_t fun( const char *s )
{
const char *t = s;
while( *t ) ++t;
return t - s;
}
int main(void)
{
const char *s = "";
printf( "The length of the string \"%s\" is equal to %zu\n", s, fun( s ) );
s = "1";
printf( "The length of the string \"%s\" is equal to %zu\n", s, fun( s ) );
s = "12";
printf( "The length of the string \"%s\" is equal to %zu\n", s, fun( s ) );
s = "123";
printf( "The length of the string \"%s\" is equal to %zu\n", s, fun( s ) );
return 0;
}
The program output is
The length of the string "" is equal to 0
The length of the string "1" is equal to 1
The length of the string "12" is equal to 2
The length of the string "123" is equal to 3
The loop while (*++str1); increments the pointer, reads the byte pointed to by the updated str1, and tests if this byte is null, if not it stops otherwise do nothing and repeat. This loop would be more readable with an explicit statement instead of an empty statement ;:
while (*++str1 != '\0')
continue;
return (str1 - str2); computes the difference of pointers str1 and str2 and returns this value as an int. The difference of 2 pointers is defined if they point to the same array and evaluates to the number of elements between them.
The function attempts to compute the length of the string argument but would fail for the empty string because str1 is always incremented before the test, hence would skip the null terminator at offset 0 for the empty string. The behavior is undefined as the code then reads beyond the end of the string. For non empty strings, It prints the number of non null characters, aka the length of the string: fun("GeeksQuiz") returns 9.
Here is a modified version:
#include <stdio.h>
int fun(const char *str) {
const char *start = str;
while (*str != '\0')
str++;
return str - start;
}
int main() {
const char *str = "GeeksQuiz";
printf("length of \"%s\" is %d\n", str, fun(str));
return 0;
}
I ran your code through clang-format [see Note 1] to confirm what I suspected about the weird while loop you've got going on there, and I came up with this as correct formatting for your code:
#include <stdio.h>
int fun(char *str1)
{
char *str2 = str1;
while (*++str1)
;
return (str1 - str2);
}
int main()
{
char *str = "GeeksQuiz";
printf("%d", fun(str));
return 0;
}
Personally, I would have written it like this though, to make the while loop super obvious. You can run this code here: https://onlinegdb.com/BkxlKb75GO.
#include <stdio.h>
int fun(char *str1)
{
char *str2 = str1;
while (*++str1)
{
// do nothing
}
return (str1 - str2);
}
int main()
{
char *str = "GeeksQuiz";
printf("%d", fun(str));
return 0;
}
Even more-readable, however, is this for the fun() function, which I've also renamed to count_num_chars_in_str():
int count_num_chars_in_str(char *str1)
{
char *str2 = str1;
while (*str1 != '\0')
{
str1++;
}
return str1 - str2;
}
A shorter name might be num_chars_in_str(), str_length(), or strlen(). strlen() already exists (see here and here), and this is precisely what it does. It can be included by header string.h, and is part of the C and C++ standard. Here's its description on cplusplus.com:
size_t strlen ( const char * str );
Get string length
Returns the length of the C string str.
The length of a C string is determined by the terminating null-character: A C string is as long as the number of characters between the beginning of the string and the terminating null character (without including the terminating null character itself).
This should not be confused with the size of the array that holds the string.
So, running any of these programs above, the output is 9. All the program does is count the number of non-null chars (where a null char is 0, or '\0'--same thing) in the string passed in, which is GeeksQuiz in this case. GeeksQuiz contains 9 non-null chars.
Where did you get your code by the way? Please post links and references. You should always reference your sources.
while (*++str) simply keeps incrementing the str pointer one char at a time until a null terminator (0) is found, which occurs right at the end of the string, after the last char in it. Once that happens, the difference between the two char pointers is taken, resulting in the difference between the address location of the null terminator right after the z, and the address location of the first char in the string, which is G. The difference in memory address between these 2 chars is 9 chars.
Not only is the original version less-readable, it also has a bug in it. For this test case, it should print 0, but it prints 1 instead:
char *str = "\0";
printf("%d", fun(str));
My more-readable version in count_num_chars_in_str() corrects this bug too.
Lesson: don't write unreadable or obfuscated code.
[Note 1] The way I ran it through clang-format is I just copy-pasted your original code into a main.c file, then copied that into my eRCaGuy_CodeFormatter repo here, then ran ./run_clang-format.sh.
In this context, does the while loop work like a for loop?
I would say that all while loops act like for loops, and vice versa.
Any time you have a loop
while(condition)
{ /* do something */; }
you can replace it by an equivalent for loop:
for(; condition; )
{ /* do something */; }
Going the other way, any time you have a for loop
for(initial_expression; test_expression; increment_expression)
{ /* do something */; }
you can (almost) replace it with an equivalent while loop:
initial_expression;
while(test_expression) {
/* do something */;
increment_expression;
}
(There's one small difference between the two, but it only shows up if you use a continue statement in the loop.)
If you were stranded on a desert island with a broken C compiler (or if you were stranded in the classroom of an instructor who likes to pose "trick" questions), and you had to write a C program without using the for keyword, you could: you could write all your loops using while instead, without loss of functionality.
In the case down below.
Does changing the string 'out' change the string 'str' respectively? In other words, do they have the same pointer?
Thank you in advance.
int main() {
char str[]={'g','o','o','d','/0'};
char special[]={'o','/0'};
char* out=str;
return 0;
}
It depends. If you write:
out = "hello!";
you do not change the string str, but simply make out point to another memory location.
But if you write into out like in this:
sprintf(out, "abcd");
then you do change str. But beware of overflow!
For starters I think you mean the terminating zero '\0' instead of the multibyte character literal '/0'.
To escape such an error it is better to initialize character arrays with string literals (if you are going to store a string in an array). For example
char str[] = { "good" };
or just like
char str[] = "good";
As for the question then after this assignment
char* out=str;
the pointer out points to the first character of the array str. Thus using this pointer and the pointer arithmetic you can change the array. For example
char str[] = "good";
char *out = str;
out[0] = 'G';
*( out + 3 ) = 'D';
puts( str );
Moreover an array passed as an argument to a function is implicitly converted to pointer to its first character. So you can use interchangeably either an array itself as an argument or a pointer that initialized by the array designator. For example
#include <stdio.h>
#include <string.h>
//...
char str[] = "good";
char *out = str;
size_t n1 = strlen( str );
size_t n2 = strlen( out );
printf( "n1 == n2 is %s\n", n1 == n2 ? "true" : "false" );
The output of this code snippet is true.
However there is one important difference. The size of the array is the number of bytes allocated to all its elements while the size of the pointer usually either equal to 4 or 8 based on used system and does not depend on the number of elements in the array. That is
sizeof( str ) is equal to 5
sizeof( out ) is equal to 4 or 8
Take into account that according to the C Standard the function main without parameters shall be declared like
int main( void )
I think there's a typo in your code, you have written '/0' but it's not a null character but '\0' is.
As far as out & str are concerned, str[] is a char array, whereas out is a pointer to it. If you make out point to some other char array there'll be no effect on str. But you can use out pointer to change the values inside the str[], like this,
int main( void )
{
char str[]={'g','o','o','d','\0'}; // There was a typo, you wrote '/0', I guess you meant '\0'
//char special[]={'o','\0'};
char* out=str;
for(int i=0; out[i] != '\0'; i++)
{
out[i] = 'a';
// This will write 'a' to the str[]
}
printf("out: %s\n", out);
printf("str: %s", str);
return 0;
}
No. out is a different variable that holds the same address str is at, i.e. it points to the same location. Note that changing *str will change *out.
In C, assignment takes the value of the right end and stores it in the left end, it does not makes the right "become" left
I'm trying to build a string that consists of two variables that are divided by a null terminator. It must be done this way for the custom protocol we're using.
const char* vendorChar = "3333-3333-4444-aaa3-3333";
const char* userChar = "someUsername";
char usernameString[strlen(vendorChar) + strlen(userChar) + 1];
char* uPtr = usernameString;
strcpy(uPtr, vendorChar);
strcpy(uPtr+strlen(vendorChar)+1, userChar);
When I run the above code, it only sends over the value of vendorChar and ignores userChar. When it is working it should look like
4444-2222-3333-1111\0someUsername
So far I've learned that str functions will drop the null as it sees it at the end of the string. I think I have to use memcpy to preserve it, but I can't figure out how to.
You're right in your assumption, strcpy may copy up to the middle null char,
according to this, strcpy(char *str1, const char *str2) does this:
Copies the string pointed to by str2 to str1. Copies up to and including the null character of str2. If str1 and str2 overlap the behavior is undefined.
memcpy should solve the problem as it just treats the memory as a chunk of bytes, not as a string.
strcpy signature:
char *strcpy(char *dest, const char *src);
memcpy signature:
void *memcpy(void *dest, const void *src, size_t n);
So just replace the name and add the cumulative lengths (with both null chars of course).
EDIT
To eliviate some doubts raised here, consider this code:
#include "string.h"
#include "stdio.h"
int main() {
char x[10] = {0};
char y[10];
char z[10];
x[0] = x[1] = x[5] = 'a';
memcpy(y,x,10);
strcpy(z,x);
printf ("y[5]= %s\n", &y[5]);
printf ("z[5]= %s\n", &z[5]);
return 0;
}
results is:
y[5]= a
z[5]=
So it's clear that memcpy moved the entire length, including byte [5], while strcpy did not, stopping at the null termination
const char* vendorChar = [vendorId cStringUsingEncoding: [NSString defaultCStringEncoding]];
const char* userChar = [dsUsername cStringUsingEncoding: [NSString defaultCStringEncoding]];
char usernameString[strlen(vendorChar) + strlen(userChar) + 2];
char* uPtr = usernameString;
strcpy(uPtr, vendorChar);
memcpy(uPtr+strlen(vendorChar)+1, userChar, strlen(userChar) + 1);
Changes: I added space for the trailing \0, the userChar string is copied with trailing \0 included.
Firstly, you need usernameString[] to be like -
char usernameString[strlen(vendorChar) + strlen(userChar) + 3];
because 1 is for putting "\", 1 for "0" and the other 1 is for null terminator, so becomes 3. Then use strcat() create the string you need. Like, below:
strcpy(uPtr, vendorChar);
strcat(uPtr,"\\");
strcat(uPtr,"0");
strcat(uPtr, userChar);
I tried to code a function which replace all string s1 to s2, in a given string s.
however, i don't know why my program stop at the line *p=0 in that replace function without any error reported? ##
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void replace(char * s, char * s1, char * s2) {
char * p; int l=strlen(s2);
while ((p=strstr(s,s1))) {
*p=0;
p+=l;
strcat(s,s2);
strcat(s,p);
}
}
int main(void) {
char *s=(char *)"cmd=ls+-la&abc=xyz";
replace (s, "+", " ");
printf("%s", s);
return EXIT_SUCCESS;
}
There are some problems with the replace function but, first of all, there is a big difference between a pointer to a constant char array vs a character array:
char *str = "some string";
Assigns str the address of the immutable character array (read-only), it does not copy the string, only pointers are involved. Any attempt to modify that string will result in undefined behavior.
char str[] = "some string";
In this case str is an array (of size big enough to hold the string + \0) that is initialized to that string, allowing the modification of individual characters within the array.
Back to your replace function.
I will start with the first thing that I saw which is your use of strstr and strcat inside the loop is highly inefficient. Every time you call strstr it starts from the beginning of the string and searches for the first occurrence of the second string all over, the same problem can be seen with strcat which needs to find the null-terminator every time.
Another issue I see is if the replacement string (s2) is longer than the original string (s1) you must shift the entire string to accommodate for the additional characters of the new string. The same issue will occur if the replacement string is shorter.
a basic method to replace a simple char might look like this:
while (*s)
{
if (*s == c1)
*s = c2;
++s;
}
a little more complex method to replace a string would be:
/* PRECONDITION: strlen(s1) == strlen(s2) */
int l = strlen(s2);
while (*s)
{
if (!strncmp(s, s1, l))
{
memcpy(s, s2, l);
s += l;
}
else
++s;
}
Your compiler is allowed to place string literals into read-only memory, which is probably what it did with s.
Try:
char s[] = "cmd=ls+-la&abc=xyz";
This changes s from a pointer to a string literal into an array initialized with your string.