Strings with malloc in C - c

I am writing a very simple program to copy a string using malloc.
#include <stdio.h>
#include <stdlib.h>
char * copyStr(char s[])
{
int len = strlen(s); //find length of s
char * copy;
copy = (char *)malloc(len); //dynamically allocate memory
int i;
for(i=0;i<len;i++)
{
copy[i]=s[i]; //copy characters
}
return copy; //return address
}
int main(int argc, char ** argv)
{
char * str;
str = "music is my aeroplane";
char * res;
res = copyStr(str);
printf("The copied string is : %s",res);
getch();
}
The desired output is:
The copied string is : music is my aeroplane
The current output is:
The copied string is : music is my aeroplaneOMEeJ8«≤╝
Any advice is appreciated.

A C string is null terminated. Add a null character (ie the char which ASCII code is 0) at end of the string :
char * copyStr(char s[])
{
size_t len = strlen(s); //find length of s
char * copy;
copy = (char *)malloc(len + 1); //dynamically allocate memory
/* One more char must be allocated for the null char */
size_t i;
for(i=0;i<len;i++)
{
copy[i]=s[i]; //copy characters
}
copy[i] = '\0'; // HERE
return copy; //return address
}
It is better to use size_t for the lengths because it is unsigned.

Strings in C are null-terminated.
The C programming language has a set of functions implementing
operations on strings (character strings and byte strings) in its
standard library. Various operations, such as copying, concatenation,
tokenization and searching are supported. For character strings, the
standard library uses the convention that strings are null-terminated:
a string of n characters is represented as an array of n + 1 elements,
the last of which is a "NUL" character.
In this case, you should have enough memory to store the original string contents and the "NUL" character (length+1). And don't forget to ensure the presence of the "NUL" character after the end of the string.
There are many possible ways to implement char * copyStr(char[]) function:
1) Your way (corrected):
char * copyStr(char s[])
{
int i;
size_t len = strlen( s );
char * p = (char*) malloc( len + 1 );
for( i = 0; i < len; i++ )
p[i] = s[i];
p[i] = '\0';
return p;
}
2) Using memcpy():
char * copyStr(char s[])
{
size_t len = strlen( s );
char * p = (char*) malloc( len + 1 );
memcpy( p, s, len );
p[ len ] = '\0';
return p;
}
3) Using strcpy():
char * copyStr(char s[])
{
size_t len = strlen( s );
char * p = (char*) malloc( len + 1 );
strcpy( p, s );
return p;
}
4) Using strdup():
char * copyStr(char s[])
{
return strdup(s);
}
Note: For every malloc() function call you need a free() function call, your main() needs a little modification for correctness:
int main( int argc, char ** argv )
{
char * str;
char * res;
str = "music is my aeroplane";
res = copyStr( str );
printf( "The copied string is : %s", res );
free(res); /* freedom */
getch();
return 0;
}
Hope it Helps!

Related

How do I create an array based off an existing array where each element of the new array copies the original array until the first tab character in C

I have an array of strings read from a file. I'd like to take each string in the existing array and copy it to a new array unit the first instance of a tab character, and then move to the next element in the array.
What would be the best way to do this?
Thanks
You can use standard C function strchr. For example if you have two character arrays like
char s1[12] = "Hello\tWorld";
char s2[12];
then you can write
char *p = strchr( s1, '\t' );
if ( p != NULL )
{
memcpy( s2, s1, p - s1 );
s2[p - s1] = '\0';
}
else
{
strcpy( s2, s1 );
}
For two dimensional arrays you can do the same in a loop.
You could create a function until_tabs that takes an array of strings and the array's length. Then we allocate a same sized array of char pointers and iterate over the original array.
For each string input we can use strchr to look for a tab. If it's absent, just duplicate the string with strdup. Otherwise allocate an adequately sized buffer for the new string and copy everything before '\t' into it with strncpy.
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
char **until_tabs(char **strings, size_t n) {
char **result = malloc(sizeof(char *) * n);
for (size_t i = 0; i < n; i++) {
char *tab = strchr(strings[i], '\t');
if (!tab) {
result[i] = strdup(strings[i]);
continue;
}
size_t size = tab-strings[i];
result[i] = malloc(size+1);
strncpy(result[i], strings[i], size);
result[i][size] = '\0';
}
return result;
}
int main(void) {
char *arr[] = {"hello", "world", "foo\tbar"};
char **arr2 = until_tabs(arr, 3);
for (size_t i = 0; i < 3; i++) {
printf("%s\n", arr2[i]);
}
return 0;
}
Output:
hello
world
foo
For each string in the array of strings:
Find the length of the string, but only up to a potential '\t'
size_t length == strcspn(source_string, "\t");
Allocated needed memory
char *destination_string = malloc(length + 1); // +1 for the null character.
if (destination_string == NULL) Handle_Allocation_Error();
Copy it
memcpy(destination_string, source_string, length);
destination_string[length] = '\0';
// or
sprintf(destination_string, ".*s", (int) length, source_string);
// or
strncpy(destination_string, source_string, length);
destination_string[length] = '\0';

Can't print string after reverse in C

I'm writing this function to return a char pointer of reversed string.
void * PreverseStr (char str[])
{
int size = strlen (str);
char *returnstr = (char *)malloc (size * sizeof(char));
for (int i = size - 1; i >= 0 ; i--)
{
*returnstr = str[i];
returnstr ++;
}
returnstr = 0;
returnstr -= size;
return returnstr ;
}
To test this function I wrote a main function like this
int main()
{
char str[] = "abcdefghijklmnopqrstuvwxyz";
char *newstr = PreverseStr(str);
printf("Reversed string using pointer: %s\n", newstr);
free(newstr);
return 0;
}
But it crashes before it could print out anything. I wonder what's wrong with my code. It would be much helpful if you can explain a fix to this.
For starters the return type void * makes no sense. The return type should be char *. As the function creates a new string without changing the source string then the function parameter should have the qualifier const.
This memory allocation
char *returnstr = (char *)malloc (size * sizeof(char));
allocates not enough space tp store the terminating zero character '\0' of the source string.
You need to write at least
char *returnstr = (char *)malloc ( ( size + 1 ) * sizeof(char));
After the for loop the pointer returnstr points to beyond the allocated memory because it is increased within the loop
returnstr ++;
Moreover after this assignment
returnstr = 0;
it becomes a null pointer.
The function can be declared and defined the following way
char * reverse_copy( const char s[] )
{
size_t n = strlen( s );
char *p = malloc( n + 1 );
if ( p != NULL )
{
p += n;
*p = '\0';
while ( n-- )
{
*--p = *s++;
}
}
return p;
}
Here is a demonstration program.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *reverse_copy( const char s[] )
{
size_t n = strlen( s );
char *p = malloc( n + 1 );
if (p != NULL)
{
p += n;
*p = '\0';
while (n--)
{
*--p = *s++;
}
}
return p;
}
int main( void )
{
const char *s = "Hello, World!";
puts( s );
char *p = reverse_copy( s );
if (p) puts( p );
free( p );
}
Its output is
Hello, World!
!dlroW ,olleH

when printing a char* in C only the first character is being printed

I'm trying to write a function that will print out a substring of string however when printing it, only the first character in the array is printed.
As you can see in the code I've put a printf statement in the function after the substring is created and it displays properly. However when the function is passed into a printf function in the main function it only prints the first character.
Thanks for any help people are able to provide.
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
char *ft_substr (const char *s, unsigned int start, size_t len)
{
char *str;
unsigned int i;
unsigned int j;
str = malloc(len * sizeof(char) + 1);
i = start;
j = 0;
while (i < len + start)
{
str[j] = s[i];
j++;
i++;
}
str[j + 1] = '\0';
printf("%s\n", str);
free(str);
return (str);
}
int main (void)
{
char hello[] = "Hello World";
char sub = *ft_substr(hello, 1, 4);
printf("%s\n", &sub);
return (0);
}
Before returning the pointer str from the function you freed all the allocated memory
free(str);
return (str);
So the returned pointer is invalid.
Remove the statement
free(str);
Another problem in the function is using an incorrect index in this statement
str[j + 1] = '\0';
Just write
str[j] = '\0';
Also this declaration is incorrect
char sub = *ft_substr(hello, 1, 4);
It declares a single character while you need to declare a pointer that will point to the dynamically allocated string in the function. So write
char *sub = ft_substr(hello, 1, 4);
and then write
printf("%s\n", sub);
free( sub );
And if you are using the type size_t for the length of a string then use indices also of the type size_t.
Here is a demonstrative program.
#include <stdio.h>
#include <stdlib.h>
char * ft_substr( const char *s, size_t start, size_t len )
{
char *str = malloc( len + 1 );
if ( str != NULL )
{
size_t i = 0;
for ( ; i < len; i++ )
{
str[i] = s[start + i];
}
str[i] = '\0';
}
return str;
}
int main(void)
{
const char *hello= "Hello World";
char *sub = ft_substr( hello, 1, 4 );
if ( sub != NULL ) puts( sub );
free( sub );
return 0;
}
Its output is
ello
The function will be more safer if it will check whether the starting index and the length are specified correctly. For example
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char * ft_substr( const char *s, size_t start, size_t len )
{
char *str = NULL;
size_t n = strlen( s );
if ( start < n )
{
if ( n - start < len ) len = n - start;
str = malloc( len + 1 );
if ( str )
{
memcpy( str, s + start, len );
str[len] = '\0';
}
}
return str;
}
int main(void)
{
const char *hello= "Hello World";
char *sub = ft_substr( hello, 1, 4 );
if ( sub != NULL ) puts( sub );
free( sub );
return 0;
}
You have UB in your main. Yout try to print as string a single character (passed as reference).
int main (void)
{
char hello[] = "Hello World";
char *sub = ft_substr(hello, 1, 4);
printf("%s\n", sub?sub:"");
free(sub);
return (0);
}

My own strcat function with pointers does not work right

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.

character concatenation in C

I want to do in C, what can be achieved in Java as follows
String str = "hello";
System.out.println(str + 'a');
I have written the following.
1. It doesn't work
2. Is there an easier way to do this in C, something that can be achieved in java in a single line.
#include <stdio.h>
char* charcat(char str[], char c);
int main(void)
{
char str[] = "hello";
printf("%s\n",charcat(str,'a'));
}
char* charcat(char str[], char c)
{
char newstr[] = {c,'\0'};
char temp[20];
strcpy(temp,str);
strcat(temp,newstr);
return temp;
}
EDIT :
I have edited based on ameyCU's response.
char* charcat(char str[], char c);
int main(void)
{
char str[] = "hello";
printf("%s\n",charcat(str,'a'));
}
char* charcat(char str[], char c)
{
char* temp;
char newstr[] = {c,'\0'};
temp = malloc((strlen(str) + 1)* sizeof(char));
strcpy(temp,str);
return strcat(temp,newstr);
}
EDIT 2:
char* charcat(char str[], char c);
int main(void)
{
char str[] = "hello";
char temp[20];
strcpy(temp,str);
printf("%s\n",charcat(temp,'a'));
}
char* charcat(char str[], char c)
{
char newstr[] = {c,'\0'};
return strcat(str,newstr);
}
I think what you were trying to do was this:
char* charcat(char str[], char c)
{
char newstr[] = {c,'\0'};
char *temp=(char *)malloc((strlen(str)+1+1)*sizeof(char));
strcpy(temp,str);
strcat(temp,newstr);
return temp;
}
make sure you free() the pointer.
You can use strcat() function
char str1[20]="hello";
strcat(str1,"c");
printf("%s",str1);
Problem is that you return a local variable.
return temp;
temp is local variable and its scope is just inside the function it is declared.
After concatenation -strcat(temp,newstr);
You can do this -
strcpy(str,temp);
return str;
But this will also change the contents of original array.
EDIT
To keep original array intact assign a pointer to string in function and return the pointer .
And also to use functions like strcpy and strcat you need to include string.h header.
This uses snprintf() to get the required length for the target string. Memory is allocated and then snprintf() creates the target string.
#include<stdio.h>
#include<stdlib.h>
char* charcat(char str[], char c);
int main ( ) {
char str[] = "hello";
char *output = NULL;
printf ( "str-> %s\n\n", str);
if ( ( output = charcat ( str, 'a'))) {//successful return of pointer
printf ( "output-> %s\n", output);
free ( output);//release memory
}
return 0;
}
char* charcat(char str[], char c)
{
char *temp = NULL;
int length = 0;
length = snprintf ( NULL, 0, "%s%c", str, c);//get required length
if ( ( temp = malloc ( length + 1))) {//allocate plus one for '\0'
snprintf ( temp, length + 1, "%s%c", str, c);//malloc succeeds make target
}
return temp;
}
It is always better to use strncat() instead of strcat to avoid buffer overflows.
#include <cstdio>
#include <cstring>
int main ()
{
char str[20] = "hello";
strncat (str, "a", sizeof(str) - strlen(str) - 1);
printf("%s",str);
return 0;
}
Output:
helloa
RUN SUCCESSFUL (total time: 49ms)
Something like Java in a single line
// String str = "hello";
// System.out.println(str + 'a');
const char *str = "hello";
printf("%s%c\n", str, 'a');
Or is one wants to print a concatenated string, we need to do memory management.
char *charcatconst char *src, int ch) {
size_t len = strlen(src);
char *s = memcpy(malloc(len+2), src, len); // Out-of-memory check omitted.
s[len] = ch;
s[len+1] = '\0';
return s;
}
// simple usage, but a memory leak
puts(charcat("hello", 'a'));
// Better to free memory explicitly
char *s = charcat("hello", 'a');
puts(s);
free(s);

Resources