Why did I get EXC_BAD_ACCESS? - c

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;
}

Related

Trying to create a strcat in c

So, I'm trying to code a strcat function using pointers, just for studying purposes.
#include <stdio.h>
#include <string.h>
char *strcpyy(char *dest, char *orig){
char *tmp = dest;
while (*dest++ = *orig++);
return tmp;
}
char *strcatt(char *dest, char *orig){
strcpyy(dest + strlen(dest), orig);
return dest;
}
int main(){
char *a = "one";
char *b = "two";
printf("%s", strcatt(a,b));
}
When I run this code, the output is empty. Can anyone point out the problem?
String literals are read-only. Any attempt to write to a string literal will invoke undefined behavior, which means that your program may crash or not behave as intended.
Therefore, you should not use a pointer to a string literal as the first argument to strcat or your equivalent function. Instead, you must provide a pointer to an object which is writable and has sufficient space for the result (including the terminating null character), for example a char array of length 7. This array can be initialized using a string literal.
Therefore, I recommend that you change the line
char *a = "one";
to the following:
char a[7] = "one";
After making this change, your program should work as intended.
You declared two pointers to string literals
char *a = "one";
char *b = "two";
You may not append one string literal to another.
Instead you need to define the variable a as a character array large enough to contain the appended string literal pointed to by the pointer b.
And the both functions should be declared like
char *strcpyy(char *dest, const char *orig);
char *strcatt(char *dest, const char *orig);
Also as you are using standard C string functions like strlen
strcpyy(dest + strlen(dest), orig);
then it will be logically consistent to use standard C function strcpy instead of your own function strcpyy.
Otherwise without using standard string functions your function strcatt can look the following way
char * strcatt( char *s1, const char *s2 )
{
char *p = s1;
while ( *p ) ++p;
while ( ( *p++ = *s2++ ) != '\0' );
return s1;
}
Here is a demonstration program.
#include <stdio.h>
char * strcatt( char *s1, const char *s2 )
{
char *p = s1;
while ( *p ) ++p;
while ( ( *p++ = *s2++ ) != '\0' );
return s1;
}
int main( void )
{
char a[7] = "one";
const char *b = "two";
puts( strcatt( a, b ) );
}
The program output is
onetwo
You cannot modify "string literals". Those are not mutable.
The usual idiom for this sort of operation is to build up a string in a temporary working buffer that should be pre-dimensioned large enough to hold all that is required.
The following also shows more obvious code in both your functions.
#include <stdio.h>
char *strcpyy( char *dst, const char *org ) {
for( char *p = dst; (*p++ = *org++) != '\0'; /**/ )
; // loop
return dst;
}
char *strcatt( char *dst, const char *org ) {
char *p = dst;
while( *p != '\0' )
p++; //loop
while( (*p = *org++) != '\0' )
p++; // loop
return dst;
}
int main(){
const char *a = "one ";
const char *b = "two ";
const char *c = "three";
char wrk[ 64 ]; // sufficient mutable space defined
printf( "%s\n", strcatt( strcatt( strcpyy( wrk, a ), b ), c ) );
return 0;
}
one two three

Why am I able to modify char * in this example?

I have problems understanding how char* works.
In the example below, the struses is called by main().
I created a buf to store the const variable because I want to make a modifiable copy of s1, then I just call the sortString().
This version makes sense to me as I understand that char[] can be modified:
#include "common.h"
#include <stdbool.h>
void sortString(char string[50]);
bool struses(const char *s1, const char *s2)
{
char buf[50];
strcpy(buf, s1); // <===== input = "perpetuity";
sortString(buf);
printf("%s\n", buf); // prints "eeipprttuy"
return true;
}
void sortString(char string[50])
{
char temp;
int n = strlen(string);
for (int i = 0; i < n - 1; i++)
{
for (int j = i + 1; j < n; j++)
{
if (string[i] > string[j])
{
temp = string[i];
string[i] = string[j];
string[j] = temp;
}
}
}
}
However, in this version I deliberately changed the type to char* which is supposed to be read-only. Why do I still get the same result?
#include "common.h"
#include <stdbool.h>
void sortString(char *string);
bool struses(const char *s1, const char *s2)
{
char buf[50];
strcpy(buf, s1);
sortString(buf);
printf("%s\n", buf);
return true;
}
void sortString(char *string) // <==== changed the type
{
char temp;
int n = strlen(string);
for (int i = 0; i < n - 1; i++)
{
for (int j = i + 1; j < n; j++)
{
if (string[i] > string[j])
{
temp = string[i];
string[i] = string[j];
string[j] = temp;
}
}
}
}
This is why I think char * is read only. I get a bus error after trying to to modify read[0]:
char * read = "Hello";
read[0]='B';// <=== Bus error
printf("%s\n", read);
The compiler adjusts the type of the parameter having an array type of this function declaration
void sortString(char string[50]);
to pointer to the element type
void sortString(char *string);
So for example these function declarations are equivalent and declare the same one function
void sortString(char string[100]);
void sortString(char string[50]);
void sortString(char string[]);
void sortString(char *string);
Within this function
void sortString(char *string)
there is used the character array buf that stores the copy of the passed array (or of the passed string literal through a pointer to it)
char buf[50];
strcpy(buf, s1);
sortString(buf);
So there is no problem. s1 can be a pointer to a string literal. But the content of the string literal is copied in the character array buf that is being changed
As for this code snippet
char * read = "Hello";
read[0]='B';
printf("%s\n", read); <=== still prints "Hello"
then it has undefined behavior because you may not change a string literal.
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.
Pay attention to that in C++ opposite to C string literals have types of constant character arrays. It is advisable also in C to declare pointers to string literals with the qualifier const to avoid undefined behavior as for example
const char * read = "Hello";
By the way the function sortString has redundant swappings of elements in the passed string. It is better to declare and define it the following way
// Selection sort
char * sortString( char *s )
{
for ( size_t i = 0, n = strlen( s ); i != n; i++ )
{
size_t min_i = i;
for ( size_t j = i + 1; j != n; j++ )
{
if ( s[j] < s[min_i] )
{
min_i = j;
}
}
if ( i != min_i )
{
char c = s[i];
s[i] = s[min_i];
s[min_i] = c;
}
}
return s;
}
char * does not mean read-only. char * simply means pointer to char.
You have likely been taught that string literals, such as "Hello", may not be modified. That is not quite true; a correct statement is that the C standard does not define what happens when you attempt to modify a string literal, and C implementations commonly place string literals in read-only memory.
We can define objects with the const qualifier to say we intend not to modify them and to allow the compiler to place them in read-only memory (although it is not obligated to). If we were defining the C language from scratch, we would specify that string literals are const-qualified, the pointers that come from string literals would be const char *.
However, when C was first developed, there was no const, and string literals produced pointers that were just char *. The const qualifier came later, and it is too late the change string literals to be const-qualified because of all the old code using char *.
Because of this, it is possible that a char * points to characters in a string literal that should not be modified (because the behavior is not defined). But char * in general does not mean read-only.
Your premise that the area pointed by a char* isn't modifiable is false. This is perfectly line:
char s[] = "abc"; // Same as: char s[4] = { 'a', 'b', 'c', 0 };
char *p = s; // Same as: char *p = &(s[0]);
*p = 'A';
printf("%s\n", p); // Abc
Demo
The reason you had a fault is because you tried to modify the string created by a string literal. This is undefined behaviour:
char *p = "abc";
*p = 'A'; // Undefined behaviour
printf("%s\n", p);
One would normally use a const char * for such strings.
const char *p = "abc";
*p = 'A'; // Compilation error.
printf("%s\n", p);
Demo
Regarding
char * read = "Hello";
read[0]='B';
printf("%s\n", read); // still prints "Hello"
you have tripped over a backward compatibility wart in the C specification.
String constants are read-only. char *, however, is a pointer to modifiable data.
The type of a string constant ought to be const char [N] where N is the number of chars given by the contents of the constant, plus one. However, const did not exist in the original C language (prior to C89). So there was, in 1989, a whole lot of code that used char * to point to string constants. So the C committee made the type of string constants be char [N], even though they are read-only, to keep that code working.
Writing through a char * that points to a string constant triggers undefined behavior; anything can happen. I would have expected a crash, but the write getting discarded is not terribly surprising either.
In C++ the type of string constants is in fact const char [N] and the above fragment would have failed to compile. Some C compilers have an optional mode you can turn on that changes the type of string constants to const char [N]; for instance, GCC and clang have the -Wwrite-strings command line option. Using this mode for new programs is a good idea.
Yout long examples can be reduced to your last question.
This is why I think char * is read only, get bus error after attempt
to modify read[0]
char * read = "Hello";
read[0]='B';
printf("%s\n", read); <=== Bus error
"Hello" is a string literal . Attempt to modify the string literal manifested itself by the Bus Error.
Your pointer is referencing the memory which should not be modified.
How to sort it out? You need to define pointer referencing the modifiable object
char * read = (char []){"Hello"};
read[0]='B';
printf("%s\n", read);
So as you see declaring it as modifiable is not making it modifiable.

Reverse String with a pointer to a function, which executes the String reverse

I would like to reverse a String with an pointer to a function, which executes the String reverse.
I have the feeling that I did not grasp the concept of using pointer to variables or functions correctly, so I would be very thankful if someone could expain me, where I am thinking wrong here:
1) Define a pointer to a function:
char *strrev(char *str)
{
char *p1, *p2;
if (! str || ! *str)
return str;
for (p1 = str, p2 = str + strlen(str) - 1; p2 > p1; ++p1, --p2)
{
*p1 ^= *p2;
*p2 ^= *p1;
*p1 ^= *p2;
}
return str;
}
2) Now in my main I define a pointer, which matches the function I defined above:
int main(void) {
char (*functPtr)(char);
functPtr = &strrev;
3) Now I define the String, which I want to reverse, define a new pointer and let the pointer point to the address space of the String.
char str[50] = "Hello, World";
char *pointer[50];
pointer[50] = &str[50];
4) Lastly I define a new String and write the result of the function, which call through the pointer, which points to the pointer to the function.
char t[50] = (*functPtr)(pointer[50]);
printf("%s\n", str);
return(0);
}
Unfortunaly I get all kinds of error message such as:
Ü1.c:29:10: error: array initializer must be an initializer list or string literal
char t[50] = (*functPtr)(pointer[50]);
^
Ü1.c:27:5: warning: array index 50 is past the end of the array (which contains 50 elements) [-Warray-bounds]
pointer[50] = &str[50];
^ ~~
Ü1.c:26:5: note: array 'pointer' declared here
char *pointer[50];
^
Ü1.c:29:30: warning: array index 50 is past the end of the array (which contains 50 elements) [-Warray-bounds]
char t[50] = (*functPtr)(pointer[50]);
^ ~~
Ü1.c:26:5: note: array 'pointer' declared here
char *pointer[50];
^
2 warnings and 1 error generated.
1) Define a pointer to a function:
No, you did not define a pointer to function. You defined a function with the name strrev.
2) Now in my main I define a pointer, which matches the function I
defined above:
int main(void) {
char *(*functPtr)(char *);
functPtr = &strrev;
Yes, you defined a pointer to function and initialized it with the address of the function strrev. As function designators used in expressions are implicitly converted to pointers to function then you could write
int main(void) {
char *(*functPtr)(char *);
functPtr = strrev;
3) Now I define the String, which I want to reverse, define a new
pointer and let the pointer point to the address space of the String.
char str[50] = "Hello, World";
char *pointer[50];
pointer[50] = &str[50];
Except the definition of the character array that contains a string all other records do not make any sense. For starters the function strrev reverses a string in place. It does not create a reversed copy of the passed to it string.
If you want to declare a pointer that will get the address of the reversed string returned by the function that equal to the address of the original string then you could just write
char *pointer = functPtr( str );
4) Lastly I define a new String and write the result of the function,
which call through the pointer, which points to the pointer to the
function.
char t[50] = (*functPtr)(pointer[50]);
printf("%s\n", str);
You already defined a pointer that will get the value returned from the function. So there is no sense to declare one more array. Moreover arrays do not have the assignment operator. And the function reversed the original string in place. Why are you going to create one more array with the duplicate copy of the original reversed string?! This entirely does not make a sense.
Your program can look the following way
#include <stdio.h>
#include <string.h>
char * strrev( char *s )
{
size_t n = strlen( s );
if ( n )
{
for ( char *first = s, *last = s + n; first < --last; ++first )
{
char c = *first;
*first = *last;
*last = c;
}
}
return s;
}
int main(void)
{
char * ( *fp )( char * ) = strrev;
char s[] = "Hello, World";
puts( s );
puts( fp( s ) );
return 0;
}
The program output is
Hello, World
dlroW ,olleH
If you initially wanted that the function would not reverse the original string but make a reversed copy of the original string then in this case indeed there is a sense to define one additional character array that will get the reversed copy of the original string.
In this case the program can look like.
#include <stdio.h>
#include <string.h>
char *reverse_copy( char *s1, const char *s2 )
{
*( s1 += strlen( s2 ) ) = '\0';
while (*s2)
{
*--s1 = *s2++;
}
return s1;
}
int main(void)
{
char * ( *fp )( char *, const char * ) = reverse_copy;
char s[] = "Hello, World";
char t[sizeof( s )];
puts( s );
puts( fp( t, s ) );
return 0;
}
The program output is
Hello, World
dlroW ,olleH
Now the original character array s was not changed while the array t got the reversed copy of the original string stored in the array s.
I summarize my comments in this answer, as it gives more space for details of the comments.
char (*functPtr)(char); should be char *(*functPtr)(char *); as it takes a pointer to a char, not a char. Likewise it returns a pointer.
char *pointer[50]; would be an array of 50 pointers, You want to say "a pointer to an array of 50 chars". In C we don't say that. We just say "a pointer to a char" and don't say how many. So char *pointer; would be enough.
char t[50] = (*functPtr)(pointer[50]); is not correct in C.
You want to assign the result of funcPtr to the array t. But here you mix initialization with assignment.
char t[50]; declares an array of 50 chars. You can initialize it by giving it a value, for example char t[50] = "Hello World"; which will have the compiler copy "Hello World" to the array.
But you try to assign the function pointer to the array. You probably intend to put the result of the function into the array.
Note also that you cannot "assign" an array to another array. You can only copy it.
So the correct code would be:
char *(*functPtr)(char *);
functPtr = &strrev;
char str[50] = "Hello, World";
char t[50];
char *s= funcPtr(str); // call the function and save the returned pointer
strcpy(t, s); // now copy the result to your array.
printf("%s\n", t); // and print it
Note: char str[50] = "Hello, World"; is correct and, just so you'll know, char *str = "Hello, World"; is wrong. Why? Because the second str will point to read-only memory (a "string literal") and any attempt to modify it would abort the program. But here you did it right.

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).

getting "segmentation failed" error in strrev function implementation

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.

Resources