I wanted to make a simple str_join function in C (to learn a bit more about pointers and arrays), which literally joins two string together.
#include <stdio.h>
#include <stdlib.h>
int str_size(char *str);
void str_join(char *str1, char *str2);
int main(int argc, char **argv)
{
char *part1 = "Hello ";
char *part2 = "World!";
str_join(part1, part2);
printf("%s\n", part1);
return 0;
}
int str_size(char *str)
{
char c;
for(int i = 0;; i++)
{
c = str[i];
if(c == '\0')
return i + 1;
}
}
void str_join(char *str1, char *str2)
{
int str_size_1 = str_size(str1) - 1; //Last char is '\0', don't need them 2 times
int str_size_2 = str_size(str2);
char str3[str_size_1 + str_size_2];
int i;
for(i = 0; i < str_size_1; i++)
str3[i] = str1[i];
for(i = 0; i < str_size_2; i++)
str3[i + str_size_1] = str2[i];
str1 = (char *)str3;
}
It looks simple (maybe too simple).
I excepted the output to be:
Hello World
but it looks like:
Hello
I compiled the program using following command:
gcc main.c -o main
And ran it:
./main
I don't see my failure, could someone point me to my error?
Thank you for helping me out!
In C, function arguments are passed by value. Any changes made to any parameter from inside the function is will not reflect to the caller (actual argument).
So, in your case, str1 = (char *)str3;, does not do what you think it does.
That said, wait, stop!! str3 is a VLA and lifetime is the block scope. You cannot possibly return the address of the first element and expect that to be valid outside the scope for accessing the memory location(s). You need to allocate memory in such a way that it outlives its scope., You have to either
use an array with static storage (cannot be combined with VLAs)
use memory allocator function
You are not returning the pointer you think you are returning from the function.
str1 = (char *)str3;
You seem to assume that this changes str1 so that it points to the (correctly) joined string str3, but this change is not visible outside of the function.
You can fix this in (at least) two ways:
1) Allocate with malloc
char *str3 = malloc(str_size_1 + str_size_2);
And then return this pointer from the function (instead of void)
or 2)
pass a pointer to the pointer to the function, like this
void str_join(char **str1, char *str2)
And then
*str1 = str3;
The objective you wish to achieve is done with the help of call by reference method of the function calling method. But in your code, the str_join is a call by value function. When you change the value of str1 it is changed just for the scope of the function. As, soon as you come out of the str_join scope the value of str1 is again changed to the earlier one, becuase what you are passing to the function is not the address of str1 but a copy of the value of str1. You should try this instead :
void str_join(char **str1, char **str2)
// though the str2 need not to be passed by reference you can leave it as it is now
Replace the str1 inside the function with *str1
Then you can call it in your main function as : str_join(&str1, &str2)
The & sign signifies that you are passing the address of str1 and str2
I'm sure that there are many ways of implementing what is required here. A reasonably idiomatic way in C would be to create a new dynamically-allocated string large enough to hold both the original strings, and return that to the caller.
#include <stdio.h>
#include <string.h>
#include <malloc.h>
char *str_join(char *str1, char *str2)
{
char *result = malloc (strlen (str1) + strlen (str2) + 1);
strcpy (result, str1);
strcat (result, str2);
return result;
}
int main(int argc, char **argv)
{
char *part1 = "Hello ";
char *part2 = "World!";
char *joined = str_join(part1, part2);
printf("%s\n", joined);
free (joined);
return 0;
}
The caller will have to call free() on the result. It's reasonable common practice to assume that any function that returns a "char *" is returning something that has to be freed, whilst a function that returns a "const char *" is returning something that doesn't need to be freed. A number of basic, long-standing functions in the C standard library don't follow this convention, however.
Related
this program it suppose to print Hello World but guess what exited, segmentation fault why is that happening ?
#include <stdio.h>
#include <string.h>
char f(char *a, char *b)
{
int i , m, n;
m = strlen(a);
n = strlen(b);
for (i = 0; i<=n; i++)
{
a[m+i] = b[i];
}
}
int main() {
char*str1 = "hello ";
char*str2 = "world!";
str1=f(str1, str2);
printf("%s", str1);
return 0;
}
You are not allowed to modify string literals. Use arrays with enough elements instead for strings to be modified.
Also assigning the return value of f to str1 is a bad idea because no return statement is executed in the function f and using its return value invokes undefined behavior. The return type should be changed to void if you are not going to return anything.
#include <stdio.h>
#include <string.h>
void f(char *a, char *b)
{
int i , m, n;
m = strlen(a);
n = strlen(b);
for (i = 0; i<=n; i++)
{
a[m+i] = b[i];
}
}
int main() {
char str1[16] = "hello ";
char*str2 = "world!";
f(str1, str2);
printf("%s", str1);
return 0;
}
First of all, this:
char*str1 = "hello ";
is a pointer to constant data, which means that you can't change the string "hello "
This is a constant pointer to variable data:
char str1[] = "hello ";
Which means that str1 always points to the same address in memory, but you can modify the content of that chunk of memory.
However str1 will have a fixed size of 7 characters (don't forget to count \0), so you can't append another string to it.
You could define a size #define SIZE 20 large enough to store both strings and declare
char str1[SIZE] = "hello ";
Or you could declare str1 as a VLA (variable length array) after having declared the string to append:
char*str2 = "world!";
char str1[strlen("hello ")+strlen(str2)+1] = "hello ";
Where the +1 is for \0.
Is it important that you copy characters one by one?
Because if it's not you can just copy one string to another like this.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main() {
char str1[] = "hello ";
char str2[] = "world!";
char *result = malloc(strlen(str1) + strlen(str2) + 1);
strcpy(result, str1);
strcat(result, str2);
printf("%s", result);
return 0;
}
First you are not allowed to change a constant string, that is undefined behaviour.
Secondly your f function has no return statement and thus returns random data, making the str1 variable in main point to random memory. Using it then also has undefined behaviour.
To fix it you should allocate new memory and concatenate the string into that
char* f(const char *s1, const char *s2)
{
char *s = malloc(strlen(s1) + strlen(s2) +1);
if (s) {
strcpy(s, s1);
strcat(s, s2);
}
return s;
}
The extra one byte allocated is for the terminating zero.
Both arguments are const as there is no reason to modify them, which allows both arguments to be literal strings.
For starters you may not change string literals (in this case the string literal pointed to by the pointer str1).
char*str1 = "hello ";
char*str2 = "world!";
Any attempt to change a string literal results in undefined behavior.
You need to allocate a character array large enough to store the result string with the appended string literal pointed to by the pointer str2.
Secondly there is already the standard C function strcat that performs the required task. If you have to write such a function yourself then it seems you should not use any string function as for example strlen.
And the return type char of your function does not make a sense. And moreover actually your function returns nothing.
So this assignment
str1=f(str1, str2);
results in undefined behavior.
The function and the program in whole can be written the following way without using standard string functions.
#include <stdio.h>
char * f( char *s1, const char *s2 )
{
char *p = s1;
while ( *p ) ++p;
while ( ( *p++ = *s2++ ) );
return s1;
}
int main(void)
{
char s1[14] = "Hello ";
char *s2 = "World!";
puts( f( s1, s2 ) );
return 0;
}
The program output is
Hello World!
Pay attention to that the second function parameter shall have the qualifier const because the pointed string is not changed within the function. And the function return type should be char * that is the function should return the result string.
I need to store the memory address of a string in an int pointer out parameter. I've created the code below to test the implementation.
void getMemAddress (int *a) {
char str[80] = "Hello world";
a = (int*)&str; // Assign memory address of str to a
printf("%s", (char*)a);
}
int main(int argc, const char * argv[]) {
int *memaddress;
getMemAddress(memaddress);
printf("%s", (char*)memaddress);
return 0;
}
printf("%s", (char*)a);
prints "Hello World" as it should but
printf("%s", (char*)memaddress);
prints null
How could I go about retrieving the actual memory address as using it to access the original string?
Thanks!
Parameters are passed by value in C. Similar issues have been answered countless times on stackoverflow.
You need this:
void getMemAddress (int **a) {
char str[80] = "Hello world";
*a = (int*)str; // Assign memory address of str to *a
printf("%s", (char*)*a);
}
int main(int argc, const char * argv[]) {
int *memaddress;
getMemAddress(&memaddress);
printf("%s", memaddress);
return 0;
}
Casting a memory address to int won't work on a 64 bit system. On a 32 bit system it works, but it's not very clean.
Other problem. You are returning the address of a local variable that is on the stack. As soon as you leave the getMemAddress function the str buffer will be overwritten by following function calls (also a classic problem). Never return the address of a local variable.
You are assining the address of &str to your function-local copy of the pointer a. What you need is to modify getMemAddress so that it takes int **a as an argument, and assign it like this:
*a = (int *) str;
then in main:
int *memaddress;
getMemAddress(&memaddress);
And one more thing-- str only exists inside your function. Once you exit the function, you won't be able to access it. To fix this, make str a char pointer and use malloc to allocate some memory for it. Then use strcpy to insert your string.
To modify something in a function, you need to pass a pointer to the thing you want to modify.
In this case you want to modify a pointer, so you need to pass a pointer to the pointer.
void getMemAddress (int **a) { // <-------------- added a *
char str[80] = "Hello world";
*a = (int*)str; // <-------------- added a *
printf("%s", (char*)*a); // <-------------- added a *
}
int main(int argc, const char * argv[]) {
int *memaddress;
getMemAddress(&memaddress); // <-------------- added a &
printf("%s", (char*)memaddress);
return 0;
}
Also, &str should be &str[0] or just str.
Also, str is a local variable, so it will cease to exist once getMemAddress returns (and then the printf call in main will probably print garbage). You could make str static, or you could return a pointer to a string literal instead (char *str = "Hello world"; *a = (int*)str;).
I am trying to write a function that deletes a char c from a string src, and I am getting a seg fault when I try to run it. Here is the function.
void removeChar(char *src, char c){
int i, j = 0;
int size;
char ch1;
char str1[100];
size = strlen(src);
for (i = 0; i < size; i++){
if (src[i] != c){
ch1 = src[i];
str1[j] = ch1;
j++;
}
}
str1[j] = '\0';
src = str1;
}
And here is the main function where I am calling it.
int main(int argc, char **argv){
char *str = "Hello, world!\0";
printf("%s\n", removeChar(str, 'l'));
}
the return type of this function removeChar(str, 'l') is void not an char array and you are passing this to
printf("%s\n", removeChar(str, 'l'));
so here %s may give you the segmentation fault.
You assigned pointer src by the address of the first element of a local array
src = str1;
that will be destroyed after exiting the function. Moreover variable src is a local variable of the function so any changes of it do not influence the original pointer str.
Take into account that you may not change string literals. Any attempt to change a string literal results in undefined behaviour of the program.
Also the function has return type void and may not be used as an outputed object in function printf.
Type void is an incomplete type. It has no values.
And there is no need to append explicitly terminating zero to a string literal as you did.
"Hello, world!\0"
String literals already have terminating zeroes. So you could write simply
"Hello, world!"
As I already answered this question then you can visit my personal forum where there is a realization of the corresponding valid function.
If to declare correctly the function like
char * removeChar( char *s, char c );
then the main will look the following way
int main(int argc, char **argv)
{
char str[] = "Hello, world!";
printf( "%s\n", removeChar( str, 'l' ) );
}
You can print the string in the function itself! Then it works:
#include <stdio.h>
#include <string.h>
void removeChar(char src[], char c){
int i, j = 0;
int size;
char ch1;
char str1[100];
size = strlen(src);
for (i = 0; i < size; i++) {
if (src[i] != c) {
ch1 = src[i];
str1[j] = ch1;
j++;
}
}
str1[j] = '\0';
src = str1;
printf("%s\n", src);
}
int main(int argc, char **argv) {
char str[] = "Hello, world!";
removeChar(str, 'l');
return 0;
}
You have several bugs:
char *str = "Hello, world!\0";. Setting a non-constant pointer to point at a string literal is always wrong. Instead, declare the variable as const char *str. See this FAQ.
removeChar doesn't return anything so you can't pass it as a parameter to be printed by printf. Your compiler really should have complained here. Chances are that your compiler is misconfigured or you you aren't using it with all warnings enabled.
char str1[100]; You cannot use local variables and then try to pass the contents on to the caller. See this FAQ.
src = str1; doesn't do a thing, since src is only a local copy of the original pointer. With this assignment, you will not change the address of str in main. Which would have been a bug anyway, because of 3) above. You should rewrite your program so that is only uses src and no temporary array.
Not have enough reputation to comment. So, I had to write this on answer:
As Vlad from Moscow pointed out,
`a local array do not exist after the function terminate`
I suggest you obey the same principle as of standard library functions. If you didn't already notice,none string.h function allocate memory for the user. You must allocate before call.
char *str = "Hello, world!\0";
The above code do not guarantee a modifiable memory. The compiler can set them in read only memory. You should use a array instead.
I have the following program:
#include <stdio.h>
#define MAXLEN 100
char *my_strcat(char *strp1,char *strp2) {
char str[MAXLEN], *strp;
strp = str;
while (*strp1 != '\0') {
*strp++ = *strp1++;
}
while (*strp2 != '\0') {
*strp++ = *strp2++;
}
*strp = '\0';
strp = str;
return strp;
}
void test_strcat(void) {
char *strp1, *strp2, *strp3, str1[MAXLEN], str2[MAXLEN];
printf("Testing strcat! Give two strings:\n");
gets_s(str1, sizeof(str1));
gets_s(str2, sizeof(str2));
strp1 = str1;
strp2 = str2;
strp3 = my_strcat(strp1, strp2);
printf("Concatenated string: %s", strp3);
}
int main(void) {
test_strcat();
}
The function char *mystrcat is supposed to concatenate two strings, and I test it with
test_strcat. The program runs without errors but instead of printing the concatenated string a smiley symbol is printed. I have gone through the program with debugging and it
appears that the result sent back by my_strcat is the correct string. However, when
going into the last line where strp3 is supposed to be printed it appears red in the
debugging tool, implying that its value is about to change. After the printf call, strp3
no longer points to the concatenated string. Anyone knows what could be causing this error?
Here is the problem:
char str[MAXLEN], *strp;
strp = str; // str is a local variable
...
return strp; // <<== WRONG!!!
Since str is a local variable that disappears as soon as you return, the value pointed to by strp becomes invalid the instance the caller gets the control back.
Use malloc instead of allocating memory in the automatic storage area (i.e. on the stack) will fix this problem:
char *str = malloc(strlen(strp1)+strlen(strp2)+1);
char *strp = str;
I suggest you 2 ways as following.
first,
char *my_strcat(char *strp1,char *strp2) {
static char str[MAXLEN * 2]; /* from char str[MAXLEN] */
second,
char *my_strcat(char *strp1,char *strp2) {
char *str = malloc(strlen(strp1) + strlen(strp2) + 1);
because in my_strcat function, you allocated the str as auto variable.
When my_strcat function is finish, str will be freed.
so I was practicing writing c code with pointers using the K&R. For one problem with strcat function, I couldn't find out what was wrong with my code, which according to Visual Studio, returned the destination string unchanged after the strcat function. Any suggestion is appreciated!
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int strcat(char* s, char* t);
int main(void)
{
char *s="hello ", *t="world";
strcat(s,t);
printf("%s",s);
return 0;
}
int strcat(char* s,char* t)
{
int i;
i=strlen(s)+strlen(t);
s=(char*) malloc(i);
while(*s!='\0')
s++;
while('\0'!=(*s++=*t++))
;
return 0;
}
I'm pretty sure that strcat returns a char* in the real implementation (holding the original value of the first string).
strcat is not supposed to alter the first parameter's address, so you shouldn't call malloc.
Point #2 means that you need to declare char *s as char s[20] in main (where 20 is some arbitrary number big enough to hold the whole string).
If you really want to alter the value of the an input parameter you will need to pass the address of the value - so it would need to be strcat(char **s, ...) in the function declaration/definition, and called with strcat(&s, ...) in main.
1) defining string in this way
char *s="hello "
means that you are defined a literal string. a literal string is saved into read only memory so you can not edit it
you have to define your string as a char array in order to be able to edit it
char s[100] = "hello ";
2) when you define your function in this way
int strcat(char* s,char* t)
you can not change the address of s into the function strcat(). So assigning memory with malloc() into the function will not change the s address when leaving the function
3) change your function strcat to
int strcat(char** s,char* t)
{
int i;
char *u, *v;
i=strlen(*s)+strlen(t);
v = *s;
u=(char*) malloc(i+1);
while(*v!='\0')
*u++ = *v++;
while('\0'!=(*u++=*t++));
*s = u;
return 0;
}
and you call it in the main with:
char *s="hello ", *t="world";
strcat(&s,t);
In
strcat(char* s, char* t)
the 's' is send by value. The value of 's' at call time is copied into the stack then strcat() is call. At the return of strcat the modified version is discard from the stack. So the calling value of 's' is never changed (and you create a memory leak).
Beward, in C every memory cell can be change, even parameters or instructions sections; some changes can be very hard to understand.
Since you are trying to do like the real strcat it's said that the first parameter
The string s1 must have sufficient space to hold the result.
so you don't need to use malloc
char *strcat(char* s, const char* t);
int main(void)
{
char s[15] = {0}; //
char *t = "world"; //const char * so you can't change it
strcpy(s, "Hello ");
strcat(s,t);
printf("%s\n",s);
return (0);
}
char *strcat(char* s, const char* t)
{
int i = 0;
while (s[i] != '\0')
i++;
while (*t != '\0')
s[i++] = *t++;
s[i] = '\0'; //useless because already initialized with 0
return (s);
}
#include<stdio.h>
#include<string.h>
#define LIMIT 100
void strcatt(char*,char*);
main()
{
int i=0;
char s[LIMIT];
char t[LIMIT];
strcpy(s,"hello");
strcpy(t,"world");
strcatt(s,t);
printf("%s",s);
getch();
}
void strcatt(char *s,char *t)
{
while(*s!='\0')
{
s++;
}
*s=' ';
++s;
while(*t!='\0')
{
*s=*t;
s++;
t++;
}
*s=*t;
}
Dear user,
you don't have to complicate things that much. The simpliest code for strcat, using pointers:
void strcat(char *s, char *t) {
while(*s++); /*This will point after the '\0' */
--s; /*So we decrement the pointer to point to '\0' */
while(*s++ = *t++); /*This will copy the '\0' from *t also */
}
Although, this won't give you report about the concatenation's success.
Look at this main() part for the rest of the answer:
int main() {
char s[60] = "Hello ";
char *t = "world!";
strcat(s, t);
printf("%s\n", s);
return 0;
}
The s[60] part is very important, because you can't concatenate an another string to it's end if it doesn't have enough space for that.