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).
Related
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 want to reverse a string, but I got a error on swap char.
Could someone help me with this?
char* reverse_char(char* src){
char *p,*q;
p = q = src;
while(*(p) != '\0'){
p++;
}
p--;
char temp = '\0';
while (p > q) {
temp = *p;
*p = *q; // I got exec bad access here ??? why
*q = temp;
p--;
q++;
}
return src;
}
This is the main method.
int main(int argc, char const* argv[])
{
char *hi = "hello world!\n";
printf("%s", hi);
reverse_char(hi);
printf("%s", hi);
return 0;
}
Replace char *hi = "hello world!\n"; with char hi[] = "hello world!\n";
"hello world!\n" is string literal and may not be writable causing the access error. Modifying the contents of string literal is undefined behavior, it may write the contents silently, raise an access error or may do something else unexpected. (So you should not write to string literal)
Summing up
char a[] = "..."; /* Contents of a can be assigned */
char *a = "..."; /* Writing to contents of memory pointed by a leads to UB */
Though string literals in C have types of non-const character arrays they may not be changed.
From the C Standard (6.4.5 String literals)
7 It is unspecified whether these arrays are distinct provided their
elements have the appropriate values. If the program attempts to
modify such an array, the behavior is undefined.
it is better to declare a pointer initialized with a string literal as having type const char * as it is done in C++. For example
const char *hi = "hello world!\n";
In this case instead of a run-time error you would get a compile-time error that would be understandable because the parameter of the function is declared as a non-const character pointer.
You have to use a character array instead of a pointer to a string literal.
For example
char hi[] = "hello world!\n";
As for the function that it has some problem when a pointer points to an empty string. In this case after operation
p--;
you can get invalid pointer that is not necessary less than src.
I would write the function the following way
char* reverse_string( char *s )
{
char *p = s;
while ( *p ) ++p;
if ( p != s )
{
for ( char *q = s; q < --p; ++q )
{
char c = *q;
*q = *p;
*p = c;
}
}
return s;
}
I have coded the following function that will reverse a String in C:
void reverse(char *str) {
int length = strlen(str) - 1;
for (int i=0; i < length/2; i++) {
char tmp = str[i];
str[i] = str[length - i];
str[length - i] = tmp;
}
}
This works if I do this:
char a[]="Hello";
reverse(a);
But if I call it passing a string literal, such as:
char *a = "Hello";
It won't work.
So, how would I modify my function so that it can accept string literals and reverse them?
You can not do that, string literals are constants in C
Perhaps, you need to copy the string, much like you do it in your first example, where you initialize a char array using a string literal.
You better of copying string to some other temp string.
Use another char* to copy original string. Allocate sufficient memory.
Copy sources string to this one. Don't forget to null terminate it.
reverse..
Dont forget to free this memory after use.
char *a1 = "Hello";
char* copy_a1 = malloc(sizeof(char)*(strlen(a1)+1));
strncpy(copy_a1, a1, strlen(a1));
copy_a1[strlen(a1)] = '\0';
reverse(copy_a1);
//free memory used.
The problem is C history.
char *a = "Hello"; should be const char *a = "Hello";. But const came in after C was successful so char *a = "Hello"; was allowed to remain OK syntax.
Had code been const char *a = "Hello";, reverse(a); would generate a warning (or error).
To modify create something like:
char *reverse(char *dest, const char *src);
It's a textbook C code
void strcpy_new(char *s, char *t) {
while ((*s = *t) != '\0') {
s++;
t++;
}
}
int main(int argc, const char * argv[])
{
char *s = "this is line a";
char *t = "this is line b";
printf("%s", s);
strcpy_new(s, t);
printf("%s", s);
return 0;
}
when I run it with Xcode, I got EXEC_BAD_ACCESS.
The reason you get EXEC_BAD_ACCESS is because those string literals "this is line a" and "this is line b" are stored in read-only memory. Attempting to write to it (*s = *t) is undefined behavior and you are receiving a crash because of it.
To remedy this code you should allocate some memory for s so that it is large enough to hold the second string (t):
char s[] = "this is line a"; // contrived example, s and t are the same length
char *t = "this is line b";
strcpy_new(s, t);
I'm willing to bet that you're trying to run strcpy_new with a destination char *s that is a string literal
#include <string.h>
int main(int argc, char *argv[])
{
char *a = "Some String";
char *b = "Another string";
strcpy(b, a);
return 0;
}
will give an EXEC_BAD_ACCESS. The following, however, won't
#include <string.h>
int main(int argc, char *argv[])
{
char *a = "Some String";
char b[] = "Another string";
strcpy(b, a);
return 0;
}
The difference is that in the first case, b points to a block of memory in the __TEXT,__cstring,cstring_literals section of the executable, which is write protected. In the second case, it points to a block of memory on the stack.
The problem is that the effect of overwriting a string literal is undefined.
char *s = "this is line a";
char *t = "this is line b";
strcpy_new(s, t);
s and t are both off in the data section of the code, and your particular setup happens to give you an EXEC_BAD_ACCESS when you try changing them.
String literal are read-only. A good answer is found here: http://ubuntuforums.org/showthread.php?t=357869
String literals in C are read-only. In your sample code, "My string" is a string literal.
The str[] declaration copies the literal into writable memory (stack or heap). Therefore, your program can modify the string.
The * declaration initializes a pointer to the literal itself, so you have a pointer to a read-only segment. If you try to overwrite it, you get the SEGV.
void main() {
void strrev(char *);
char *p="GOOd";
strrev(p);
printf("%s",p);
}
void strrev(char *str) {
char temp, *end_ptr;
if( str == NULL || !(*str) ) return;
end_ptr = str + strlen(str) - 1;
while( end_ptr > str )
{
temp = *str;
*str = *end_ptr;
*end_ptr = temp; str++;
end_ptr--;
}
}
i am getting the error segmentation failed can any one help me out how to sort it out...
The statement:
char *p = "GOOd";
Defines a string literal "GOOD", pointed by an pointer p.
You are trying to modify this string literal through the strrev function which results in Undefined Behavior(UB) and the crash.
The problem with string literals is they are stored in a read-only(Implementation defined) memory location and user programs are not allowed to change that.If a program attempts to do so it causes an UB.
So instead of using a string literal You should use an array.
You should be using:
char p[] = "GOOd";
One problem is that in the following:
char *p = "GOOd";
the compiler is allowed to place the string literal in read-only memory.
Any attempt to modify the string pointed to by p results in undefined behaviour.
Try changing the above line to:
char p[] = "GOOd";
I don't see anything wrong with the strrev() function itself.