I wrote a function to concatenate two strings (s = "computer"; t = "keyboard"), but my code only returns "keyboard". Please point out the mistakes.
char *concat(char *s, char *t) {
s = malloc((strlen(s) + strlen(t) + 1) * sizeof(char));
char *p = s;
while (*p != '\0') {
++p;
}
while (*t != '\0') {
*p++ = *t++;
}
*p = '\0';
return s;
}
I do not want to use strcat(). This is a test program from Stepik, so I cannot change anything in the main function.
Here is the question: Write a function which receives two character pointers and returns a new character pointer representing their concatenation.
char *myconcat(const char *s1, const char *s2)
{
size_t len1,len2;
char *result = malloc((len1 = strlen(s1)) + (len2 = strlen(s2)) + 1);
if(result)
{
memcpy(result, s1, len1);
memcpy(result + len1, s2, len2 + 1);
}
return result;
}
You have s="computer" when passed into a function, and then on the very first line you reassign it with malloc, so "computer" is gone.
You can debug your program step by step, or just print the values to the console. This will help you to find the error.
You are on the right track:
you allocate the correct amount of memory,
you copy the second string correctly,
you set the null terminator correctly,
you return the pointer to the allocated block.
Yet there are some issues:
you overwrite the pointer to the first string with that returned by malloc(),
you read from the allocated memory block instead of copying the first string: this has undefined behavior,
(minor) the argument strings should be declared as const char * as you do not modify these strings.
Here is a corrected version:
#include <stdlib.h>
#include <string.h>
char *concat(const char *s, const char *t) {
char *ret = malloc((strlen(s) + strlen(t) + 1) * sizeof(char));
char *p = ret;
while (*s != '\0') {
*p++ = *s++;
}
while (*t != '\0') {
*p++ = *t++;
}
*p = '\0';
return ret;
}
Related
I am new to pointers and want to learn them well. So this is my own attempt to write my strcat function. If I return just a it prints some binary things (I think it should print the solution), If I return *a it says seg fault core dumped I couldn't find the error. Any help is accepted thanks.
#include <stdio.h>
#include <string.h>
int main() {
char *strcaT();
char *a = "first";
char *b = "second";
printf("%s", strcaT(a, b));
return 0;
}
char *strcaT(char *t, char *s) {
char buffer[strlen(t) + strlen(s) - 1];
char *a = &buffer[0];
for (int i = 0; i < strlen(s) + strlen(t); i++, t++) {
if (*t == '\n') {
for (int i = 0; i < strlen(s);i++) {
buffer[strlen(t) + i] = *(s + i);
}
}
buffer[i] = *(t + i);
}
return a;
}
The code has multiple cases of undefined behavior:
you return the address of a local array in strcaT with automatic storage, which means this array can no longer be used once it goes out of scope, ie: when you return from the function.
the buffer size is too small, it should be the sum of the lengths plus 1 for the null terminator. You write beyond the end of this local array, potentially overwriting some important information such as the caller's framce pointer or the return address. This undefined behavior has a high chance of causing a segmentation fault.
you copy strlen(t)+strlen(s) bytes from the first string, accessing beyond the end of t.
It is unclear why you test for '\n' and copy the second string at the position of the newline in the first string. Strings do not end with a newline, they may contain a newline but and at a null terminator (byte value '\0' or simply 0). Strings read by fgets() may have a trailing newline just before the null terminator, but not all strings do. In your loop, the effect of copying the second string is immediately cancelled as you continue copying the bytes from the first string, even beyond its null terminator. You should perform these loops separately, first copying from t, then from s, regardless of whether either string contains newlines.
Also note that it is very bad style to declare strcaT() locally in main(), without even a proper prototype. Declare this function before the main function with its argument list.
Here is a modified version that allocates the concatenated string:
#include <stdio.h>
#include <stdlib.h>
char *strcaT(const char *s1, const char *s2);
int main() {
const char *a = "first";
const char *b = "second";
char *s = strcaT(a, b);
if (s) {
printf("%s\n", s);
free(s);
}
return 0;
}
char *strcaT(const char *t, const char *s) {
char *dest = malloc(strlen(t) + strlen(s) + 1);
if (dest) {
char *p = dest;
/* copy the first string */
while (*t) {
*p++ = *t++;
}
/* copy the second string at the end */
while (*s) {
*p++ = *s++;
}
*p = '\0'; /* set the null terminator */
}
return dest;
}
Note however that this is not what the strcat function does: it copies the second string at the end of the first string, so there must be enough space after the end of the first string in its array for the second string to fit including the null terminator. The definitions for a and b in main() would be inappropriate for these semantics, you must make a an array, large enough to accommodate both strings.
Here is a modified version with this approach:
#include <stdio.h>
char *strcaT(char *s1, const char *s2);
int main() {
char a[12] = "first";
const char *b = "second";
printf("%s\n", strcaT(a, b));
return 0;
}
char *strcaT(char *t, const char *s) {
char *p = t;
/* find the end of the first string */
while (*p) {
*p++;
}
/* copy the second string at the end */
while (*s) {
*p++ = *s++;
}
*p = '\0'; /* set the null terminator */
return t;
}
It is a very bad idea to return some local variable, it will be cleared after the function finishes its operation. The following function should work.
char* strcaT(char *t, char *s)
{
char *res = (char*) malloc(sizeof(char) * (strlen(t) + strlen(s) + 1));
int count = 0;
for (int i = 0; t[i] != '\0'; i++, count++)
res[count] = t[i];
for (int i = 0; s[i] != '\0'; i++, count++)
res[count] = s[i];
res[count] = '\0';
return res;
}
In the main function
char *strcaT();
It should be declared before main function:
char *strcaT(char *t, char *s);
int main() {...}
You returns the local array buffer[], it's is undefined behavior, because out of strcaT function, it maybe does not exist. You should use the pointer then allocate for it.
The size of your buffer should be +1 not -1 as you did in your code.
char *strcaT(char *t, char *s) {
char *a = malloc(strlen(t) + strlen(s) + 1);
if (!a) {
return NULL;
}
int i;
for(i = 0; t[i] != '\0'; i++) {
a[i] = t[i];
}
for(int j = 0; s[j] != '\0'; j++,i++) {
a[i] = s[j];
}
a[i] = '\0';
return a;
}
The complete code for test:
#include <stdio.h>
#include <stdlib.h>
char *strcaT(char *t, char *s);
int main() {
char *a = "first";
char *b = "second";
char *str = strcaT(a, b);
if (str != NULL) {
printf("%s\n", str);
free(str); // Never forget freeing the pointer to avoid the memory leak
}
return 0;
}
char *strcaT(char *t, char *s) {
char *a = malloc(strlen(t) + strlen(s) + 1);
if (!a) {
return NULL;
}
int i;
for(i = 0; t[i] != '\0'; i++) {
a[i] = t[i];
}
for(int j = 0; s[j] != '\0'; j++,i++) {
a[i] = s[j];
}
a[i] = '\0';
return a;
}
For starters the function strcaT should append the string specified by the second parameter to the end of the string specified by the first parameter. So the first parameter should point to a character array large enough to store the appended string.
Your function is incorrect because at least it returns a (invalid) pointer to a local variable length character array that will not be alive after exiting the function and moreover the array has a less size than it is required to store two strings that is instead of
char buffer[strlen(t) + strlen(s) - 1];
^^^
it should be declared at least like
char buffer[strlen(t) + strlen(s) + 1];
^^^
and could be declared as static
static char buffer[strlen(t) + strlen(s) + 1];
Also the nested loops do not make sense.
Pay attention that you should provide the function prototype before calling the function. In this case the compiler will be able to check passed arguments to the function. And the name of the function strcaT is confusing. At least the function can be named like strCat.
The function can be defined the following way
#include <stdio.h>
#include <string.h>
char * strCat( char *s1, const char *s2 )
{
char *p = s1 + strlen( s1 );
while ( ( *p++ = *s2++ ) );
return s1;
}
int main(void)
{
enum { N = 14 };
char s1[N] = "first";
char *s2 = "second";
puts( strCat( s1, s2 ) );
return 0;
}
The program output is
firstsecond
On the other hand if you are already using the standard C function strlen then why not to use another standard C function strcpy?
With this function your function could be defined more simpler like
char * strCat( char *s1, const char *s2 )
{
strcpy( s1 + strlen( s1 ), s2 );
return s1;
}
If you want to build a new character array that contains two strings one appended to another then the function can look for example the following way.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char * strCat( const char *s1, const char *s2 )
{
size_t n1 = strlen( s1 );
char *result = malloc( n1 + strlen( s2 ) + 1 );
if ( result != NULL )
{
strcpy( result, s1 );
strcpy( result + n1, s2 );
}
return result;
}
int main(void)
{
char *s1 = "first";
char *s2 = "second";
char *result = strCat( s1, s2 );
if ( result ) puts( result );
free( result );
return 0;
}
Again the program output is
firstsecond
Of course calls of the standard C function strcpy you can substitute for your own loops but this does not make great sense.
If you are not allowed to use standard C string functions then the function above can be implemented the following way.
#include <stdio.h>
#include <stdlib.h>
char * strCat( const char *s1, const char *s2 )
{
size_t n = 0;
while ( s1[n] != '\0' ) ++n;
for ( size_t i = 0; s2[i] != '\0'; )
{
n += ++i;
}
char *result = malloc( n + 1 );
if ( result != NULL )
{
char *p = result;
while ( ( *p = *s1++ ) != '\0' ) ++p;
while ( ( *p = *s2++ ) != '\0' ) ++p;
}
return result;
}
int main(void)
{
char *s1 = "first";
char *s2 = "second";
char *result = strCat( s1, s2 );
if ( result ) puts( result );
free( result );
return 0;
}
I have changed your program to look like below:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main()
{
char* strcaT();
char* a = "first";
char* b = "second";
printf("%s",strcaT(a,b));
return 0;
}
char* strcaT(char *t, char *s)
{
char* a = (char*)malloc(sizeof(char)*(strlen(t) + strlen(s) + 1));
for(int i=0; i<strlen(t); i++) {
a[i] = t[i];
}
for(int i=0; i<strlen(s); i++) {
a[strlen(t) + i] = s[i];
}
a[strlen(t)+strlen(s)] = '\0';
return a;
}
You are getting segfault because you are returning address of a local array which is on stack and will be inaccessible after you return. Second is that your logic is complicated to concatenate the strings.
I'm trying to concatenate two strings using pointer in C, but it doesn't work 100%. At the end of the output String, many unknown characters appear...
char* concat_string (char* s1, char* s2) {
char *s;
int k=0;
s=(char *)malloc((strlen(s1)+strlen(s2))*sizeof(char));
while (*s1!='\0') {
*(s+k)=*s1;
k++;
s1++;
}
while (*s2!='\0') {
*(s+k)=*s2;
k++;
s2++;
}
return s;
}
int main () {
char *ch1, *ch2, *s;
char cch1[10], cch2[10];
printf("ch1 ? ");
scanf("%s",cch1);
printf("ch2 ? ");
scanf("%s",cch2);
ch1=cch1;
ch2=cch2;
s=concat_string(ch1, ch2);
printf("\n%s + %s = ", ch1, ch2);
while (*s!='\0') {
printf("%c", *s);
s++;
}
}
You're not including space for the terminator in the concatenated result. This:
s=(char *)malloc((strlen(s1)+strlen(s2))*sizeof(char));
should be:
s = malloc(strlen(s1) + strlen(s2) + 1);
You're not copying the terminator either, which explains the result you're seeing.
Also, don't cast malloc()'s return value in C, and make your input strings const.
Your code is very hard to read. The use of an integer indexing variable instead of just using pointers makes it needlessly complicated. For reference, here's how I would write it:
char * concat_string(const char *s1, const char *s2)
{
char *s = malloc(strlen(s1) + strlen(s2) + 1);
if(s != NULL)
{
char *p = s;
while((*p++ = *s1++) != '\0');
--p;
while((*p++ = *s2++) != '\0');
}
return s;
}
This is of course still somewhat terse, but I'd argue it's more readable than your version.
printf expects null terminated strings. Otherwise, it will print whatever characters in memory until it hits one. Your concat_string function doesn't put a null terminator on the string.
char* concat_string (char* s1, char* s2){char *s;int k=0;
s=(char *)malloc((strlen(s1)+strlen(s2))*sizeof(char));
while(*s1!='\0'){*(s+k)=*s1;k++;s1++; }
while(*s2!='\0'){*(s+k)=*s2;k++;s2++;}
*(s+k) = 0;
return s;
}
Also, this function is already written for you, just try using strcat.
I have to make a function which concatenates two strings but I have to add a '\n' after the first word. I figured everything out and for some reason it doesn't print out anything. Any ideas? It probably has to do something with the pointers. I just can't get my head around them. Here's the code.
char *function(char *s1, char *s2){
char *newStr;
int size;
size = strlen(s1) + strlen(s2);
newStr = (char *)malloc((size+1)*sizeof(char));
while(*s1!= '\0'){
*newStr = *s1;
newStr++;
s1++;
}
*newStr = '\n';
newStr++;
while(*s2 != '\0'){
*newStr = *s2;
newStr++;
s2++;
}
*newStr = '\0';
return newStr;
}
int main (int argc, const char * argv[]) {
char *str1 = "Hello";
char *str2 = "World";
printf("%s",function(str1, str2));
return 0;
}
So as a result I should get:
Hello
World
but I'm not getting anything back.
You are returning a pointer to the end of the buffer rather than a pointer to the start of the buffer. Look at the last two lines of the function:
*newStr = '\0';
return newStr;
Clearly this returns a pointer to the null char, i.e. the empty string.
Solve the problem by introducing a temporary pointer which you will use to step through the output buffer. Then you can return the pointer to the beginning of the output buffer.
char *function(char *s1, char *s2){
int size = strlen(s1) + strlen(s2) + 2;//one for '\n', one for '\0'
char *result = malloc(size);
char *p = result;
while(*s1 != '\0'){
*p = *s1;
p++;
s1++;
}
*p = '\n';
p++;
while(*s2 != '\0'){
*p = *s2;
p++;
s2++;
}
*p = '\0';
return result;
}
You also need to allocate an extra char for the \n, as shown above. Finally, your calling code never frees the memory allocated by function.
I would take a look at two things:
how much space you're allocating for the new string, and compare that with how many characters you're actually writing to that string.
where in the string your returned pointer is pointing to.
You return from function() a pointer to the last element in the allocated char[] – instead of returning the pointer to the first element.
Every time you do newStr++; you increase the actual pointer you later return. to solve it you can do one of these:
create a copy of the pointer newStr, which is initialized to be the same as newStr and increase it - leave newStr as it is.
create an index [let it be i] and increase it, and use newStr[i] to access the allocated array.
I have debugged the code for you. Here is the debugged code:
char *function(char *s1, char *s2) {
char *newStr, *str;
int size;
size = strlen(s1) + strlen(s2);
newStr = (char *) malloc((size + 2) * sizeof(char));
str = newStr;
while (*s1 != '\0') {
*(newStr++) = *(s1++);
}
*newStr = '\n';
newStr++;
while (*s2 != '\0') {
*newStr = *s2;
newStr++;
s2++;
}
*newStr = '\0';
return str;
}
int main(int argc, const char *argv[]) {
char *str1 = "Hello";
char *str2 = "World";
printf("%s", function(str1, str2));
return 0;
}
The actual problem was that as you incremented newStr until the last, when you returned it from function() it was pointing to the end of the buffer. ie '\0'. That is why it didn't show up. Now In the above code I have introduced a variable str that points at the beginning of the string newStr.
Hope you understood..
Peace...
Im trying to remove the first char of the string and keep the remainder, my current code doesnt compile and im confused on how to fix it.
My code:
char * newStr (char * charBuffer)
{
int len = strlen(charBuffer);
int i = 1;
char v;
if(charBuffer[0] == 'A' || charBuffer[0] == 'Q'){
for(i=1;i<len;i++)
v = v + charBuffer[i];
}
v = v + '\0';
return v;
}
Gcc: "Warning: return makes pointer from integer without a cast"
Also: "char * newStr (char * charBuffer)" needs to remain the same.
Strings don't work like this in C. You're summing up all of the characters in the buffer into the v variable. You can't use + to concatenate. The code you posted has some serious problems which indicate that there's an understanding gap with how to use C.
Try this:
char *newStr (char *charBuffer) {
int length = strlen(charBuffer);
char *str;
if (length <= 1) {
str = (char *) malloc(1);
str[0] = '\0';
} else {
str = (char *) malloc(length);
strcpy(str, &charBuffer[1]);
}
return str;
}
or this:
char *newStr (char *charBuffer) {
char *str;
if (strlen(charBuffer) == 0)
str = charBuffer;
else
str = charBuffer + 1;
return str;
}
Depending on whether you want to allocate a new string or not. You'll also have to add the code for handling the cases that don't start with 'Q' or 'A'. I didn't include those because I'm not sure exactly what you're trying to do here.
Make sure you do some research into allocating and deallocating memory with malloc and free. These are fundamental functions to be able to use if you're going to be doing C programming.
Well, your description says you want to deal with "strings", but you code deals with char buffers/pointers. The simplest approach to remove the first character for strings would be
const char *newStr(const char *string)
{
return string+1;
}
but as that doesn't look at all like what your code is doing, you probabaly want something different. For example, if you want to just remove a leading 'A' or 'Q' and then copy the string to a buffer, you want something like
char *newStr(const char *string)
{
if (string[0] == 'A' || string[0] == 'Q')
string++;
return strdup(string);
}
You can simply move your char pointer one character in:
char* newstring = oldstring + 1;
Your function is declared to return a char * and you are returning a char.
Furthermore, why don't you just return a pointer to the second character?
char * newStr (char * charBuffer)
{
if (charBuffer && (*charBuffer == 'A' || *charBuffer == 'Q')) return charBuffer + 1;
return charBuffer;
}
Several of the other answers recommended returning charBuffer + 1. As I noted in my previous comment:
This is bad practice. What if the string is dynamically allocated? Perhaps eventually the storage will be freed (starting from the second character). The string should be copied to new storage first.
Freeing a piece of storage from the middle will result in undefined behavior.
Instead, try the strdup function which will return a duplicate of the given string.
#include <string.h>
#include <stdio.h>
char *newStr(char* charBuffer) {
if (charBuffer && (charBuffer[0] == 'A' || charBuffer[0] == 'Q'))
return strdup(charBuffer + 1);
else
return strdup(charBuffer);
}
void main() {
char a[7] = "Advait";
char b[5] = "John";
printf("%s\n",newStr(a)); // Prints "dvait"
printf("%s\n",newStr(b)); // Prints "John"
}
How can I strip a string with all \n and \t in C?
This works in my quick and dirty tests. Does it in place:
#include <stdio.h>
void strip(char *s) {
char *p2 = s;
while(*s != '\0') {
if(*s != '\t' && *s != '\n') {
*p2++ = *s++;
} else {
++s;
}
}
*p2 = '\0';
}
int main() {
char buf[] = "this\t is\n a\t test\n test";
strip(buf);
printf("%s\n", buf);
}
And to appease Chris, here is a version which will make a place the result in a newly malloced buffer and return it (thus it'll work on literals). You will need to free the result.
char *strip_copy(const char *s) {
char *p = malloc(strlen(s) + 1);
if(p) {
char *p2 = p;
while(*s != '\0') {
if(*s != '\t' && *s != '\n') {
*p2++ = *s++;
} else {
++s;
}
}
*p2 = '\0';
}
return p;
}
If you want to replace \n or \t with something else, you can use the function strstr(). It returns a pointer to the first place in a function that has a certain string. For example:
// Find the first "\n".
char new_char = 't';
char* pFirstN = strstr(szMyString, "\n");
*pFirstN = new_char;
You can run that in a loop to find all \n's and \t's.
If you want to "strip" them, i.e. remove them from the string, you'll need to actually use the same method as above, but copy the contents of the string "back" every time you find a \n or \t, so that "this i\ns a test" becomes: "this is a test".
You can do that with memmove (not memcpy, since the src and dst are pointing to overlapping memory), like so:
char* temp = strstr(str, "\t");
// Remove \n.
while ((temp = strstr(str, "\n")) != NULL) {
// Len is the length of the string, from the ampersand \n, including the \n.
int len = strlen(str);
memmove(temp, temp + 1, len);
}
You'll need to repeat this loop again to remove the \t's.
Note: Both of these methods work in-place. This might not be safe! (read Evan Teran's comments for details.. Also, these methods are not very efficient, although they do utilize a library function for some of the code instead of rolling your own.
Basically, you have two ways to do this: you can create a copy of the original string, minus all '\t' and '\n' characters, or you can strip the string "in-place." However, I bet money that the first option will be faster, and I promise you it will be safer.
So we'll make a function:
char *strip(const char *str, const char *d);
We want to use strlen() and malloc() to allocate a new char * buffer the same size as our str buffer. Then we go through str character by character. If the character is not contained in d, we copy it into our new buffer. We can use something like strchr() to see if each character is in the string d. Once we're done, we have a new buffer, with the contents of our old buffer minus characters in the string d, so we just return that. I won't give you sample code, because this might be homework, but here's the sample usage to show you how it solves your problem:
char *string = "some\n text\t to strip";
char *stripped = strip(string, "\t\n");
This is a c string function that will find any character in accept and return a pointer to that position or NULL if it is not found.
#include <string.h>
char *strpbrk(const char *s, const char *accept);
Example:
char search[] = "a string with \t and \n";
char *first_occ = strpbrk( search, "\t\n" );
first_occ will point to the \t, or the 15 character in search. You can replace then call again to loop through until all have been replaced.
I like to make the standard library do as much of the work as possible, so I would use something similar to Evan's solution but with strspn() and strcspn().
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define SPACE " \t\r\n"
static void strip(char *s);
static char *strip_copy(char const *s);
int main(int ac, char **av)
{
char s[] = "this\t is\n a\t test\n test";
char *s1 = strip_copy(s);
strip(s);
printf("%s\n%s\n", s, s1);
return 0;
}
static void strip(char *s)
{
char *p = s;
int n;
while (*s)
{
n = strcspn(s, SPACE);
strncpy(p, s, n);
p += n;
s += n + strspn(s+n, SPACE);
}
*p = 0;
}
static char *strip_copy(char const *s)
{
char *buf = malloc(1 + strlen(s));
if (buf)
{
char *p = buf;
char const *q;
int n;
for (q = s; *q; q += n + strspn(q+n, SPACE))
{
n = strcspn(q, SPACE);
strncpy(p, q, n);
p += n;
}
*p++ = '\0';
buf = realloc(buf, p - buf);
}
return buf;
}