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 :){
Related
I was just playing around with some code, and ended up typing something along the lines of the following piece of code. The issue seems to be that the char *string line isn't actually interchangeable with a char string[], but I can't seem to wrap my head around why strtok(...) throws a "segmentation violation" if my argument is initialized as a char* to a string, or why it would even require an initialization of char[] instead?
#include <stdio.h>
#include <string.h>
//extern char *strtok (char *__restrict __s, const char *__restrict __delim);
char *string = "Hello world whats up?";
/*
SEGV - Must be char string[] in order to execute.
e.g. char string[] = "Hello world whats up?";
*/
char *delim = "\t ";
char *token;
int main (argc, argv)
int argc;
char **argv;
{
token = strtok(string, delim);
while ( token != NULL ) {
printf("%s\n", token);
token = strtok(NULL, delim);
}
}
The strtok function (potentially) modifies the string passed to it as its first argument. That is the critical point, here.
In your code snippet (not using the [] version), your string variable is initialized to be the address of a string literal. That literal is a constant and is likely to be placed in read-only memory. Thus, when you call strtok and that function finds a delimiter character, it attempts to replace that character with a nul, which would require writing to memory to which it does not have the required access – and your program crashes.
However, in your version using the [] syntax, you are declaring a (modifiable) array of characters and initializing it with a copy of the string literal.
In summary:
char* pc = "Hello, World!"; // pc points to a CONSTANT string literal
char ca[] = "Hello, World!"; // ca is a 'normal' array initialized with data
In C all literal strings are non-modifiable, they are in essence read-only.
When you define and initialize string you make it point to the first character of such a literal string.
This is the reason it's recommended to use const char * for literal strings.
If you want to modify the string in any way, and strtok modifies the string it tokenizes, then you must use an explicit modifiable array.
i cant see why i'm getting segmentation fault from this code and somehow when i use arrays instead of pointers it works, i would be happy if anyone can make me understand this.
void main() {
char *str = "example string";
wrapChrInStr(str, 'a');
}
void wrapChrInStr(char *str, unsigned char chr) {
char *ptr = str;
char c;
while((c = *ptr)) {
if(c != chr) {
*str = c;
str++;
ptr++;
} else {
ptr++;
}
}
*str = '\0';
}
Thank you. I'm doing a lot of c programming and its really weird that i never faced that before.
Probably because you don't realize that there are different ways of storing a
C-String. You may have been lucky enough never to have encountered a segfault
because of this.
String literals
A string literal is declared with double quotation marks, e.g.
"hello world"
This string is usually stored in a read-only section. When using string
literals, it's best to declare the variables with a const like this:
const char *str = "hello world";
With this you know that str is pointing to read-only memory location and you cannot
manipulate the contents of the string. In fact, if you do this:
const char *str = "hello world";
str[0] = 'H';
// or the equivalent
*str = 'H'
the compiler will return an error like this:
a.c:5:5: error: assignment of read-only location ‘*str’
which I found very helpful, because you cannot accidentally manipulate the
contents pointed to by str.
Arrays
If you need to manipulate the contents of a string, then you need to store the
string in an array, e.g.
char str[] = "hello word";
In this case the compiler knows that the string literal has 10 characters and reserves 11 bytes (1 byte for '\0' - the terminating byte) for str and initializes the array with
the contents of the string literal.
Here you can do stuff like
str[0] = 'H'
but you cannot access beyond the 11th byte.
You can also declare an array with a fixed size. In this case the size must be
at least the same as the length+1 of the string literal.
char str[11] = "Hello world";
If you declare less space (char str[3] = "hello world"; for example),
your compiler will warn you with something like this
a.c:4:14: warning: initializer-string for array of chars is too long
but I'm not sure what happens if you execute the code anyway. I think this is a case of undefined behaviour
and that means: anything can happen.
Personally, I usually declare my string without a fixed size, unless there is
a reason for having a fixed size.
static void foo(unsigned char *cmd)
{
strcat(cmd, "\r\n");
printf("\r\nfoo: #%s#", cmd);
}
int main()
{
foo("test");
return 0;
}
Compiler says Segmentation fault (core dumped)
What is the actual problem here?
You have undefined behaviour. You are not allowed to modify string literals. cmd points to a string literal and strcat() attempts concatenate to it, which is the problem.
int main(void)
{
char arr[256] = "test";
foo(arr);
return 0;
}
You generally need to be careful when using strcpy() and strcat() etc in C as there's a possibility that you could overflow the buffer.
In my example, I used an array size of 256 which is more than enough for your example. But if you are concatenating something of unknown size, you need to be careful.
In C string literals (like "test") are read-only arrays of characters. As they are read-only they can't be modified. As they are arrays they have a fixed size. You both try to modify the string literal, and extend it.
You are trying to append something to the string literal test which cannot be modified. It's undefined behaviour.
You want this:
static void foo(unsigned char *cmd)
{
strcat(cmd, "\r\n");
printf("\r\nfoo: #%s#", cmd);
}
int main()
{
char test[50] = "test";
foo(test);
printf("test after calling foo: %s\n", test);
return 0;
}
Other people have explained why you cannot do this operation in place.
You have basically two options:
Either you modify the string in place (with realloc() to allow you to add your suffix ("\r\n"). But you have to be careful and use a malloc allocated data.
Otherwise, allocate a new string of the size of the input, plus the size of your suffix, and copy the input string and the prefix there, and return it. In that case, the caller will need to free() the returned string (and possibly the one passed to the function, but this would have been handled eitherway).
Edit: if you use a statically allocated buffer, you'll probably have to add an additional parameter to the function indicating the size of the buffer available.
To work with I changed the program like:
static void foo(unsigned char *cmd)
{
unsigned char local[10];
strcpy(local, cmd);
strcat(local, "\r\n");
printf("\r\nfoo: #%s#", local);
}
int main()
{
foo("test");
return 0;
}
I have this program in C
#include<stdio.h>
int main()
{
printf("Hello New!\n");
char c = 'd';
char* s = "hello world";
char **t = &s;
*t[0] = c;
return 0;
}
The program compiles but doesn't run.
I have this output :
Hello New!
Bus error
I don't understand why
String constants are stored in readonly memory and you cannot modify them.
If you must, then use:
#include<stdio.h>
int main()
{
printf("Hello New!\n");
char c = 'd';
char s[] = "hello world";
char **t = &s[0];
*t[0] = c;
return 0;
}
This allocates a local variable (not a constant) that is conveniently initialized and may be modified to your heart's content.
You may not modify the string that 's' points to, in any way. It is in a part of memory that you are not allowed to change.
String constants are unmodifiable, despite having the type char* rather than const char* for historical reasons. Try using the string constant to initialize an array, rather than a pointer:
#include <stdio.h>
int
main(void)
{
char s[] = "hello new!";
puts(s);
s[0] = 'c';
puts(s);
return 0;
}
A bus error usually means that you're accessing a pointer with an invalid value - e.g. an address that is out of the address space.
I would guess that in this case, it is because you are trying to write to memory that is read-only. The string "hello world" is in a memory segment that you are not allowed to write to. Depending on the operating system, these memory segments are either protected or you can write arbitrary garbage to it. Seems like yours doesn't allow it. As you can see in the other answers, you can work around this by copying/initializing the string constant into an array.
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.