Create a function that concatenates two strings
The function should be created based on the following criteria
The putchar keyword should be used
The prototype must be char *_strcat(char *dest, char *src);
The function should add a terminating null value at the end of dest
The function should return a pointer to dest.
The function below finds the end of the src string and appends it to dest string.
I tried it out with my main.c file and got
World!Hello instead of Hello World!
void concatenate(char* str1, char* str2) {
int i = 0, j = 0;
// Find the end of the first string
while (str1[i] != '\0') {
i++;
}
// Append the second string to the end of the first string
while (str2[j] != '\0') {
str1[i] = str2[j];
i++;
j++;
}
// Add a null terminator to the end of the concatenated string
str1[i] = '\0';
}
Your assignment has problems:
Create a function that concatenates two strings.
This statement is not precise enough: should it allocate a new string or concatenate the second string at the end of the first string like strcat()?
The function should be created based on the following criteria.
I would rather write: The function should meet the following requirements.
The putchar keyword should be used.
This is a most ridiculous requirement! putchar is not a keyword, but a macro (an a function) defined in <stdio.h>. Using it in a user function is feasible, but tricky, not something newbies should be required to try and certainly not something any programmer should do.
The prototype must be char *_strcat(char *dest, char *src);
This requirement is bogus:
the identifier is a reserved word (it starts with an _). my_strcat or concat_string would be better choices
at least src should be declared const char *src. And it would indicate that the function likely behaves like strcat, or both arguments should be const qualified and the function should allocate memory.
The function should add a terminating null value at the end of dest.
This is implicit if the result is to be used as a C string.
The function should return a pointer to dest.
At last an indication regarding the expected semantics: the same as strcat.
Your implementation is almost correct, except for this:
the name is not as specified
the argument names are not dest and src
you should use size_t for the type of i and j
you must return dest.
Regarding your observations, you did not post the full program, but it is likely you passed the arguments in the wrong order and/or the destination array that contains Hello is not long enough to receive the concatenated string.
Here is a modified version:
#include <stdio.h>
char *my_strcat(char *dest, const char *src) {
size_t i = 0, j = 0;
#ifdef putchar
// just using the putchar identifier for fun
#endif
// Find the end of the first string
while (dest[i] != '\0') {
i++;
}
// Append the second string to the end of the first string
while (src[j] != '\0') {
dest[i] = src[j];
i++;
j++;
}
// Add a null terminator to the end of the concatenated string
dest[i] = '\0';
// return a pointer to dest.
return dest;
}
int main() {
char hello[20] = "Hello ";
char world[] = "World!";
printf("%s\n", my_strcat(hello, world));
return 0;
}
Related
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.
From my book:
void strcpy (char *s, char *t)
{
int i=0;
while ((s[i] = t[i]) != ’\0’)
++i;
}
I'm trying to understand this snippet of code from my textbook. They give no main function so I'm trying to wrap my head around how the parameters would be used in a call to the function. As I understand it, the "i-number" of characters of string t[ ] are being copied to the string s[ ] until there are no longer characters to read, from the \0 escape sequence. I don't really understand how the parameters would be defined outside of the function. Any help is greatly appreciated. Thank you.
Two things to remember here:
Strings in C are arrays of chars
Arrays are passed to functions as pointers
So you would call this like so:
char destination[16];
char source[] = "Hello world!";
strcpy(destination, source);
printf("%s", destination);
i is just an internal variable, it has no meaning outside the strcpy function (it's not a parameter or anything). This function copies the entire string t to s, and stops when it sees a \0 character (which marks the end of a string by C convention).
EDIT: Also, strcpy is a standard library function, so weird things might happen if you try to redefine it. Give your copy a new name and all will be well.
Here's a main for you:
int main()
{
char buf[30];
strcpy(buf, "Hi!");
puts(buf);
strcpy(buf, "Hello there.");
puts(buf);
}
The point of s and t are to accept character arrays that exist elsewhere in the program. They are defined elsewhere, at this level usually by the immediate caller or one more caller above. Their meanings are replaced at runtime.
Your get compile problems because your book is wrong. Should read
const strcpy (char *s, const char *t)
{
...
return s;
}
Where const means will not modify. Because strcpy is a standard function you really do need it to be correct.
Here is how you might use the function (note you should change the function name as it will conflict with the standard library)
void my_strcpy (char *s, char *t)
{
int i=0;
while ((s[i] = t[i]) != ’\0’)
++i;
}
int main()
{
char *dataToCopy = "This is the data to copy";
char buffer[81]; // This buffer should be at least big enough to hold the data from the
// source string (dataToCopy) plus 1 for the null terminator
// call your strcpy function
my_strcpy(buffer, dataToCopy);
printf("%s", buffer);
}
In the code, the i variable is pointing to the character in the character array. So when i is 0 you are pointing to the first character of s and t. s[i] = t[i]copies the i'th character from t to the i'th character of s. This assignment in C is self an expression and returns the character that was copied, which allows you to compare that to the null terminator 0 ie. (s[i] = t[i]) != ’\0’ which indicates the end of the string, if the copied character is not a null terminator the loop continues otherwise it will end.
I have a problem with printing a string in C (well, the string that *ptr points to).
I have the following code:
char *removeColon(char *word) {
size_t wordLength;
char word1[MAXLENGTH];
wordLength = strlen(word);
wordLength--;
memcpy(word1, word, wordLength);
printf("word1: %s\n", word1);
return *word1;
}
I ran this with word = "MAIN:" (the value of word comes from strtok on a string read from a file).
It works fine until the printf, where the result is:
word1: MAIN╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠
and then there is an exception and everything breaks.
Any thoughts?
Your function removeColon should either
operate in place and modify the string passed as an argument
be given a destination buffer and copy the shortened string to it or
allocate memory for the shortened string and return that.
You copy just the characters into the local array, not the null terminator, nor do you set one in the buffer, passing this array to printf("%s", ...) invokes undefined behavior: printf continues printing the buffer contents until it finds a '\0' byte, it even goes beyond the end of the array, invoking undefined behavior, printing garbage and eventually dies in a crash.
You cannot return a pointer to an automatic array because this array becomes unavailable as soon as the function returns. Dereferencing the pointer later will invoke undefined behavior.
Here is a function that works in place:
char *removeColon(char *word) {
if (*word) word[strlen(word) - 1] = '\0';
return word;
}
Here is one that copies to a destination buffer, assumed to be long enough:
char *removeColon(char *dest, const char *word) {
size_t len = strlen(word);
memcpy(dest, word, len - 1);
dest[len - 1] = '\0';
return dest;
}
Here is one that allocates memory:
char *removeColon(const char *word) {
size_t len = strlen(word);
char *dest = malloc(len);
memcpy(dest, word, len - 1);
dest[len - 1] = '\0';
return dest;
}
You must make sure (1) each string is nul-terminated, and (2) you are not attempting to modify a string-literal. You have many approaches you can take. A simple approach to remove the last character (any char) with strlen:
char *rmlast (char *s)
{
if (!*s) return s; /* return if empty-string */
s[strlen (s) - 1] = 0; /* overwrite last w/nul */
return s;
}
(you can also use the string.h functions strchr (searching for 0), strrchr (searching for your target char, if passed), strpbrk (searching for one of several chars), etc.. to locate the last character as well)
Or you can do the same thing with pointers:
char *rmlast (char *s)
{
if (!*s) return s; /* return if empty-string */
char *p = s;
for (; *p; p++) {} /* advance to end of str */
*--p = 0; /* overwrite last w/nul */
return s;
}
You can also pass the last character of interest if you want to limit removal to any specific character and make a simple comparison in the function before overwriting it with a nul-terminating character.
Look over both and let me know if you have any questions.
wordLength = strlen(word);
You have to include the null terminator in the length, because every string has a terminating character whose ASCII value is 0, spelled \0 in C. Also, use the str... family of functions instead of mem..., since the former is intended for null terminated strings, but the latter for arrays. In addition, you cannot return a local stack allocated array. Based on the code of the function, it sounds like you're removing the last character. If that is the case, it is better to do
void remlast(char *str)
{
str[strlen(str) - 1] = '\0';
}
Note that this does not work on empty strings.
You copy over wordLength bytes, but you fail to add a null terminating byte. Because word1 is uninitialized prior to this copy, the remaining bytes are undefined.
So when printf attempts to print the string, it doesn't find a null terminator and keeps reading until it finds a null byte somewhere outside the bounds of the array. This is undefined behavior.
After copying the bytes, you need to manually add the null terminator:
memcpy(word1, word, wordLength);
word1[wordLength] = '\0';
Also, you're returning a pointer to a local variable. When the function returns, that variable is out of scope, and dereferencing that pointer is also undefined behavior.
Rather than making word1 a local array, you can allocate memory dynamically for it:
char *word1 = malloc(strlen(word));
If you do this, you'll need to free this memory somewhere in the calling function. The other option is to have the caller pass in a buffer of the proper size:
void removeColon(char *word, char *word1) {
I'm writing a function eliminate(char *str, int character) that takes a c-string and a character to eliminate as input, scans str for instances of character and replaces the value at the current index with... what? I thought NULL, but this seems risky and could mess with other functions that rely on the null-terminator in a c-string. For example:
char *eliminate(char *str, int character) {
if (!str) return str;
int index = 0;
while (str[index])
if (str[index] == character)
str[index++] = '\0'; //THIS LINE IS IN QUESTION
return str;
}
My question is, how do I properly implement this function such that I'm effectively eliminating all instances of a specified character in a string? And if a proper elimination assigns '\0' to the character to be replaced, how does this not affect the entire string (i.e., it effectively ends at the first '\0' encountered). For example, if I were to run the above function twice on the same string, the second call would only examine the string up to where the last character was replaced.
It is fine to use such replacement if you know what you are doing.
It can work only if the char buffer char *str is writable (dynamically allocated, for example by malloc, or just char array on stack char str[SIZE]). It cannot work for string literals.
The standard function strtok also works in this way. By the way, probably you can use strtok for your task if you want to have null terminated substring.
It does not make sense to have integer type for charcter function argument: int character -> char character
Replacing the character by '\0' will likely cause confusion. I would eliminate the undesirable character by shifting the next eligible character into its spot.
char *eliminate(char *str, int character) {
if (!str) return str;
int index = 0, shiftIndex = 0;
while (str[index]) {
if (str[index] == character)
index++;
else {
str[shiftIndex] = str[index];
shiftIndex++, index++;
}
}
str[shiftIndex] = '\0';
return str;
}
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.