How do I get rid of this Segmentation Fault? - c

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.

Related

Segmentation fault (core dumped) copying form array to string

#include <string.h>
#include <stdio.h>
int main()
{
char str[255] = "Hello;thisnewwolrd";
int i =0;
while(str[i] != ';')
{
i++;
}
i++;
char *name = NULL;
while(str[i] != NULL)
{
name[i] = str[i];
i++;
printf("%c \r\n",name[i]);
}
}
the expected output is thisnewwolrd but i am getting error of core dumped
canany one have reason why and how to over come this
This should work:
int main()
{
char str[255] = "Hello;thisnewwolrd";
char *ptr = strchr(str, ';') + 1;
char name[255];
strcpy( name, ptr);
printf("%s \r\n", name);
}
You don't have to reinvent the wheel, and are much better off using standard library functions for string manipulation.
You have to allocate memory to store your string copy. For example: char *name = malloc(255*sizeof(char));.
And you have to create another iterator than i to start to fill the memory space pointed by name starting at the index 0.

Keep getting segmentation fault (core dumped)

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.

my_strcpy gives seg fault

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

implementation of strstr() function

The code says at many places "invalid indirection".Please help.
int main()
{
char *s1,*s2,*position;
printf("Enter string:\n");
gets(s1);
printf("Enter word to find:\n");
gets(s2);
*position=ststr(*s1,*s1);
if(*position)
printf("word is found at %c loc\n",*position);
else
printf("word not found");
getch();
return 0;
}
char *strstr(char *s1,char *s2)
{
int flag=1;
char i,j;
for(i=0; ;i++)
{
if(*s1[i]==*s2[0])
for(j=i;*s2;j++)
{
if(*s1[j]!=*s2[j])
flag=0;
}
}
if(flag)
return i;
else
return 0;
}
First, s1 and s2 in main have not been initialized to point anywhere meaningful. Either declare them as static arrays, or allocate memory to them at runtime using malloc() or calloc():
#define SIZE 20 // or some number big enough to hold your input
...
char s1[SIZE], s2[SIZE], *position; // s1 and s2 declared statically
Second, NEVER NEVER NEVER NEVER NEVER use gets(); it will introduce a point of failure in your program. Use fgets() instead:
if (fgets(s1, sizeof s1, stdin) != NULL)
// process s1
else
// check for EOF or error on read
EDIT
And like everyone else has pointed out, your comparison in the strstr() function needs to be either
*s1 == *s2
or
s1[i] == s2[i]
but first you need to deal with allocating your buffers in main properly.
One of the problems I'm noticing is whenever you do *s1[j]. The asterisk is dereferencing the array, and so is the [] notation.
s[i] really means *(s + i), so you don't have to dereference it again. The way you have it would read **(s + i), and since it's a single pointer you can't do that.
if(*s1[i]==*s2[0])
is such an example where my gcc complains:
error: invalid type argument of ‘unary *’ (have ‘int’)
if s1 is a pointer to char, s1[i] is a char. So you can't dereference it any more (with the *), i.e. s1[i] does not point to anything any more.
Try
if(s1[i]==s2[0])
instead.
You should also change the return value of strstr: you return an integer where you declare to return a pointer to a character. So try returning s1+i instead.
This here:
for(j=i;*s2;j++)
probably does not what you want. You're not advancing the pointer s2 anywhere in the loop, in fact you're just testing whether s2[0] (which is the same as *s2) is zero for each iteration. If s2 isn't the empty string, this loop will never terminate.
#include "stdio.h"
char *strstr(char *str, char *substr)
{
int len = strlen(substr);
char *ref = substr;
while(*str && *ref)
{
if (*str++ == *ref)
{
ref++;
}
if(!*ref)
{
return (str - len);
}
if (len == (ref - substr))
{
ref = substr;
}
}
return NULL;
}
int main(int argc, char *argv[])
{
printf("%s \n", strstr("TEST IS NOT DONE", "IS NOT"));
}
if(*s1[j]!=*s2[j])
*s1 means "the character where s1 is pointing".
s1[j] means "*(s1+j)" or "the character j positions after where s1 is pointing"
You have to use one or the other; not both.
#include <stdio.h>
char* my_strstr(char *s2, char *s1)
{
int i, j;
int flag = 0;
if ((s2 == NULL || s1 == NULL)) return NULL;
for( i = 0; s2[i] != '\0'; i++)
{
if (s2[i] == s1[0])
{
for (j = i; ; j++)
{
if (s1[j-i] == '\0'){ flag = 1; break;}
if (s2[j] == s1[j-i]) continue;
else break;
}
}
if (flag == 1) break;
}
if (flag) return (s2+i);
else return NULL;
}
int main()
{
char s2[] = "This is the statement";
char s1[] = "the";
char *temp;
temp = my_strstr(s2,s1);
printf("%s\n",temp);
return 0;
}

How to remove \n or \t from a given string in C?

How can I strip a string with all \n and \t in C?
This works in my quick and dirty tests. Does it in place:
#include <stdio.h>
void strip(char *s) {
char *p2 = s;
while(*s != '\0') {
if(*s != '\t' && *s != '\n') {
*p2++ = *s++;
} else {
++s;
}
}
*p2 = '\0';
}
int main() {
char buf[] = "this\t is\n a\t test\n test";
strip(buf);
printf("%s\n", buf);
}
And to appease Chris, here is a version which will make a place the result in a newly malloced buffer and return it (thus it'll work on literals). You will need to free the result.
char *strip_copy(const char *s) {
char *p = malloc(strlen(s) + 1);
if(p) {
char *p2 = p;
while(*s != '\0') {
if(*s != '\t' && *s != '\n') {
*p2++ = *s++;
} else {
++s;
}
}
*p2 = '\0';
}
return p;
}
If you want to replace \n or \t with something else, you can use the function strstr(). It returns a pointer to the first place in a function that has a certain string. For example:
// Find the first "\n".
char new_char = 't';
char* pFirstN = strstr(szMyString, "\n");
*pFirstN = new_char;
You can run that in a loop to find all \n's and \t's.
If you want to "strip" them, i.e. remove them from the string, you'll need to actually use the same method as above, but copy the contents of the string "back" every time you find a \n or \t, so that "this i\ns a test" becomes: "this is a test".
You can do that with memmove (not memcpy, since the src and dst are pointing to overlapping memory), like so:
char* temp = strstr(str, "\t");
// Remove \n.
while ((temp = strstr(str, "\n")) != NULL) {
// Len is the length of the string, from the ampersand \n, including the \n.
int len = strlen(str);
memmove(temp, temp + 1, len);
}
You'll need to repeat this loop again to remove the \t's.
Note: Both of these methods work in-place. This might not be safe! (read Evan Teran's comments for details.. Also, these methods are not very efficient, although they do utilize a library function for some of the code instead of rolling your own.
Basically, you have two ways to do this: you can create a copy of the original string, minus all '\t' and '\n' characters, or you can strip the string "in-place." However, I bet money that the first option will be faster, and I promise you it will be safer.
So we'll make a function:
char *strip(const char *str, const char *d);
We want to use strlen() and malloc() to allocate a new char * buffer the same size as our str buffer. Then we go through str character by character. If the character is not contained in d, we copy it into our new buffer. We can use something like strchr() to see if each character is in the string d. Once we're done, we have a new buffer, with the contents of our old buffer minus characters in the string d, so we just return that. I won't give you sample code, because this might be homework, but here's the sample usage to show you how it solves your problem:
char *string = "some\n text\t to strip";
char *stripped = strip(string, "\t\n");
This is a c string function that will find any character in accept and return a pointer to that position or NULL if it is not found.
#include <string.h>
char *strpbrk(const char *s, const char *accept);
Example:
char search[] = "a string with \t and \n";
char *first_occ = strpbrk( search, "\t\n" );
first_occ will point to the \t, or the 15 character in search. You can replace then call again to loop through until all have been replaced.
I like to make the standard library do as much of the work as possible, so I would use something similar to Evan's solution but with strspn() and strcspn().
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define SPACE " \t\r\n"
static void strip(char *s);
static char *strip_copy(char const *s);
int main(int ac, char **av)
{
char s[] = "this\t is\n a\t test\n test";
char *s1 = strip_copy(s);
strip(s);
printf("%s\n%s\n", s, s1);
return 0;
}
static void strip(char *s)
{
char *p = s;
int n;
while (*s)
{
n = strcspn(s, SPACE);
strncpy(p, s, n);
p += n;
s += n + strspn(s+n, SPACE);
}
*p = 0;
}
static char *strip_copy(char const *s)
{
char *buf = malloc(1 + strlen(s));
if (buf)
{
char *p = buf;
char const *q;
int n;
for (q = s; *q; q += n + strspn(q+n, SPACE))
{
n = strcspn(q, SPACE);
strncpy(p, q, n);
p += n;
}
*p++ = '\0';
buf = realloc(buf, p - buf);
}
return buf;
}

Resources