This question already has an answer here:
String literals: pointer vs. char array
(1 answer)
Closed 2 months ago.
I am trying to reverse string using pointer (ref source). in function
string_reverse
Bus Error happened at this line when copying character from char pointer end to start char pointer :
*start = *end;
I tried LLDB in VS code. .
Can some one explain why there is bus error happened at below line?
*start = *end
Full code below:
#include <stdio.h>
#include <string.h>
void string_reverse(char* str)
{
int len = strlen(str);
char temp;
char *end = str;
char *start = str;
/* Move end pointer to the last character */
for (int j = 0; j < len-1; j++)
{
end++;
}
for(int i = 0; i< len/2;i++ )
{
temp = *start;
*start = *end;
*end = temp;
/* update pointer positions */
start++;
end--;
}
}
int main( void )
{
char *str = "test string";
printf("Original string is %s\n", str);
string_reverse(str);
printf("Reverse string is %s\n", str);
return 0;
}
Actual result: Bus Error happened at line
*start = *end;
Expected output:
Reverse string is gnirts tset
The error happens because
char * str = "...";
mean you have a pointer to a string literal. It's a constant string that you can not modify.
When you change it to
char str[] = "...";
as chux-reinstate-monica mentioned, str will be char array with the length of your string, and you can modify it without any error.
Related
I am working on a string reversal problem where I am trying to swap values from two ends with one another. As a part of the reverse function, I have a line that checks whether the pointer has reached the end-of-string character (in the form of while(*end!= '\0')). However, this doesn't seem to be working, and at the end of the while loop when I de-reference "end" I get blank. When I use (while(*end)), everything works perfectly but I have to then decrement my pointer "end" to make sure I am accessing the last element of my string. Why can't I check the pointer against the string literal '\0'?
#include<stdio.h>
void reverse(char* s);
void main(){
char str[]="abcdef";
printf("%s\n",str);
reverse(str);
printf("%s\n",str);
}
void reverse(char* p){
char* start = p;
char* end = p;
char tmp;
int length =0;
while(*end!='\0'){
end+=1;
length+=1;
}
printf("%c\n",*end); // problem line
int c;
for (c = 0; c < length/2; c++)
{
tmp = *start;
*start = *end;
*end = tmp;
start++;
end--;
}
//printf("%s\n",p);
}
In the //Problem line the value of *end is '\0' - You should print the integer value of '\0' to verify which is 0 & it works - apart from that you'll need to uncomment the } from reverse function.
'\0' is a non printable character: Reference: Non-printable and Printable ASCII Characters
#include <stdio.h>
#include <string.h>
size_t mystrlen(const char *str)
{
const char *ptr = str;
while(*ptr++);
return ptr - str;
}
char *reverse(char *str)
{
size_t len = mystrlen(str);
char *end = str + len -1;
char *saved = str;
len /= 2;
while(len--)
{
char tmp = *str;
*str++ = *end;
*end-- = tmp;
}
return saved;
}
int main(void)
{
char str[] = "This is the string which will be reversed";
printf("%s\n", reverse(str));
}
your code works. end reaches '\0'. but printf prints string until the first '\0'. so your print appears empty. if you add after the while loop:
--end;
or change the while to: while(*(end+1))
your code will do what you want it to
You don't need the length variable, and you can use pre-decrement on end.
#include <stdio.h>
void reverse(char *start);
int main(void) {
char str[]= "abcdef";
printf("%s\n", str);
reverse(str);
printf("%s\n", str);
}
void reverse(char* start) {
char *end = start;
while(*end != '\0') {
end++;
}
while(start < end) {
char temp = *--end;
*end = *start;
*start++ = temp;
}
}
This question already has answers here:
What is the difference between char s[] and char *s?
(14 answers)
Definitive List of Common Reasons for Segmentation Faults
(1 answer)
Closed 5 years ago.
I have the following code to split strings by tokens:
char **strToWordArray(char *str, const char *delimiter)
{
char **words;
int nwords = 1;
words = malloc(sizeof(*words) * (nwords + 1));
int w = 0;
int len = strlen(delimiter);
words[w++] = str;
while (*str)
{
if (strncmp(str, delimiter, len) == 0)
{
for (int i = 0; i < len; i++)
{
*(str++) = 0;
}
if (*str != 0) {
nwords++;
char **tmp = realloc(words, sizeof(*words) * (nwords + 1));
words = tmp;
words[w++] = str;
} else {
str--;
}
}
str++;
}
words[w] = NULL;
return words;
}
If I do this:
char str[] = "abc/def/foo/bar";
char **words=strToWordArray(str,"/");
then the program works just fine but if I do this:
char *str = "abc/def/foo/bar";
char **words=strToWordArray(str,"/");
then I get a segmentation fault.
Why is that? The program expects a char* as an argument then why does a char* argument crash the program?
Because the function contains:
*(str++) = 0;
which modifies the string that was passed to it. When you do:
char *str = "abc/def/foo/bar";
str points to a read-only string literal. See the section titled Attempting to modify a string literal in this question:
Definitive List of Common Reasons for Segmentation Faults
1.) Is it possible to reverse a string including the NULL character
(which means that “abcd” is represented as five characters, including the null character.)
2.) In my current implementation, that doesn't take 1.) into account,
I am getting segmentation error during swapping. ie while assigning: *str = *end;
void reverse(char *str)
{
char * end = str;
char tmp;
if (str)
{ // to handle null string
while (*end)
{ // find the end character
++end;
}
--end; // last meaningful element
while (str < end) // terminal condition: str and end meets in the middle
{ tmp = *str; // normal swap subroutine
*str = *end; // str advance one step
*end = tmp; // end back one step
str++;
end-- ;
}
}
return;
}
Your function is correct. It seems that the problem is that you are trying to reverse a string literal. You may not change string literals. They are immutable. Any attemp to change a string literal results in undefined behaviour of the program.
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
Only take into account that it would be better to write
if ( *str )
instead of
if (str)
Or if you want to check that the poinetr is not NULL then
if ( str && *str )
In this case this decrement
--end;
will be valid even if the original string is empty.
Nevertheless the function itself could be defined the following way as it is shown in the demonstrative program
#include <stdio.h>
char * reverse( char *s )
{
char *last = s;
while ( *last ) ++last;
if ( last != s )
{
for ( char *first = s; first < --last; ++first )
{
char c = *first;
*first = *last;
*last = c;
}
}
return s;
}
int main( void )
{
char s[] = "Hello arshdeep kaur";
puts( s );
puts( reverse( s ) );
}
The program output is
Hello arshdeep kaur
ruak peedhsra olleH
Calling your code like this:
int main()
{
char a[]="abcd";
int i;
reverse(a);
for (i=0;i<5;i++) {
printf("a[%d]=%02x\n",i,a[i]);
}
}
Outputs this:
a[0]=64
a[1]=63
a[2]=62
a[3]=61
a[4]=00
So you're probably passing in a string literal (i.e. char *a="abcd";). These literals are commonly stored in a read-only section of memory, which is likely why it is core dumping.
That being said, doing a reversal including the null character is not of much practical usage when you're dealing with strings.
I'm quite certain you can. You just need the length of the string and be aware to test NUL.
Strings can and probably should be thought of as character arrays. In particular, trying to direction assign a string literal to an already initialized string is an invalid operation.
An Example:
Here is one way to reverse a string:
void reverse(char *str) {
// First calculate the length
unsigned int length = 0;
int i = 0;
for (; str[i] != '\0'; i++) {
++length;
}
++length;
// Allocate temporary storage
char tmp = malloc(length);
int x = 0;
// Loop through starting at the end and go backwards
// It is perfectly legal to change the characters themselves, just not the pointer
for (i = length - 1; i >= 0; i++, x++) {
if (str[i] != '\0') {
tmp[x] = str[i];
}
}
tmp[length - 1] = '\0';
// Reassign to the given argument
for (i = 0; i < length; i++) {
str[i] = tmp[i];
}
// Free memory
free(tmp);
}
Like the other answer stated, you're trying to do something that is left as undefined behavior in the standard.
You can try this :
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 need to split a char array into CSV's. Actually we can do the reverse of it using strtok() like:
#include <stdio.h>
#include <string.h>
int main ()
{
char str[] ="This,a,sample,string.";
char * pch;
printf ("Splitting string \"%s\" into tokens:\n",str);
pch = strtok (str,",");
while (pch != NULL)
{
printf ("%s\n",pch);
pch = strtok (NULL, ",");
}
return 0;
}
But in my case, there's an char array suppose char bits[1024]="abcdefghijklmn". I need to get the output as a,b,c,d,e,f,g,h,i,j,k,m,n.
Is there any function or library to do this i.e. in terms of raw meaning, for every character it has to put a comma.
Just iterate over the string until you hit the end-of-string '\0' character. Or use the length of the data in the array (which may be smaller than the array size) and use a simple for loop.
This works for a null terminated string. But it will leave a dangling comma at the end.
void tokenise(char *s, char *d)
{
while(*d++ = *s++) *d++ = ',';
}
If you know the length of the string already, you can pass that through. This will not leave a dangling comma.
void tokenise(char *s, char *d, int length)
{
int i = 0;
while((*d++ = *s++) && ((i++)<(length-1))) *d++ = ',';
}
In both examples, s is a pointer to the source string and d points to the output tokenised string. It is up to the calling code to ensure the buffer d points to is sufficiently large.
you can use this simple function from old basic :
// ............................................................. string word at
char * word_at(char *tString, int upTo, char *dilim) {
int wcount;
char *rString, *temp;
temp= (char *) malloc(sizeof(char) * (strlen(tString)+1));
strcpy(temp, tString);
rString= strtok(temp, dilim);
wcount=1;
while (rString != NULL){
if (wcount==upTo) {
return rString;
}
rString= strtok(NULL, dilim);
wcount++;
}
return tString ;
}
parameter : string , index and character delimiter
return : word : ( char *)
If you find easy to implement it, then this could help you to start
char* split_all( char arr[], char ch )
{
char *new, *ptr;
new = ptr = calloc( 1, 2*strlen( arr ) ); // FIXME : Error checks
for( ; *(arr + 1) ; new++, arr++ )
{
*new = *arr;
new++;
*new = ch;
}
*new = *arr;
return ptr;
}
You can re-use, optimize this for your requirement. Its a quick and dirty solution, feel free to fix it..
This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Getting Segmentation Fault
/* Reverse a string in place
*/
#import <stdio.h>
void reverse(char * str);
int main()
{
char * string = "This is a string.";
printf("%s\n", string);
reverse(string);
printf("%s\n", string);
}
void reverse(char * str)
{
char * start = str;
char * end = str;
if(0==*str)
return;
//Find the end
for(;0 != *(++end););
end--;
do
{
*end = *end ^ *start;
*start = *end ^ *start;
*end = *end ^ *start;
}while(++start < --end);
}
I'm not sure why this seg faults. Is is because I'm initializing my char * with a constant string?
You are trying to modify a string constant. Replace:
char * string = "This is a string.";
with
char string[] = "This is a string.";
to remedy that.