views:

712

answers:

9

I have the following code in C:

    char *str = "Hello World";
    char *s = malloc(strlen(str));
    int i =0;
    for(;i<strlen(str)-5;i++)
    {
        s += *(str+i);
    }
    printf(s);

It shows nothing. What I want is to get the substring of str stored in s.

In Java I would do the following:

    String str = "Hello World";
    String s="";

    for(int i=0;i<str.length()-5; i++)
        s+=str[i];

    System.out.println(s);

Or instead use the substring method. As String s = str.substring(1,2); for example.

How can I achieve it?

+2  A: 

C strings are pointers to characters in memory, not objects like in other languages. I suggest you Google for an explanation of strings (this one, for example) and then look at the strcpy function defined in string.h.

Javier Badia
+4  A: 

You can't use the += operator on a char* object - it's just a pointer to char. Instead, you'll want to use strncpy, and pass it a pre-allocated buffer, plus a pointer to where in the string you want the copying to begin, and the number of characters you want to copy.

Amber
You can use the += operator on a char * object; but it doesn't do what the questioner wants done.
Jonathan Leffler
+5  A: 

Use the strcpy function.

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

int main(int argc, char *argv[] ) 
{
  char *str = "Hello World";
  size_t length = strlen(str);

  char *s = (char*)malloc(sizeof(char) * (length + 1));

  strcpy(s, str);

  s[length] = '\0'; // makes sure it's NUL terminated

  printf("%s", s);

  free(s);

  return 0;
}

When allocating the destination buffer, pay attention to the fact that strings are terminated by the NUL character.

To only copy a substring, use strncpy:

strncpy(s, str + 6, strlen(str) - 6);

will just copy "World" into s.

In any case, make sure your C strings are NUL terminated before using functions like printf.

See also strcat and strncat. And well, familiarize yourself with C arrays and pointers.

Gregory Pakosz
You're not allocating space for the NUL terminator and you should check malloc's return value. There's no need to cast malloc's return value in C either.
Emerick Rogul
yes i was editing the answer :)
Gregory Pakosz
how can i get substring of str in s?
asel
indeed the cast is not necessary, it's a matter of personal taste in case I move around code from C to C++ projects
Gregory Pakosz
but why do i have to keep the size of s higher than what i want to keep in it?
asel
The size needs to be the number of characters you want + 1 more for the terminating NULL (\0) character. That's the way you mark the end of the string in C.
Ken White
Your strncpy call neglects to NUL-terminate.Also, sizeof(char) is defined to be 1.
jamesdlin
no there is no need to make the destination buffer bigger than necessary
Gregory Pakosz
@jamesdlin sizeof(char) is defined to be 1 but writing it this way conveys the intent: "allocate space for n chars"
Gregory Pakosz
Using strncpy() and strncat() is seldom a good idea. What size do you specify with strncat()? (The answer is the amount of space left after the data that's currently in the target string - not the total amount of space that is available in the target string.) And the non-null terminating behaviour of strncpy() is bad, as is its null padding behaviour. You'd do better with memmove() for strings of known length where null termination is not required.
Jonathan Leffler
+4  A: 

Others have said how to correctly solve this problem (strcat) but the trick is to think about types. C doesn't do ANYTHING magical for you. s is a char*. what happens when you add 3 to a char*? you get another char* that is pointing 3 characters farther down the line. Adding 'a' to a char* is the same as adding 97 (ascii of 'a') to the pointer, and thus pointing to another character far down the array...

I hope that explains what was happening...

Brian Postow
A: 

For substrings in general where you want to omit characters from both the beginning and the end, you should use strncpy or strncat. (Be careful, though: strncpy doesn't necessarily NUL-terminate.)

jamesdlin
A: 

You need to allocate memory for the string that will hold the substring. Maybe something like this:

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

#define LESS 4
#define MAX 10 /*Keep it atleast strlen(str) - LESS + 1*/

int main(int argc, char *argv[] )
{

        char *str = "Hello World";
        char s[MAX]; /* Declare the array to hold the substring.*/
        int i =0,j=0; /* i is index into original string and j in the result string. */
        for(;i<strlen(str)-LESS;i++)
        {
                s[j++] = *(str+i);
        }
        s[j] = '\0'; /* Terminate the result string.*/
        printf("%s\n",s); /* Output: Hello W */

        return 0;
}
codaddict
A: 

You can do what you're asking to do with the following changes to your code:

int main (int argc, char *argv[])
{
    char *str = "Hello World";
    char *s = malloc(strlen(str));
    int i = 0;
    for(;i<strlen(str)-5;i++)
    {
        s[i] = *(str+i);
    }
    s[i] = 0;

    printf(s);

   return 0;
}
jfawcett
`s` is not NUL terminated. Do a `s[i] = 0;` right after the loop.
pmg
also `malloc(strlen(str));` is misleading - it's only correct because the loop only iterates to `strlen(str) - 5`
Gregory Pakosz
A: 

Use strncpy():

char *str = "Hello World";         
size_t len = strlen(str) - 5;   
char *s = malloc(len + 1); // +1 for nul terminator
if (s)            
{
  strncpy(s, str, len); // copies strlen(str)-5 characters from str to s
  s[len] = 0; // add nul terminator
}

A somewhat more general function:

/**
 * Return a substring of _len_ characters starting at position _start_
 * substring("Hello, World", 2, 3) == "llo"
 */
char *substring(char *str, size_t start, size_t len)
{
  char *s = malloc(len + 1);
  if (s)
  {
    strncpy(s, str+start, len);
    s[len] = 0;
  }
  return s;
}

Add sanity checks as needed (e.g., start < strlen(str), len <= strlen(str) - start, etc.).

John Bode
A: 

'+' is not a stribg concatenation operator in C

appusajeev