-2

I'm trying to make an startswith function which if i had a string consists of
"Hello I am kira"
will split into the first word
"Hello" Only

and I really tried my best to get it to this form

#include <stdio.h>
unsigned char *startswith(unsigned char *str)
{
    char *result;
    char *cstr = (char *)str;     
    for (int i=0; cstr[i] != ' '; i++)
       result[i] = cstr[i];
    return(result);
}

int main()
{
    printf("%s\n",startswith("What is your name momo?"));
    return 0;
}

which should print "in my imagination"

What

and an newline then exit with 0 but i get the unknown holy error when compiling

Segmentation fault

I can't understand why that happens or even locate the problem
gcc doesn't help or show me warnings

stdio.h header was just to print the result no more
I know there's a way to achieve this without using any standard libraries but i need leading

Thanks!

  • 1
    You must understand what goes on stack in the memory model. `result` is local to function and scope ends in the function itself. – Milind Deore Sep 01 '17 at 04:29
  • for that i made it pointer (*) and by the way it doesn't work even if inside the scope. –  Sep 01 '17 at 04:34
  • So now you have a pointing to a location which is not present, as the function has exited and locals are popped. Do you think that makes sense? Pointer doesn't mean dedicated allocation and therefore you need memory from heap as mentioned in the answer below. – Milind Deore Sep 01 '17 at 04:37
  • 1
    @KiraSama `char *result;` declares an *uninitialized character pointer that points nowhere*. You need to allocate memory and make `result` point to that block, e.g. `char *result = calloc (strlen (str) + 1, 1);` and then validate the allocation with `if (result == NULL) { /* handle error */ }`, then enter your for loop. – David C. Rankin Sep 01 '17 at 04:43
  • nice code to handle errors it gave me "`(null)`" in other compiler in **android** while in gcc "`Segmentation fault`" and you alright I noticed this now, i was all time thinking that the problem from (`for-loop`) cause that "`Segmentation fault`" which i didn't know that this var is `uninitialized` if it shows ('null') maybe i was be able to figure it out instead of editing `for-loop` multiple times.. –  Sep 01 '17 at 04:51
  • 1
    Compile with all warnings and debug info (e.g. `gcc -Wall -Wextra -g` with [GCC](http://gcc.gnu.org/)...) then learn how to **use the debugger** `gdb` and [valgrind](http://valgrind.org/) – Basile Starynkevitch Sep 01 '17 at 05:13
  • I remember using the debugger when i was windows in visual-studio, i'm new to linux by the way but learnt a lot thanks for the note –  Sep 01 '17 at 05:15
  • @KiraSama - that's how we all learn. This won't be the last time you beat your head into the wall over something -- that once you see it makes perfect sense. See [**How to debug small programs**](https://ericlippert.com/2014/03/05/how-to-debug-small-programs/) and talk to the duck... Really, it helps `:)` – David C. Rankin Sep 01 '17 at 05:16
  • I appreciate all your help despite i'm new and maybe i get stuck on trivial things that i can't notice thinking that the problem from else but you show me the mistake and why with how to fix, i'm glad to be in this community :) Thanks for the link –  Sep 01 '17 at 05:23

3 Answers3

3

Allocate some memory in result. result=malloc(sizeof(char)*MAXLEN);

Now you are accessing some garbage value stored in result.

Accessing a uninitialized variable is Undefined Behavior.


  • Also you can allocate strlen(str)+1 as it you know no matter what the result can at most be as long as the str.

  • $7.20.3.1 Another point is that you can use calloc function for which the space is initialized to all bits zero.This has the benefit of always having a null terminated string , even if you accidentally omit nul-termination1

1. Pointed by David C. Rankin

user2736738
  • 30,591
  • 5
  • 42
  • 56
  • Thanks! now i can see what my code does and improve it I was trying to make it with no library but that way gave me a hint :) –  Sep 01 '17 at 04:40
  • 2
    You might as well allocate `strlen (str) + 1` chars for `result` as it never needs to be longer than that. If you use `calloc` instead of `malloc` you will initialize all memory to `0` (insuring you will always have a *nul-terminated* string, if you *accidentally* omit the nul-termination) – David C. Rankin Sep 01 '17 at 04:45
  • @DavidC.Rankin.: Thanks for the addition. Check my answer now. – user2736738 Sep 01 '17 at 04:57
  • 1
    Like, more complete and gives the OP options (and some additional learning `:)` – David C. Rankin Sep 01 '17 at 05:11
2

Basically what u are doing here is using a pointer which has no memory allocated .you need to allocate memory to result variable using malloc, for this u need to include stdlib.h

#include <stdio.h>
#include<stdlib.h>
#define MAXLEN 1000
unsigned char *startswith(unsigned char *str)
{
    char *result = malloc(sizeof(char)*MAXLEN);
    char *cstr = (char *)str;     
    for (int i=0; cstr[i] != ' '; i++)
    result[i] = cstr[i];
    return(result);
}

int main()
{
    printf("%s\n",startswith("What is your name momo?"));
    return 0;
}
Omniverse10
  • 134
  • 2
  • 15
  • That's a good start but it creates a memory leak because the pointer returned from `startswith()` is never passed to `free()`. A better solution would be to assign the return value from `startswith()` to a `char` pointer variable that could then be passed to `free()` after it is used by the `printf()` function. A still better solution would be to pass an already-allocated block of memory to `startswith()` so that the caller could uniformly look after the memory management, following the pattern of [strncpy()](http://www.cplusplus.com/reference/cstring/strncpy/). – Simon Sep 01 '17 at 04:38
  • oh ,yes! i didn't used it here...using free() is good habit of writing efficient code. Thanks for pointing that out! – Omniverse10 Sep 01 '17 at 04:41
0

A bit deeper explanation of what's happening here... You are getting a segfault because you are dereferencing a pointer to memory your process doesn't own. Your char* result pointer is uninitialized, meaning it could have any kind of junk data in it. When you try result[i] = cstr[i], you are invoking undefined behavior (SO won't let me link their undefined behavior documentation anymore), which simply means that from this point forward execution of the program has unpredictable results. In your case, the UB manifests itself with a segfault, although it may not always.

In order to initialize your pointer, you must allocate some space for it using malloc or one of its similar functions. You should also free your memory when you are done using it. Your program is so short, in this case it's not a huge deal (the OS will most certainly clean up any memory allocated to the process when it exits), but it's good to get in the habit.

#include <stdio.h>
#include <string.h>

// this function shouldn't modify str (and in fact modifying a string
// literal like you're passing in would be UB anyway), so make this
// a const char*
char *startswith(const char *str)
{
    // sizeof(char) is defined as 1 in the standard, so you can leave it out of the malloc expression
    char *result = malloc(strlen(str)+1);  // Assuming str has at least 1 space, this will guarantee enough space for result
    if (result == NULL)   // make sure malloc returned some memory for you
    {
        // handle the error here how you want
        fprintf(stderr, "out of memory!\n");
        exit(-1);
    }
    // no need for cstr
    int i;  // move i out of the loop so it will be in scope after the loop
    for (i=0; str[i] != ' '; i++)
       result[i] = str[i];
    // NUL terminate your string
    result[i] = '\0';

    // "return" isn't a function, parenthesis unnecessary.
    return result;
}

int main(void)
{
    // store the returned result to a variable so we can free it
    char* result = startswith("What is your name momo?");
    printf("%s\n", result);
    // clean up the memory
    free(result);
    return 0;
}
yano
  • 4,827
  • 2
  • 23
  • 35