What I am trying to do is, take the message from the user input and reverse the string. So, I am using 2 pointers, one is pointing at the first element of the message array and the other is pointing to the last element. And then I am doing the swap until the two pointers meet.
#include <stdio.h>
#include <string.h>
void reverse(char* message);
int main()
{
char message[100];
printf("Enter a message: ");
scanf("%s",message);
printf("\nok");
reverse(message);
printf("ok \n");
printf("%s",message);
return 0;
}
void reverse(char* message){
char* p = message;
char* temp = message;
char* q = (message + (strlen(message)); // pointing to the last element before
// null character
printf("\ncoming");
while( p != q){
// why am I getting a segmentation fault? whats happening?
*p = *q;
*q = *temp;
p++;
q--;
temp = p;
}// while loop
}// reverse
This line
char* q = (message + (strlen(message));
Does it point to the last character.
Consider a message of one character - strlen(message) will by one. But the first character would be char * q = message
So the line should read
char* q = (message + strlen(message) - 1;
Also the swap is a be awry
Try
char temp;
Instead then instead of
*p = *q;
*q = *temp;
p++;
q--;
temp = p;
Use
temp = *p; // We got the temp
*p = *q; // Old p is safe - it is now temp.
*q = temp;
p++;
q++;
With this code the null character is not reversed! Hence in the right place!
Finalluy,
while( p != q){
Should be
while( p < q){
regarding:
p++;
q--;
After the above statements, the pointers can have passed each other. Then the loop keeps running until the seg. fault occurs
I fixed the while loop condition. Now i gave while(p < q) but the swapping isnt happening, can anyone explain why?
Both pointers p and temp are pointing at message:
char* p = message;
char* temp = message;
When *p = *q; is executed in the while loop, the character pointed by "p" and the character pointed by "temp", get updated with the character at "q" (because of the above declarations).
The next line *q = *temp; is essentially copying the newly updated character("*q") back to "q".
In addition, as pointed out by "M Oehm", the line
message + strlen(message), points at the NULL character, instead of the last character before NULL.
Also note the comment posted by "user3629249" regarding the missing parentheses.
Correcting these your code should look like...
void reverse(char* message){
char* p = message;
char* temp = message;
char* q = (message + strlen(message)-1); // pointing to the last element
char c; //to store the value of "temp"
printf("\ncoming");
while( p < q){
c = *temp;
*p = *q;
*q = c;
p++;
q--;
temp = p;
}// while loop
}// reverse
Having said this, since "C" passes parameters by value, you could implement the same function, like so....
void reverse(char* message){
char* q = (message + strlen(message)-1);
char c;
while( message < q){
c = *message;
*message = *q;
*q = c;
message++;
q--;
}
}
A segmentation fault is caused by a program trying to read or write an illegal memory location. With both p++ and q-- the while (p != q) can be always true, for instance if p and q point at 2 consecutive characters. Check this approach for string reversing:
#include <string.h>
void reverse(char *str)
{
//skip null string
if (str == 0)
{
return;
}
// skip empty string
if (*str == 0)
{
return;
}
// get range
char *start = str;
char *end = start + strlen(str) - 1; // -1 for the end \0
char temp;
// reverse
while (end > start)
{
// swap chars
temp = *start;
*start = *end;
*end = temp;
// move to next position
++start;
--end;
}
}
int main(void)
{
char s1[] = "Stack Overflow is GREAT!";
reverse(s1);
printf("%s\n", s1);
return 0;
}
Related
I am trying to create a function that extract the extension from a file name. file_name points to a string containing a file name. The function should store the extension on the file name in the string pointed to by extension. For example, if the file name is “memo.txt”, the function will store “txt” in the string pointed to by extension. If the file name doesn’t have an extension, the function should store an empty string (a single null character) in the string pointed to by extension.
This is what I have:
#include <stdio.h>
void get_extension(char *file_name, char *extension);
int main(){
char *ex;
get_extension("hello.txt", ex);
char *p;
for(p = ex; *p != '\0'; p++){
printf("extension: %c", *p);
}
return 0;
}
void get_extension(char *file_name, char *extension){
char *p;
for (p = file_name; *p != '\0'; p++){
if(*p == '.'){
p++;
while(*p != '\0'){
*extension = *p;
p++;
extension++;
}
} *extension = '\0';
}
}
I keep getting a segmentation fault error and I don't know what is wrong.
Can someone help me, please?
Thanks!
There can be 2 reasons for your seg fault.
1) ex doesn't point to any memory. So inside the function you write to a memory location using an uninitialized pointer. That's real bad.
2) In the function the inner while loop continues until end-of-string. Then the outer loop increments p and dereferences it. So you read beyond end-of-string which is again real bad.
Try like:
#include <stdio.h>
#define MAX_EXT_LEN 100
void get_extension(char *file_name, char *extension, int sz);
int main(){
char ex[MAX_EXT_LEN]; // Create an array to store the data
get_extension("hello.txt", ex, sizeof ex);
char *p;
printf("extension: ");
for(p = ex; *p != '\0'; p++){
printf("%c", *p);
}
return 0;
}
void get_extension(char *file_name, char *extension, int sz){
char *p = file_name;
if (file_name == NULL || extension == NULL || sz < 1) return;
while (*p != '\0' && *p != '.') ++p;
if(*p == '.') ++p;
int cnt = 0;
while(*p != '\0' && cnt < (sz-1)){
extension[cnt] = *p;
++p;
++cnt;
}
extension[cnt] = '\0';
}
You should change this part:
int main(){
char *ex;
into something that not only declares a pointer, but allocates the memory to store the result:
int main(){
char ex[100];
Besides I'd recommend you to take a look at strrchr() that can help you to find the extension much easier: Getting file extension in C
Also I would like to notice that this code:
char *p;
for(p = ex; *p != '\0'; p++){
printf("extension: %c", *p);
}
will not work as you think it might. For example for the "hello.txt" is will print:
extension: textension: xextension: t
Not sure if this is what you want.
I keep getting segmentation fault when i try and compile this. Do i need a check possibly for even and odd? I know it means im trying to get memory that i dont have but im not sure where im making the mistake. This is C also.
#include<stdio.h>
int main()
{
char str[41], even[21], odd[21], *p, *pstr, *e, *o;
printf("Enter a string (40 characters maximum):");
scanf("%s", str);
*p=str[0];
*pstr=str[0];
for(*p=even[0]; *p != '\0';p++){
if((p-pstr) % 2 == 0){
*e=*p;
e++;
} else{
*o=*p;
o++;
}
}
*o = '\0';
*e = '\0';
printf("The even string is:%s", even);
printf("The odd string is:%s", odd);
return 0;
}
There is some confusion regarding the initialization of pointers in your code:
*p = str[0] copies the first character from str to the address pointed to by p, which is uninitialized, hence causes undefined behavior.
you should instead initialize the value of p to the address of str[0]:
p = &str[0];
which can be simplified as
p = str;
Here is a corrected version:
#include <stdio.h>
int main(void) {
char str[41], even[21], odd[21], *p, *pstr, *e, *o;
printf("Enter a string (40 characters maximum):");
if (scanf("%40s", str) == 1) {
e = even;
o = odd;
for (p = pstr = str; *p != '\0'; p++) {
if ((p - pstr) % 2 == 0) {
*e = *p;
e++;
} else {
*o = *p;
o++;
}
}
*o = '\0';
*e = '\0';
printf("The even string is: %s\n", even);
printf("The odd string is: %s\n", odd);
}
return 0;
}
p has no allocated memory, you can set p = str but not copy the char in str[0] to a random memory address, since p never allocated some memory where it points to.
I'm getting a segmentation fault error when trying to print out a char array in C
#include <stdio.h>
void printLoop(char args[])
{
char* p;
for (*p = *args; *p != '\0'; p++)
{
printf("%s", p);
}
getchar();
}
int main()
{
char *text = "Test";
printLoop(text);
}
I'm receiving:
Segmentation fault: 11
I've read that it has something to do with me allocating to much space for the array but I don't really understand why I'm getting this.
When you write *p = *args, you're assigning the value of the character pointed to by args to the value of p, but you haven't assigned p, so you can't dereference it.
You need to change
for (*p = *args; *p != '\0'; p++)
to
for (p = args; *p != '\0'; p++)
That assigns the pointer args to the pointer p.
After you do that, if you're only trying to print "Test", then you can't keep printing the entire string pointed to by p in each iteration of the loop.
You need to change
printf("%s", p);
to
printf("%c", *p);
or even
putchar(*p);
Because you want to print the character pointed to by p, not the string pointed to by p.
After assigning char *p = args;, Loop as
while(*p != '\0')
or
for(p = args, *p != '\0' ; p++)
and change printf("%s", *p); to printf("%c", *p);, since you are printing it char by char.
Needless to say, increment p in loop if used in a while loop.
You were using %s which is used to print a string at once, so at the first iteration it printed Test and then p was incremented, it printed est and so on..
You need to print a char pointed by p, one char at a time.
#include<stdio.h>
char* my_strcpy(char*,const char*);
int main(){
char a[20];
char* s = "Hello world!";
char* d = a;
my_strcpy(d,s);
printf("\n d : %s \n",d);
return 0;
}
char* my_strcpy(char* dest,const char* sour){
if(NULL == dest || NULL == sour){
return NULL;
}
while(1){
*dest++ = *sour++;
if(*sour == '\0'){
*dest = *sour;
break;
}
}
}
why do we need the char* as a return type for my_strcpy. If the d is " " it gives me a segmentation fault. If I assign it with a it works fine. Why does it give seg fault when given "".
MODIFIED : After the answers
#include<stdio.h>
char* my_strcpy(char*,const char*);
int main(){
char* ret;
char a[20];
char* s = "Hello world!";
char* d = "";
ret = my_strcpy(d,s);
if(NULL == ret){
perror("\nret");
}
// printf("\n d : %s \n",d);
return 0;
}
char* my_strcpy(char* dest,const char* sour){
char* temp;
if(NULL == dest || NULL == sour){
return NULL;
}
temp = dest;
while(1){
*temp++ = *sour++;
if(*sour == '\0'){
*temp = *sour;
break;
}
}
return temp;
}
This still gives a segfault. How to handle the condition if s="" when passed to the function strcpy.
You asked: "If the d is " " it gives me a segmentation fault."
Answer:
If you assign "" or " " to d, there will not be enough space to fit "Hello World". Moreover, a constant string if assigned to a memory page tagged as data might not allow modification.
You asked "why do we need the char* as a return type for my_strcpy" as the original strcpy I presume.
Answer:
You do not have to. You could have void as return type. However, it makes it practical if one is to do something like this:
printf ("%s", strcpy (dest, sour));
Corrected code:
while(1){
*dest++ = *sour++;
if(*(sour-1) == '\0'){
break;
}
or better:
while(*sour != '\0'){
*dest++ = *sour++;
}
*dest = *sour;
Here you:
Assign the value at *sour to *dest
Increment both sour and dest so now the point to the next characters
Test if *dest is now NUL to exit the loop
As you can see, the 3rd step reads from uninitialized memory. You should test if the value that was assigned before incrementing was NUL.
*dest++ = *sour++;
if(*dest == '\0'){
break;
}
If the dest you pass in is a constant string like " " you get a segfault because string constants are stored in read-only memory. They cannot be modified.
Correct:
if(*dest == '\0'){
should be:
if(*(dest - 1) == '\0'){
Note:
*dest++ = *sour++;
is equivalent to
*dest = *sour;
sour++;
dest++;
You increments dest after assignment, and so you are checking \0 at position where garbage value present as you don't initialize a[] -causes Undefined behaviour. Additionally you don't return after while loop.
You can simply write your function as:
char* my_strcpy(char* dest,const char* sour){
if(NULL == dest || NULL == sour)
return NULL;
char* d = dest;
while(*dest++ = *sour++)
;
return d;
}
Give it a try!!
here is a simple version:
char *my_strcpy(char *d, const char *s){
int i=0;
while(d[i++]=*s++)
/*done inside condition*/;
return d;
}
I would advise to implement strcpy as:
char* my_strcpy (char* s1, const char* s2)
{
char* return_val = s1;
*s1 = *s2;
while(*s2 != '\0')
{
s1++;
s2++;
*s1 = *s2;
}
return return_val;
}
Always avoid multiple ++ statements in the same expression. There is never a reason to do so and it will sooner or later give you a handful of undefined/unspecified behavior bugs.
#include<stdio.h>
#include<malloc.h>
#include<string.h>
#define SUCCESS 0
#define FAILURE -1
int str_rev(char **s, char **d){
int count = 0;
if(s == NULL || d == NULL){
printf("\n Invalid address received! \n");
return FAILURE;
}
else{
while(**s != '\0'){
**s++;count++;
}
while(count > 0){
**d++ = **s--;count--;
}
**d = '\0';
return SUCCESS;
}
}
int main(){
int ret_val = SUCCESS;
char *a = "angus";
char *b;
b = malloc((strlen(a) * sizeof(*a)) + 1);
ret_val = str_rev(&a,&b);
if(ret_val == FAILURE){
printf("\n String is not reversed! going to quit! \n");
free(b);
return FAILURE;
}
printf("\n b:%s \n",b);
free(b);
return SUCCESS;
}
I am writing a simple program without the use of predefined function for string reversal. But this throws me a segmentation fault. I beleive i'm accessing the correct memory address.
EDITED:
#include<stdio.h>
#include<malloc.h>
#include<string.h>
#define SUCCESS 0
#define FAILURE -1
int str_rev(char *s, char **d){
int count = 0;
if(s == NULL || d == NULL){
printf("\n Invalid address received! \n");
return FAILURE;
}
else{
while(*s != '\0'){
s++;count++;
}
s--;
while(count > 0){
printf("\n *s:%c \n",*s); // prints the values correctly in the reverse order
*(*d)++ = *s--;count--;
printf("\n **d:%c \n",*((*d)-1)); // doesnt print the values, after the assignement
}
**d = '\0';
printf("\n s:%s *d:%s \n",s,*d); // both s and d doesnt print the values copied
return SUCCESS;
}
}
int main(){
int ret_val = SUCCESS;
char *a = "angus";
char *b,*x;
b = malloc((strlen(a) * sizeof(*a)) + 1);
x = b;
if(b == NULL){
}
ret_val = str_rev(a,&b);
if(ret_val == FAILURE){
printf("\n String is not reversed! going to quit! \n");
free(b);
return FAILURE;
}
printf("\n b:%s \n",b);
free(b);
return SUCCESS;
}
I changed the code as above, as 'a' contains the string. hence a single pointer is enough to point to that location as no changes needs to be done. But even after this above change The contents in 's' are not getting copied to 'd'. And i'm getting a seg fault after printing "printf("\n b:%s \n",b);" .
In addition to memory allocation problem also second problem in your code:
First
after your copy loop:
while(count > 0){
**d++ = **s--;count--;
}
You do not terminate d string ny null
add
**d= '\0';
Second: after your first loop
while(**s != '\0'){
**s++;count++;
}
You copy from Null do destination first char become '\0' then how you can print using %s
you should decrements s to point back to last char instead of null char. by --s.
Third
memory allocation do like:
char *a = "angus";
char *b;
b = malloc(strlen(a)*sizeof(*a) + 1);
don't forget to free() memory for b
Four
Next is you forgot to return return SUCCESS; from str_rev()
Firth
you are passing pointer to pointer that change the b and 's' value it self in calling function. When you call with &s and modifies s then no string points to "angus" string.
Do like below I coded you logic using single pointer instead.
int str_rev(char *s, char *d){
int count = 0;
if(s == NULL || d == NULL){
printf("\n Invalid address received! \n");
return FAILURE;
}
else{
while(*s != '\0'){
s++;
count++;
}
count;
--s;
while(count > 0){
*d = *s;
// printf("\n %c %c", *d, *s);
d++ ;
s--;
count--;
}
*d = '\0';
}
return SUCCESS;
}
in main just call as:
ret_val = str_rev(a, b);
EDIT: Second Code
I notice you are not happy with my suggestion to use single pointer for both!
Well in your second (EDIT) there are some repeating errors:
(1): From function str_rev() your again forgot to return SUCCESS.
(2): Your syntax for str_rcv function is int str_rev(char *s, char **d), first argument is char* but in main() you call it like ret_val = str_rev(&a,&b); that is wrong incompatibly pointer assignment. you should call like:
ret_val = str_rev(a, &b);
(3): IMPORTANT FOR YOU: In second argument you are passing &b Where as in str_rev() function you are updating d pointer hence updating b to which you allocated memory through malloc(), You can't do that!
This will cause an error also: memory clobbered before allocated block
You should rectify your code to call like this: (read comments please)
b = malloc((strlen(a) * sizeof(*a)) + 1);
if(b == NULL){
return FAILURE; // added this line too
}
char* x = b; // first assign b to x, notice x and b are of
// same type char*
ret_val = str_rev(a,&x); // know pass &x instead of &b
(4): although my previous code also working get new version too:
#define SUCCESS 0
#define FAILURE -1
int str_rev(char *s, char **d){
int count = 0;
if(s == NULL || d == NULL){
printf("\n Invalid address received! \n");
return FAILURE;
}
else{
while(*s != '\0'){
s++;count++;
}
s--;
while(count > 0){
*(*d)++ = *s--;
printf("\n *s:%c And **d: %c\n",*(s+1), *((*d)-1)); // for bug finding
// because s decremented and d incremented
count--;
}
**d = '\0';
return 0;
}
}
the main function():
int main(){
int ret_val = SUCCESS;
char *a = "angus";
char *b;
b = malloc((strlen(a) * sizeof(*a)) + 1);
if(b == NULL){
return -1;
}
char* x = b;
ret_val = str_rev(a,&x);
if(ret_val == FAILURE){
printf("\n String is not reversed! going to quit! \n");
free(b);
return FAILURE;
}
printf("\n b:%s \n",b);
free(b);
return SUCCESS;
}
Its working Output is:
*s:s And **d: s
*s:u And **d: u
*s:g And **d: g
*s:n And **d: n
*s:a And **d: a
b:sugna
Here your running code at Codpad
Here:
**s++
you are incrementing the char ** s. This alters it to point to the next char * which is not meaningful in your program.
Because of operator precedence, **s++ is the same as (*(*(s++)). Which is to say, it returns the value of the char pointed to by the char * pointed to by s, and as a side-effect increments s to point to the 'next' char * (which isn't well-defined because you do not have an array of char *s).
A typical idiom in C string manipulation is *p++, which is the same as (*(p++)). This returns the value of the char pointed to by p and as a side effect sets p to point to the next char, which would be the next character in the string. To do the same with a char ** one must write *(*p)++, or more explicitly (*((*p)++)).
Also, it is not necessary to use char **s to reverse a string; it can be done with only char *s.
In this line
b = malloc(sizeof(b));
sizeof(b) is just the size of a pointer and that is not ehough to fit a whole string.
Either pass the size you want to malloc
b = malloc(42);
b = malloc(strlen(a) + 1);
or change b into an array instead of a pointer
char b[42];
Other than that, I would highly recommend learing to use tools like gdb or valgrind to debug these segmentation faults. At the least they will tell you what line is segfaulting and just that will help a lot.
Change ret = str_rev(&a,&b); to ret_val = str_rev(&a,&b);
Please find a reworked function as below
int str_rev(char **sinp, char **dout){
int count = 0;
char *s = *sinp; // Dereference the starting address of source
char *d = *dout; // Dereference the starting address of destination
if(s == NULL || d == NULL){
printf("\n Invalid address received! \n");
return FAILURE;
}
else{
while(*s != '\0'){
*s++;count++;
}
s--; // Requires a decrement as it is pointing to NULL
while(count > 0){
*d++ = *s--;
count--;
}
}
*d = '\0'; // Need a NULL terminator to convert it to string
return SUCCESS; // Requires a return as all branches of function should return values
}
char str[] = "hello";
char *foo = foo;
*foo++ is the equivalent to *(foo++), not (*foo)++. foo++ causes foo to point to the next char.
char str[] = "hello";
char *foo = str;
char **bar = &foo;
**bar++ is the equivalent to **(bar++);, not (**bar)++. bar++ causes bar to point to the next char *... Do you see a problem?
(*bar)++ causes foo to point to the next char. consider what you'd be doing to your caller's a and b variables in ret_val = str_rev(&a,&b);, (*s)++; and (*d)++.