why does strcat not work inside function? - c

hi i'm trying to write a function that get 3 words, concatenate them to one word and print the word reverse.
i can't put the concatenated word into the ptr w1 in concatWords function.
another question - should i put '\0' in the end of every word?
can someone review my code?
thanks!
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define N 10
void initWords(char *w1, char *w2, char *w3) {
printf("Enter first word:\n");
scanf("%10s", w1);
printf("Enter second word:\n");
scanf("%10s", w2);
printf("Enter third word:\n");
scanf("%10s", w3);
}
char* concatWords(char *w1, char *w2, char *w3) {
int len = strlen(w1) + strlen(w2) + strlen(w3);
w1 = (char*)malloc(sizeof(char) * len);
strcat(w1, w2);
strcat(w1, w3);
return w1;
}
void printReversedWord(char *word) {
int len = strlen(word);
for (int i = len - 1; i >=0; i--) {
printf("%c", word);
}
}
int main()
{
char word1[N+1];
char word2[N+1];
char word3[N+1];
char* longWord;
initWords(word1, word2, word3);
longWord = concatWords(word1, word2, word3);
printReversedWord(longWord);
free(longWord);
return 0;
}

You allocate memory that you assign to w1. Whatever w1 was pointing at can therefore not be included in the final string. You need a separate variable for where to put the final result.
Example:
char *concatWords(char *w1, char *w2, char *w3) {
size_t w1len = strlen(w1);
size_t w2len = strlen(w2);
size_t w3len = strlen(w3);
// the final result will be stored in memory pointed out by `res`:
char *res = malloc(w1len + w2len + w3len + 1); // +1 for null terminator
if (res) {
// copy the three strings where they belong:
memcpy(res, w1, w1len);
memcpy(res + w1len, w2, w2len);
memcpy(res + w1len + w2len, w3, w3len + 1); // +1 for null terminator
}
return res;
}
Another issue: printReversedWord is missing the subscript operator on word:
void printReversedWord(char *word) {
for (size_t i = strlen(word); i-- > 0;) {
printf("%c", word[i]); // <- here
}
}
Demo

The function strcat deals with strings. That means that the both function arguments shall point to strings. And the function also builds a string.
Also as your function does not change passed strings then its parameters should have qualifier const. And the function shall build a new string. Otherwise after this statement
w1 = (char*)malloc(sizeof(char) * len);
the first passed string is lost.
The function can look the following way
char * concatWords( const char *w1, const char *w2, const char *w3 )
{
size_t len = strlen( w1 ) + strlen( w2 ) + strlen( w3 );
char *result = malloc( len + 1 );
if ( result != NULL )
{
strcpy( result, w1 );
strcat( result, w2 );
strcat( result, w3 );
}
return result;
}
In turn the function printReversedWord can look the following way/ Pay attention to that your function implementation has a bug in this statement
printf("%c", word);
You have to write
printf("%c", word[i]);
Here is the updated function definition.
void printReversedWord( const char *word )
{
size_t len = strlen( word );
while ( len != 0 )
{
putchar( word[--len] );
}
putchar( '\n' );
}
In main you should write
initWords( word1, word2, word3 );
longWord = concatWords(word1, word2, word3);
if ( longWord != NULL ) printReversedWord(longWord);
free( longWord );

char* concatWords(char *w1, char *w2, char *w3) {
int len = strlen(w1) + strlen(w2) + strlen(w3);
w1 = (char*)malloc(sizeof(char) * len);
strcat(w1, w2);
strcat(w1, w3);
return w1;
}
This method:
allocates memory that is not zeroed out, which will make it impossible to "cat" to it, because that assumes the string is null-terminated.
allocates memory and then overwrites the pointer that points to the first word. That would be lost.
allocates only memory for the three words, but misses the final zero that needs to be written to a null-terminated string
does not communicate clearly, which parameters will or will not be changed be the function
So to fix this:
char* concatWords(const char* w1, const char* w2, const char* w3) {
int len = strlen(w1) + strlen(w2) + strlen(w3);
char* all = calloc(len + 1, sizeof(char));
strcat(all, w1);
strcat(all, w2);
strcat(all, w3);
return all;
}

char* concatWords(char *w1, char *w2, char *w3) {
int len = strlen(w1) + strlen(w2) + strlen(w3);
w1 = (char*)malloc(sizeof(char) * len);
strcat(w1, w2);
strcat(w1, w3);
return w1;
}
This function needs a fair bit of work. I'm assuming you want to allocate a new string sufficiently large for the job, concatenate w1, w2 and w3 into it, and return that new string.
Firstly, you overwrote the pointer for w1 in this line:
w1 = (char*)malloc(sizeof(char) * len);
So (in that function) you've now lost whatever was pointed to by w1, because w1 is now pointed to newly-allocated memory.
Secondly, you've not allocated enough memory to store the string: you need an extra +1 to include the terminal NUL character.
The original values of w1, w2 and w3 passed into the function were cast to (char *) from the base addresses of char[] arrays, so you can't use w1 = realloc(w1, len+1); - you'll need a new variable to store the new pointer.
Your concatWords() function should look like this:
char* concatWords(const char * const w1,
const char * const w2,
const char * const w3) {
int len = strlen(w1) + strlen(w2) + strlen(w3) + 1; // Note the +1!
new_w = (char*)malloc(sizeof(char) * len);
strcpy(new_w, w1);
strcat(new_w, w2);
strcat(new_w, w3);
return new_w;
}
Note that I've changed the function's parameter types, so that you don't accidentally change the values of the w1, w2 or w3 pointers, or the memory they point to. Always use minimum viable permissions, to prevent the risk of memory corruption. In C terms, if you can const it, const it!
Your printReversedWord(char *word) function won't work either. You're passing word to printf() as the argument to its "%c" format string, not the contents of the memory it's pointing to. You never use the index variable i!
This will have the effect of passing either the first or the last byte of the pointer value as the character to print, depending whether your CPU's big-endian or little-endian.
So if word's value as a pointer was 0x12345678 (the location of the first character in the string it points to), you'd either be printing 0x12 (unprintable control character DC2) or 0x78 ('x') over and over again instead of the reversed contents of word. Of course, the actual effect would depend on the real pointer's value, not my example here.
It should be (something like):
void printReversedWord(const char * const word) {
int len = strlen(word);
for (int i = len - 1; i >=0; i--) {
printf("%c", word[i]);
}
printf("\n"); // Don't forget the newline!
}
Note the [i] in the printf() argument. It indexes into the char array pointed to by word. Note also (again) the improvement in the parameter type. I've also added a newline at the end.
Finally, looking at:
#define N 10
void initWords(char *w1, char *w2, char *w3) {
printf("Enter first word:\n");
scanf("%10s", w1);
printf("Enter second word:\n");
scanf("%10s", w2);
printf("Enter third word:\n");
scanf("%10s", w3);
}
You've defined N, but then explicitly embedded 10 in the scanf() format strings. What happens if you change the value of N at a later point?
I'll leave the solution for that as an exercise for the student. :)

The max length of each string is defined in a globally available token... Why not use it (and temporarily use a bit too much dynamic memory)?
char* concatWords(char *w1, char *w2, char *w3) {
char *p = (char*)malloc( (3*N+1) * sizeof *p );
if( p )
sprintf( p, "%s%s%s", w1, w2, w3 );
return p;
}
One could also add checking that all 3 incoming pointers are not NULL...

Related

C program to concatenate two pointer strings with functions

#include <stdio.h>
#include <stdlib.h>
char concaten(const char *str1,const char *str2);
int main()
{
printf("%s",concaten("Code","blocks"));
return 0;
}
char concaten(const char *str1,const char *str2) {
int i=0,j=0;
char *result;
while(*str1){
result[i++]=str1[i++];
}
while(*str2){
result[i+j++]=str2[j++];
}
return result;
}
I wrote this function to get two strings and add them to another third string; I don't understand where I am going wrong, as it doesn't print anything.
There are a number of problems with your concaten function.
First, it should be returning a char* pointer, not a char; thus, the declaration should look like this:
char* concaten(const char* str1, const char* str2);
Next, the function will need to allocate memory in which to store the concatenated strings; this can be done with the malloc() function, and the number of characters required will be the sum of the lengths of the two input strings plus one, for the required nul-terminator.
Third, the logic of your two loops is wrong. You are incrementing i and j twice per loop but not incrementing either of the source pointers.
Finally, you must add a nul-terminator at the end of your new string.
Here's a version with the above fixes applied:
char* concaten(const char* str1, const char* str2)
{
int i = 0, j = 0;
char* result = malloc(strlen(str1) + strlen(str2) + 1); // allow space for nul-terminator
while (*str1) {
result[i++] = *str1++; // Only increment i once and "str1" once
}
while (*str2) {
result[i + j++] = *str2++; // Only increment j once and "str2" once
}
result[i + j] = '\0'; // Add required nul-terminator
return result;
}
Also, as you have allocated memory (with the malloc call), you should release that when you're done with the data, using a call to free. Here's how your main might work:
int main(void)
{
char* answer = concaten("Code", "blocks");
printf("%s", answer);
free(answer);
return 0;
}
Note: You can also remove the j variable entirely, and just re-use the result[i++] expression in the second loop. I've left it in so that you can more easily relate my code to your own.
Your function has the return type char
char concaten(const char *str1,const char *str2);
but within the function you are returning the variable result
return result;
declared like a pointer of the type char *
char *result;
So the compiler will issue a message that you are trying to convert a pointer to an integer.
The function must be declared like
char * concaten(const char *str1,const char *str2);
The pointer result is not initialized and has an indeterminate value. You need to allocate memory where you will write concatenated strings.
The while loops in the function will be infinite if str1 and/or str2 are not empty strings due to conditions
while(*str1){
and
while(*str2){
These statements
result[i++]=str1[i++];
and
result[i+j++]=str2[j++];
invoke undefined behavior not only because the pointer result is not initialized but also because there is no sequence point between left and write operands where there is used the postfix increment operator ++.
Also the result string must be zero terminated.
If you are not allowed to use standard C string functions then your function can be implemented for example the following way
char * concatenate( const char *str1, const char *str2 )
{
size_t n1 = 0;
size_t n2 = 0;
while ( str1[n1] ) ++n1;
while ( str2[n2] ) ++n2;
char *result = malloc( n1 + n2 + 1 );
if ( result != NULL )
{
char *p = result;
while ( *str1 ) *p++ = *str1++;
do
{
*p++ = *str2;
} while ( *str2++ );
}
return result;
}
Also you should not forget to free the allocated memory when the result string is not needed any more.
Here is a demonstrative program.
#include <stdio.h>
#include <stdlib.h>
char * concatenate( const char *str1, const char *str2 )
{
size_t n1 = 0;
size_t n2 = 0;
while ( str1[n1] ) ++n1;
while ( str2[n2] ) ++n2;
char *result = malloc( n1 + n2 + 1 );
if ( result != NULL )
{
char *p = result;
while ( *str1 ) *p++ = *str1++;
do
{
*p++ = *str2;
} while ( *str2++ );
}
return result;
}
int main(void)
{
char *result = concatenate( "Code ", "blocks" );
if ( result != NULL ) puts( result );
free( result );
return 0;
}
The program output is
Code blocks
If you may use standard C string functions then the function concatenate can look as it is shown in the demonstrative program below.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char * concatenate( const char *str1, const char *str2 )
{
size_t n1 = strlen( str1 );
size_t n2 = strlen( str2 );
char *result = malloc( n1 + n2 + 1 );
if ( result != NULL )
{
memcpy( result, str1, n1 );
memcpy( result + n1, str2, n2 + 1 );
}
return result;
}
int main(void)
{
char *result = concatenate( "Code ", "blocks" );
if ( result != NULL ) puts( result );
free( result );
return 0;
}
The program output is the same as shown above that is
Code blocks
Aside from the fact that your function should not return char but char*, the expression result[i++] = str1[i++]; is not correct it lacks a sequence point. Furthermore result is an unitialized pointer, it cannot hold any data, you would need to make it point to some valid memory location.
You could do something like:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char* concatenate(const char* str1, const char* str2 ){
char* result = malloc(strlen(str1) + strlen(str2) + 1);
if (result){
char* temp = result;
while (*str1 != '\0'){
*temp++ = *str1++;
}
while (*str2 != '\0'){
*temp++ = *str2++;
}
*temp = '\0'; // don't forget to null terminate the string
}
return result; // if memory allocation fails a null pointer is returned
}
The direct usage of the function in the printf statement will not allow you to free the memory and you would have a memory leak if the program didn't finish immediately, in these cases it's best to have the returned pointer assigned as to not lose track of the allocated memory:
int main(void){
char *result = concatenate("Code", "blocks");
if(result){
printf("%s", result);
free(result);
}
return EXIT_SUCCESS;
}

Concatenation of two arrays using while loop

There is no problem with the code. I have a doubt whether we can concatenate two arrays or not. We learned that we cannot increase the size of an array once it is declared. But the following code seems to be doing that. Can we add elements to the statically created arrays using bellow part?
while(S1[i] = S2[j]) {
i++;
j++;
}
#include<stdio.h>
char* strcatt(char[], char[]);
int main(void) {
char S1[] = "University of Colombo";
char S2[] = "Sri Lanka";
printf("%s\n", strcatt(S1, S2));
return 0;
}
char* strcatt(char S1[], char S2[]) {
int i = 0, j = 0;
while(S1[i]) {
i++;
}
S1[i++] = ' ';
while(S1[i] = S2[j]) {
i++;
j++;
}
return (S1);
}
I get this output :- University of Colombo Sri Lanka
The function itself is correct except it should be updated the following way
char * strcatt( char s1[], const char s2[] )
{
size_t i = 0, j = 0;
while ( s1[i] ) i++;
s1[i++] = ' ';
while ( s1[i] = s2[j] )
{
i++;
j++;
}
return s1;
}
That is the type int of the variables i and j should be changed to the type size_t because the size of an array can be greater than the meximum positive value of an object of the type int.
And the second parameter should be qualified as const because it is not changed by the function. Otherwise at least you will not be able to call the function for a constant character array passed to the function as the second argument even it is not changed in the function.
But nevertheless the program has undefined behavior because the character array S1 has no space to accomodate the string stored in the second array S2.
The program will be valid if the first character array will have at least 32 or more elements
char S1[32] = "University of Colombo";
That is if the size of the array will be equal to or greater than sizeof( "University of Colombo" ) + sizeof( "Sri Lanka" )
Take into account that undefined behavior means everything including even the expected result.:) But it also means that the corresponding code is invalid.
In case of your program there are attempts to write to memory beyond the character array S1.
It occurred such a way that the compiler placed the two arrays immediately one after another in the order S1 and then S2. So in fact the function strcatt overwrited the character array S2 by itself.
But it is not necessary that another compiler will place the arrays in this order and moreover without a gap between the character arrays.
Your call to the function is wrong as you do not have enough space for the second string. Usually such a functions allocate memory themselves or get the buffer as the additional parameter. Below you two versions one allocates the memory, the second one takes the buffer. If the buffer is null it allocates the memory for the new string. You need to free it when not needed
char *strcpyt(char *dest, const char *str)
{
char *result = dest;
if(dest && str)
{
while(*dest++ = *src++);
}
return result;
}
size_t strlent(const char *str)
{
const char *start = str;
size_t length = 0;
if(str)
{
while(*str++);
length = str - start - 1;
}
return length;
}
char *strcatt1(const char *str1, const char *str2)
{
char *result = NULL;
size_t size;
if(str1 && str2)
{
result = malloc((size = strlent(str1)) + strlent(str2) + 1);
if(result)
{
strcpyt(result, str1);
strcpyt(result + size, str2);
}
}
return result;
}
char *strcatt2(char *buff, const char *str1, const char *str2)
{
char *result = buff;
size_t size;
if(str1 && str2)
{
if(!result)
{
result = malloc((size = strlent(str1)) + strlent(str2) + 1);
}
if(result)
{
strcpyt(result, str1);
strcpyt(result + size, str2);
}
}
return result;
}

String appending function doesn't work

I tried to create a function that easily appends two strings. The source string has to be previously allocated dynamically. I used my knowledge but this resulted in ub and any sort of leaks.
void strapp (char *source_offset, int position, char *appendage)
{
size_t appendage_size = strlen(appendage);
source_offset = realloc(source_offset, strlen(source_offset) + appendage_size);
sprintf( &source_offset[position], "%s%s", appendage, source_offset + (position + appendage_size) );
}
What am I doing wrong?
source_offset + (position + appendage_size) is somehow strange. It seems that you tried to catenate the second string with a substring of the first copying the result in the first string.
source_offset + (position + appendage_size) is the suffix of the source string starting at offset position+appendage_size which is a non-sense as it is past the end of the source string...
May be you wanted something like this?
If you want to catenate the two string then the following is correct:
size_t appendage_size = strlen(appendage);
source_offset = realloc(source_offset, position + appendage_size + 1);
sprintf( &source_offset[position], "%s", appendage );
Which appends appendage to source_offset starting at position.
Now if you want to insert appendage in the middle this can be a little more tricky:
size_t appendage_size = strlen(appendage);
char *result = malloc(strlen(source_offset) + appendage_size + 1);
char cut = source_offset[position];
source_offset[position] = '\0';
sprintf( result, "%s%s%c%s", source_offset,appendage,cut,source_offset+position+1);
// do hat you want with result
Beware that realloc may change the base address of the initial memory, so you can't do things like this as the parameter value source_offset will be changed only locally.
size_t appendage_size = strlen(appendage) + 1; /* To hold a \0 character */
The new array allocated should be able to hold both the null characters in each string
strlen(string) + 1
actually your coes does not append string B to string A, it does append string B at position n of string A along with string A, with some out of memory offset of String A
char *
strapp(char *dest, const char *src)
{
size_t i,j;
for (i = 0; dest[i] != '\0'; i++)
;
for (j = 0; src[j] != '\0'; j++)
dest[i+j] = src[j];
dest[i+j] = '\0';
return dest;
}
the above code appends string B to String A and returns pointer to string a A;
char* strapp (char *source_offset, const char *appendage, int position)
{
char* temp = NULL:
size_t appendage_size = strlen(appendage);
if (( temp = realloc(source_offset, strlen(source_offset) + appendage_size + 1)) == NULL )
return NULL;
else
source_offset = temp;
sprintf( &source_offset[position], "%s", appendage);
return source_offset;
}
If you want to fix your function try this:
void strapp (char **source_offset, int position, char *appendage)
{
size_t appendage_size = strlen(appendage);
*source_offset = (char*)realloc(*source_offset, strlen(*source_offset) + appendage_size);
sprintf( *source_offset + position, "%s%s", appendage, *source_offset + (position + appendage_size) );
}
And call this like strapp(&str, 10, "INSERTION"); // &str - pointer to pointer.
The problem was in the following: when you sent pointer to function you are able to change data pointed by this pointer, but cannot change the pointer, so memory allocation made inside function do mot change address of initial string.
Since I was asked to provide an example of function usage and respectively the output. I converted this code to something compilable to mingw and it works like expected.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void strapp (char *source_offset, int position, char *appendage)
{
size_t appendage_size = strlen(appendage) + 1;
source_offset = realloc(source_offset, strlen(source_offset) + appendage_size);
sprintf( &source_offset[position], "%s%s", appendage, source_offset + (position + appendage_size) );
}
int main(void)
{
char *str1 = malloc(11 + 1);
sprintf(str1, "Hello World");
strapp(str1, 4, " Horrible ");
printf(str1);
free(str1);
return 0;
}
Output: Hell Horrible
Partial fix of the problem I found while investigating.
If I add a substring to a location of the source string like that:
sprintf(&source[4], "new");
the source string will be terminated by the "new" and the rest of the string will not be shown.
But if I declare the substring "new" and use
memcpy(&str1[4], appendage, 3); it does the job.
There, this is the working function:
void strapp (char *source_offset, int position, char *appendage)
{
size_t appendage_size = strlen(appendage) + 1;
char copy[strlen(source_offset) + 1];
strcpy(copy, source_offset);
source_offset = realloc(source_offset, strlen(source_offset) + appendage_size);
memcpy(&source_offset[position], appendage, strlen(appendage));
sprintf(&source_offset[position + strlen(appendage)], &copy[position]);
}

strncat implementation?

I'm sorry if this is too entry-level, but I tried implementing the library function of strcpystrncat() as follows:
#include <stdio.h>
void strncat (char *s, char *t, int n) {
// malloc to extend size of s
s = (char*)malloc (strlen(t) + 1);
// add t to the end of s for at most n characters
while (*s != '\0') // move pointer
s++;
int count = 0;
while (++count <= n)
*s++ = *t++;
*(++s) = '\0';
}
int main () {
char *t = " Bluish";
char *s = "Red and";
// before concat
printf ("Before concat: %s\n", s);
strncat(s, t, 4);
// after concat
printf ("After concat: %s\n", s);
return 0;
}
It compiles and runs fine...just that it doesn't concatenate at all!
Greatly appreciate any feedback...thanks!
It seems like you redefine s pointer with your malloc, since you've done it, it doesn't points to your first concatenated string.
First of all function return type should be char*
char* strncat (char *s, char *t, int n)
After, I think you should create local char pointer.
char* localString;
use malloc for allocate space with this pointer
localString = malloc (n + strlen(s) + 1);
and you don't need to make type cast here, cuz malloc do it itself
in fact, you should use your size parameter (n) here, not strlen(t)
and after doing all concatenation operation with this pointer return it
return localString

Is there a better way to write this function?

Here is a insert string function,
void ins( char * T, size_t ip, char * P)
{
char temp1[100], temp2[100];
strncpy(temp1,T,ip);
strcpy(temp2, &T[ip]);
strcat(&T[ip], P);
strcat(&T[sizeof(temp1) + sizeof(P) - 2], temp2);
}
Is there a better way to write this function?
I needed to add an extra argument maxlen: the maximal size of str that can be written to. I also modified the return type to something useful.
size_t do_insert(char *str, size_t maxlen, size_t where, char *ins)
{
size_t len_str, len_ins;
/* these could be arguments, too,
** if these are already known by the caller.
*/
len_str = strlen(str);
len_ins = strlen(ins);
/* not enough space: return */
if (len_str + len_ins >= maxlen)
return len_str + len_ins;
/* I don't know what should happen if the place to insert
** is beyond the length of str
** [ there also is a corner case lurking here if where == len_str]
*/
if (where > len_str)
return ???;
/* make place for the insert by shifting str up.
** we move one byte extra: the nul character.
*/
memmove( str + where + len_ins, str + where, len_ins + 1);
/* put the insert where it belongs */
memcpy ( str + where, ins, len_ins );
/* return the length of the new string */
return len_str + len_ins;
}
NOTE: Untested.

Resources