Why is this code getting a segmentation fault? - c

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.

Related

C - Own str_join function does not work

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.

simple strcat implementation with pointers

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.

Error with mystrlen function

I was trying to write out some of the implementations of the string functions available in C. My code is:
#include <stdio.h>
#include <stdlib.h>
char *mystrcpy(char *s1, char *s2)
{
while(*s1++ = *s2++);
return s1;
}
int mystrlen(char *s)
{
int len = 0;
while(*s != '\0')
{
len++;
}
return len;
}
int main(void)
{
char arr = "Hi";
char arr1[10];
char arr2[] = "Hello";
int length;
mystrcpy(arr1, arr2);
printf("%s", arr1);
length = mystrlen(arr);
printf("%d", length);
return 0;
}
mystrcpy works fine, but the other method mystrlen does no execute. What could be the error? The following is the program termination note:
Process terminated with status -1073741510 (0 minutes, 4 seconds)
Also, there are few warnings related to casts. Is there any place in the code where I should be using any cast?
First, your mystrlen has an infinite loop.
Fixed code:
int mystrlen(const char *s)
{
int len = 0;
while (*s++ /* increment to next character every loop */ != '\0')
{
len++;
}
return len;
}
Also added const since you never change the data referred to by *s
Second, the assignment: char arr="Hi"; is not valid.
You are attempting to assign a char[] array to a char variable. The correct form would be one of the following:
char arr[]="Hi"; // array syntax
char *arr="Hi"; // pointer syntax
Given your invalid arr assignment, your runtime error is most likely caused by mystrlen attempting to incorrectly deference arr.
What compiler are you using? Most conforming compilers should have caught the second issue. If using GCC, add the -Wall flag to your makefile.
This:
char arr="Hi"; /* Should have caused compiler warning,
as is attempting to assign a char
to a char[3]. */
should be:
char arr[] ="Hi";
or:
char* arr = "Hi";

Bus error in a simple C program

I am trying to reverse a C style string using the following simple program.
#include "stdio.h"
void reverse (char * str);
int main (int argc , char* argv[]){
char *str = "hello";
reverse(str);
return 0;
}
void reverse (char *str)
{
char *end = str;
char tmp;
if(str){
while(*end){
++end;
}
--end;
while(str < end){
tmp = *str;
*str++ = *end;
*end-- = tmp;
}
}
}
I can't figure out why I get a "bus error" when I try to run the above program. I am using i686-apple-darwin10-gcc-4.2.1. Thanks
If you change char *str = "hello"; to char str[] = "hello"; your error will go away, since string literals are stored in a read-only part of memory and trying to modify "hello" may cause your program to crash (as it does in this case).
Declaring str as a char[] will copy the literal "hello" into a non-const buffer that you can modify the contents of.
String literals in C are stored in the .data section of the binary which is read only memory. When saving it as const char * or char * they are non modifiable (in some cases if you modify the access fails silently or in your case you get a bus error because it's ROM).
Try using char str[] = "hello"; instead (I believe this should work, but I may be wrong).

Reversing a string in C using pointers?

Language: C
I am trying to program a C function which uses the header char *strrev2(const char *string) as part of interview preparation, the closest (working) solution is below, however I would like an implementation which does not include malloc... Is this possible? As it returns a character meaning if I use malloc, a free would have to be used within another function.
char *strrev2(const char *string){
int l=strlen(string);
char *r=malloc(l+1);
for(int j=0;j<l;j++){
r[j] = string[l-j-1];
}
r[l] = '\0';
return r;
}
[EDIT] I have already written implementations using a buffer and without the char. Thanks tho!
No - you need a malloc.
Other options are:
Modify the string in-place, but since you have a const char * and you aren't allowed to change the function signature, this is not possible here.
Add a parameter so that the user provides a buffer into which the result is written, but again this is not possible without changing the signature (or using globals, which is a really bad idea).
You may do it this way and let the caller responsible for freeing the memory. Or you can allow the caller to pass in an allocated char buffer, thus the allocation and the free are all done by caller:
void strrev2(const char *string, char* output)
{
// place the reversed string onto 'output' here
}
For caller:
char buffer[100];
char *input = "Hello World";
strrev2(input, buffer);
// the reversed string now in buffer
You could use a static char[1024]; (1024 is an example size), store all strings used in this buffer and return the memory address which contains each string. The following code snippet may contain bugs but will probably give you the idea.
#include <stdio.h>
#include <string.h>
char* strrev2(const char* str)
{
static char buffer[1024];
static int last_access; //Points to leftmost available byte;
//Check if buffer has enough place to store the new string
if( strlen(str) <= (1024 - last_access) )
{
char* return_address = &(buffer[last_access]);
int i;
//FixMe - Make me faster
for( i = 0; i < strlen(str) ; ++i )
{
buffer[last_access++] = str[strlen(str) - 1 - i];
}
buffer[last_access] = 0;
++last_access;
return return_address;
}else
{
return 0;
}
}
int main()
{
char* test1 = "This is a test String";
char* test2 = "George!";
puts(strrev2(test1));
puts(strrev2(test2));
return 0 ;
}
reverse string in place
char *reverse (char *str)
{
register char c, *begin, *end;
begin = end = str;
while (*end != '\0') end ++;
while (begin < --end)
{
c = *begin;
*begin++ = *end;
*end = c;
}
return str;
}

Resources