EXC_BAD_ACCESS in code from Cracking the coding interview - c

I tried to run a reverse string function by using the code from Cracking the coding interview. I don't know if the code is wrong or I should use another IDE (I used Xcode 5.2 for this one). I'm new to C programming so please explain. Thanks.
#include <stdio.h>
void reverse(char *str);
int main(int argc, const char * argv[])
{
char *str = "Hello, World!";
reverse(str);
printf("%s", 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;
}
}
}

The problem here is that you try to modify a string literal (str points to that) and string literals are constant (i.e. read-only, non modifiable).
Trying to modify something constant is undefined behavior. Undefined behavior may sometimes seem to work, but most of the time it will cause a crash at runtime.
A good advice to find possible cases of undefined behaviors (or other things that might be bad) is to enable more warnings. Then you should get a warning about assigning a constant array (all string literals are constant arrays) to a non-constant pointer.

char *str = "Hello, World!";
make it
char str[] = "Hello World!";

Related

Reverse C string - simple bug [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Is it possible to modify a string of char in C?
#include <stdio.h>
void reverseStr(char *str);
main()
{
reverseStr("abcdef");
}
void reverseStr(char *str) {
char *tmp = str;
char curr;
while (*tmp != '\0') {
tmp++;
}
tmp--;
while (tmp > str) {
curr = *str;
*str = *tmp;
*tmp = curr;
str++;
tmp--;
}
}
When I run it, I get:
/usr/bin/runit/srun_c: line 12: 2809 Segmentation fault /tmp/run_c_executable
What on earth is going on? I'm practicing for an interview, I'm rusty in my C and wanted to practice something easy but can't for the life of me figure this out.
I've noticed the seg fault disappears when I comment out the *str = *tmp; line, and I don't see why that should cause a seg fault.
Help appreciated.
You can't modify constant strings. Use a char array instead:
char str[] = "abcdef";
reverseStr(str);
You can't modify string literals — they're stored in readonly memory.
Use:
char str[] = "abcdef";
reverseStr(str);
Your reversal function looks fine. But it is the way you are calling the function that is causing this crash. You are passing a string literal which are read-only to the function. And modifying a string literal is a undefined behavior, manifesting as crash in your case.
Change
reverseStr("abcdef");
to
char str[] = "abcdef";
reverseStr(str);
where you pass a character array to the function.

Replace a character in a char[] from a function

How would I get my replace_char function to work properly?
The way that I am trying it in the function below returns segmentation faults using gcc in Ubuntu.
I have tried other ways, but each time I try to change the value, I get a fault.
int main (void)
{
char* string = "Hello World!";
printf ("%s\n", string);
replace_char(string, 10, 'a');
printf ("%s\n", string);
}
void replace_char(char str[], int n, char c)
{
str[n] = c;
}
There is nothing wrong with your replace_char function. The problem is that you are trying to modify a string literal ("Hello World!") and that's undefined behavior. Try making a copy of the string instead, like this:
char string[] = "Hello World!";
Edit
To get the 'suggestion' of editing string in place, you can edit the pointer inplace:
void replace_char(char*& str, int n, char c)
{
str = strdup(str);
str[n] = c;
}
int main()
{
char* string = "Hello World!";
string = replace_char(string, 10, 'a');
// ...
free(string);
}
Note you now have to remember to call free on the string after calling this. I suggest, instead, that you do what I suggested before: wrap the literal in strdup if required. That way you don
't incur the cost of allocating a copy all the time (just when necessary).
The problem is that "Hello World' is a const literal char array.
const char* conststr = "Hello World!";
char * string = strdup(conststr);
i assume the problem will be gone
Explanation:
Compilers can allocate string literals in (readonly) data segment.
The conversion to a char* (as opposed to const char*) is actually not valid. If you use use e.g.
gcc -Wall test.c
you'd get a warning.
Fun experiment:
Observe here that (because it is Undefined Behaviour) compilers can do funny stuff in such cases:
http://ideone.com/C39R6 shows that the program wouldn't 'crash' but silently fail to modify the string literal unless the string was copied.
YMMV. Use -Wall, use some kind of lint if you can, and do unit testing :){

Difference between char *str="STRING" and char str[] = "STRING"?

While coding a simple function to remove a particular character from a string, I fell on this strange issue:
void str_remove_chars( char *str, char to_remove)
{
if(str && to_remove)
{
char *ptr = str;
char *cur = str;
while(*ptr != '\0')
{
if(*ptr != to_remove)
{
if(ptr != cur)
{
cur[0] = ptr[0];
}
cur++;
}
ptr++;
}
cur[0] = '\0';
}
}
int main()
{
setbuf(stdout, NULL);
{
char test[] = "string test"; // stack allocation?
printf("Test: %s\n", test);
str_remove_chars(test, ' '); // works
printf("After: %s\n",test);
}
{
char *test = "string test"; // non-writable?
printf("Test: %s\n", test);
str_remove_chars(test, ' '); // crash!!
printf("After: %s\n",test);
}
return 0;
}
What I don't get is why the second test fails?
To me it looks like the first notation char *ptr = "string"; is equivalent to this one: char ptr[] = "string";.
Isn't it the case?
The two declarations are not the same.
char ptr[] = "string"; declares a char array of size 7 and initializes it with the characters s ,t,r,i,n,g and \0. You are allowed to modify the contents of this array.
char *ptr = "string"; declares ptr as a char pointer and initializes it with address of string literal "string" which is read-only. Modifying a string literal is an undefined behavior. What you saw(seg fault) is one manifestation of the undefined behavior.
Strictly speaking a declaration of char *ptr only guarantees you a pointer to the character type. It is not unusual for the string to form part of the code segment of the compiled application which would be set read-only by some operating systems. The problem lies in the fact that you are making an assumption about the nature of the pre-defined string (that it is writeable) when, in fact, you never explicitly created memory for that string yourself. It is possible that some implementations of compiler and operating system will allow you to do what you've attempted to do.
On the other hand the declaration of char test[], by definition, actually allocates readable-and-writeable memory for the entire array of characters on the stack in this case.
As far as I remember
char ptr[] = "string";
creates a copy of "string" on the stack, so this one is mutable.
The form
char *ptr = "string";
is just backwards compatibility for
const char *ptr = "string";
and you are not allowed (in terms of undefined behavior) to modify it's content.
The compiler may place such strings in a read only section of memory.
char *test = "string test"; is wrong, it should have been const char*. This code compiles just because of backward comptability reasons. The memory pointed by const char* is a read-only memory and whenever you try to write to it, it will invoke undefined behavior. On the other hand char test[] = "string test" creates a writable character array on stack. This like any other regualr local variable to which you can write.
Good answer #codaddict.
Also, a sizeof(ptr) will give different results for the different declarations.
The first one, the array declaration, will return the length of the array including the terminating null character.
The second one, char* ptr = "a long text..."; will return the length of a pointer, usually 4 or 8.
char *str = strdup("test");
str[0] = 'r';
is proper code and creates a mutable string. str is assigned a memory in the heap, the value 'test' filled in it.

Reversing a string in C

I know this has been asked thousands of times but I just can't find the error in my code. Could someone kindly point out what I'm doing wrong?
#include <stdlib.h>
#include <string.h>
void reverseString(char *myString){
char temp;
int len = strlen(myString);
char *left = myString;
// char *right = &myString[len-1];
char *right = myString + strlen(myString) - 1;
while(left < right){
temp = *left;
*left = *right; // this line seems to be causing a segfault
*right = temp;
left++;
right--;
}
}
int main(void){
char *somestring = "hello";
printf("%s\n", somestring);
reverseString(somestring);
printf("%s", somestring);
}
Ultimately, it would be cleaner to reverse it in place, like so:
#include <stdio.h>
#include <string.h>
void
reverse(char *s)
{
int a, b, c;
for (b = 0, c = strlen(s) - 1; b < c; b++, c--) {
a = s[b];
s[b] = s[c];
s[c] = a;
}
return;
}
int main(void)
{
char string[] = "hello";
printf("%s\n", string);
reverse(string);
printf("%s\n", string);
return 0;
}
Your solution is essentially a semantically larger version of this one. Understand the difference between a pointer and an array. The standard explicitly states that the behviour of such an operation (modification of the contents of a string literal) is undefined. You should also see this excerpt from eskimo:
When you initialize a character array with a string constant:
char string[] = "Hello, world!";
you end up with an array containing the string, and you can modify the array's contents to your heart's content:
string[0] = 'J';
However, it's possible to use string constants (the formal term is string literals) at other places in your code. Since they're arrays, the compiler generates pointers to their first elements when they're used in expressions, as usual. That is, if you say
char *p1 = "Hello";
int len = strlen("world");
it's almost as if you'd said
char internal_string_1[] = "Hello";
char internal_string_2[] = "world";
char *p1 = &internal_string_1[0];
int len = strlen(&internal_string_2[0]);
Here, the arrays named internal_string_1 and internal_string_2 are supposed to suggest the fact that the compiler is actually generating little temporary arrays every time you use a string constant in your code. However, the subtle fact is that the arrays which are ``behind'' the string constants are not necessarily modifiable. In particular, the compiler may store them in read-only-memory. Therefore, if you write
char *p3 = "Hello, world!";
p3[0] = 'J';
your program may crash, because it may try to store a value (in this case, the character 'J') into nonwritable memory.
The moral is that whenever you're building or modifying strings, you have to make sure that the memory you're building or modifying them in is writable. That memory should either be an array you've allocated, or some memory which you've dynamically allocated by the techniques which we'll see in the next chapter. Make sure that no part of your program will ever try to modify a string which is actually one of the unnamed, unwritable arrays which the compiler generated for you in response to one of your string constants. (The only exception is array initialization, because if you write to such an array, you're writing to the array, not to the string literal which you used to initialize the array.) "
the problem is here
char *somestring = "hello";
somestring points to the string literal "hello". the C++ standard doesn't gurantee this, but on most machines, this will be read-only data, so you won't be allowed to modify it.
declare it this way instead
char somestring[] = "hello";
You are invoking Undefined Behavior by trying to modify a potentially read-only memory area (string literals are implicitly const -- it's ok to read them but not to write them). Create a new string and return it, or pass a large enough buffer and write the reversed string to it.
You can use the following code
#include<stdio.h>
#include<string.h>
#include<malloc.h>
char * reverse(char*);
int main()
{
char* string = "hello";
printf("The reverse string is : %s", reverse(string));
return 0;
}
char * reverse(char* string)
{
int var=strlen(string)-1;
int i,k;
char *array;
array=malloc(100);
for(i=var,k=0;i>=0;i--)
{
array[k]=string[i];
k++;
}
return array;
}
I take it calling strrev() is out of the question?
Your logic seems correct. Instead of using pointers, it is cleaner to deal with char[].

Memory access violation. What's wrong with this seemingly simple program?

This is a quick program I just wrote up to see if I even remembered how to start a c++ program from scratch. It's just reversing a string (in place), and looks generally correct to me. Why doesn't this work?
#include <iostream>
using namespace std;
void strReverse(char *original)
{
char temp;
int i;
int j;
for (i = 0, j = strlen(original) - 1; i < j; i++, j--)
{
temp = original[i];
original[i] = original[j];
original[j] = temp;
}
}
void main()
{
char *someString = "Hi there, I'm bad at this.";
strReverse(someString);
}
If you change this, which makes someString a pointer to a read-only string literal:
char *someString = "Hi there, I'm bad at this.";
to this, which makes someString a modifiable array of char, initialized from a string literal:
char someString[] = "Hi there, I'm bad at this.";
You should have better results.
While the type of someString in the original code (char*) allows modification to the chars that it points to, because it was actually pointing at a string literal (which are not permitted to be modified) attempting to do any modification through the pointer resulted in what is technically known as undefined behaviour, which in your case was a memory access violation.
If this isn't homework, the C++ tag demands you do this by using the C++ standard library:
std::string s("This is easier.");
std::reverse(s.begin(), s.end());
Oh, and it's int main(), always int main(), dammit!
You're trying to modify a string literal - a string allocated in static storage. That's undefiend behaviour (usually crashes the program).
You should allocate memory and copy the string literal there prior to reversing, for example:
char *someString = "Hi there, I'm bad at this.";
char* stringCopy = new char[strlen( someString ) + 1];
strcpy( stringCopy, someString );
strReverse( stringCopy );
delete[] stringCopy;//deallocate the copy when no longer needed
The line
char *someString = "Hi there, I'm bad at this.";
makes someString point to a string literal, which cannot be modified. Instead of using a raw pointer, use a character array:
char someString[] = "Hi there, I'm bad at this.";
You can't change string literals (staticly allocated). To do what you want, you need to use something like:
int main()
{
char *str = new char[a_value];
sprintf(str, "%s", <your string here>);
strReverse(str);
delete [] str;
return 0;
}
[edit] strdup also works, also strncpy... i'm sure there's a variety of other methods :)
See sharptooth for explanation.
Try this instead:
#include <cstring>
void main()
{
char someString[27];
std::strcpy( someString, "Hi there, I'm bad at this." );
strReverse( someString );
}
Better yet, forget about char * and use <string> instead. This is C++, not C, after all.
When using more strict compiler settings, this code shouldn't even compile:
char* str = "Constant string";
because it should be constant:
const char* str = "Now correct";
const char str[] = "Also correct";
This allows you to catch these errors faster. Or you can just use a character array:
char str[] = "You can write to me, but don't try to write something longer!";
To be perfectly safe, just use std::string. You're using C++ after all, and raw string manipulation is extremely error-prone.

Resources