0

For example if a pointer points to an array of chars that read "Hello how are you?" And you only want the pointer to point to Hello. I am passing in a char pointer and when I cout it, it reads the entire array. I try to cut down the size using a for loop that break when it hit a ' '. But I am not having luck figuring it out. Any ideas?

const char *infile(char * file )
{
    cout<<file<<endl;  //this prints out the entire array
    int j;
    for(j=0;j<500; j++)
    {
        if(file[j]==' ')
           break;
    }
    strncpy(file, file,  j);
    cout<<file<<endl;  //how to get this to print out only the first word
}
Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111
Aaron
  • 4,380
  • 19
  • 85
  • 141

11 Answers11

2

strncpy() does not append a null terminator if there isn't one in the first j bytes of your source string. And your case, there isn't.

I think what you want to do is manually change the first space to a \0:

for (j = 0; j < 500; j++) {
  if (file[j] == ' ') {
    file[j] = '\0';
    break;
  }
}
chrisaycock
  • 36,470
  • 14
  • 88
  • 125
  • Thanks, nice and easy solution – Aaron Apr 16 '12 at 19:50
  • 3
    Then watch it crash and burn when somebody tries: `infile("This is a string");` – Jerry Coffin Apr 16 '12 at 19:53
  • @JerryCoffin But your compiler would at least warn you about losing `const`ness wouldn't it? (I'm not advocating this solution, in fact, I'm tempted to downvote it) – Praetorian Apr 16 '12 at 19:56
  • @Prætorian The input parameter has to be `const`. (Other issue is that the OP's code actually doesn't return anything despite claiming to return a `const char*`.) – chrisaycock Apr 16 '12 at 19:59
  • @JerryCoffin You are correct. I'm not sure what the OP's use case is though. – chrisaycock Apr 16 '12 at 20:00
  • @chrisaycock: It might -- but initializing a pointer to (non-const) char with a string literal is *so* common that many (most?) compilers don't warn about it, at least by default (and I'm pretty sure some don't, regardless of settings). – Jerry Coffin Apr 16 '12 at 20:01
  • @JerryCoffin My g++ doesn't warn even with `-Wall`. – chrisaycock Apr 16 '12 at 20:03
  • @chrisaycock What about `-pedantic -Wall -Wextra`? – Praetorian Apr 16 '12 at 20:03
  • @chrisaycock I get the following `g++ -O0 -g3 -pedantic -Wall -c -std=c++0x -o test.o ..\test.cpp` `warning: deprecated conversion from string constant to 'char*' [-Wwrite-strings]`. According to the [gcc docs](http://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html) `-Wwrite-strings` is enabled by default for C++. (I'm using gcc4.6.2) – Praetorian Apr 16 '12 at 20:12
  • @Prætorian I am on version 4.1.2. – chrisaycock Apr 16 '12 at 20:13
2

First, avoid strtok (like the plague that it mostly is). It's unpleasant but sometimes justifiable in C. I've yet to see what I'd call justification for using it in C++ though.

Second, probably the easiest way to handle this (given that you're using C++) is to use a stringstream:

void infile(char const *file) 
{
    std::strinstream buffer(file);
    std::string word;
    buffer >> word;
    std::cout << word;
}

Another possibility would be to use some of the functions built into std::string:

void infile(char const *file) {
    std::string f(file);
    std::cout << std::string(f, 0, f.find(" "));
}

...which, now that I think about it, is probably a bit simpler than the stringstream version of things.

Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111
1

A char* pointer actually just points to a single char object. If that object happens to be the first (or any) element of a string, you can use pointer arithmetic to access the other elements of that string -- which is how strings (C-style strings, not C++-style std::string objects) are generally accessed.

A (C-style) string is simply a sequence of characters terminated by a null character ('\0'). (Anything after the '\0' terminator isn't part of the string.) So a string "foo bar" consists of this sequence of characters:

{ 'f', 'o', 'o', ' ', 'b', 'a', 'r', '\0' }

If you want to change the string from "foo bar" to just "foo", one way to do it is simply to replace the space character with a null character:

{ 'f', 'o', 'o', '\0', ... }

The ... is not part of the syntax; it represents characters that are still there ('b', 'a', 'r', '\0'), but are no longer part of the string.

Since you're using C++, you'd probably be much better off using std::string; it's much more powerful and flexible, and frees you from having to worry about terminators, memory allocation, and other details. (Unless the point of this exercise is to learn how C-style strings work, of course.)

Note that this modifies the string pointed to by file, and that change will be visible to the caller. You can avoid that by making a local copy of the string (which requires allocating space for it, and later freeing that space). Again, std::string makes this kind of thing much easier.

Finally, this:

strncpy(file, file,  j);

is bad on several levels. Calling strncpy() with an overlapping source and destination like this has undefined behavior; literally anything can happen. And strncpy() doesn't necessarily provide a proper NUL terminator in the destination. In a sense, strncpy() isn't really a string function. You're probably better off pretending it doesn't exist.

See my rant on the topic.

Keith Thompson
  • 254,901
  • 44
  • 429
  • 631
0

This has nothing to do with the size of the pointer. A pointer always has the same size for a particular type.

Strtok might be the best solution (this code using strtok will break the string into substring every time is meets a space, an ",", a dot or a "-".

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, " ,.-");
  }

Source : CPP STRTOK

Erwald
  • 2,118
  • 2
  • 14
  • 20
0

Doing this would be much easier

 if(file[j]==' ') {
   file[j] = 0;
   break;
   ..

  // strncpy(file, file,  j);
stefan bachert
  • 9,413
  • 4
  • 33
  • 40
  • Easy, but dangerous -- will typically fail if, for example, the user passes a string literal to the function. – Jerry Coffin Apr 16 '12 at 19:55
  • Right, but in this case the original `strncpy(file, file, j)` fails, too. And a good compiler would warn. In such case it would be better just to pass a `const char*` – stefan bachert Apr 16 '12 at 19:59
0

Using strtok might make your life much easier.
Split up the string with ' ' as a delimiter, then print the first element you get from strtok.

Eran Zimmerman Gonen
  • 4,375
  • 1
  • 19
  • 31
0

Use 'strtok', see e.g. http://www.cplusplus.com/reference/clibrary/cstring/strtok/

Thomas W.
  • 2,134
  • 2
  • 24
  • 46
0

If what you're asking is "can I dynamically resize the memory block pointed to by this pointer" then... not really, no. (You have to create a new block of the desired size, then copy the bytes over, delete the first block, etc.)

If you're trying to just "print the first word" then set the character at the position of the space to 0. Then, when you output the file* pointer you'll just get the first word (everything up to the \0.) (Read null terminated strings for more information on why that works that way.)

But this all depends on how much of what you're doing is an example to demonstrate the problem you're trying to solve. If you're really 'splitting up strings' then you'll at least want to look in to using strtok.

Michael Wilson
  • 442
  • 1
  • 4
  • 11
0

Why not just output each character at a time and then break once you hit a space.

const char *infile(char * file )
{
  cout<<file<<endl;  //this prints out the entire array
  int j;

  for(j=0;j<500; j++)
  {
    if(file[j]==' ')
       break;
    cout<<file[j];
  }

  cout<<endl;
}
Ockham
  • 455
  • 1
  • 6
  • 16
0

If you allocated the space that a char * points to using malloc, you can change the size using realloc.

char * pzFile = malloc(sizeof("Hello how are you?" + 1));
strcpy(pzFile, "Hello how are you?");
realloc(pzFile, 6);
pzFile[6] = '\0';

Note that if you do not set the null pointer, using the string can cause a problem.

If you were just trying to shorten the string, all you had to do is set the null terminator at position 6. The space allocated is larger than needed, but that's OK as long as it's not shorter.

I strongly advise that mostly what you want to do is COPY the string up to the space.

char * pzInput = malloc(sizeof("Hello how are you?" + 1));
strcpy(pzInput, "Hello how are you?");
char * pzBuffer = malloc(BUFFER_SIZE);

char * pzSrc = pzInput;
char * pzDst = pzBuffer;
while (*pzSrc && ' ' != *pzSrc)
  *(pzDst++) = *(pzSrc++);
*pzDst = '\0';

This also ends up with pzSrc pointing at the rest of the string for later use!

Marlin Pierce
  • 9,931
  • 4
  • 30
  • 52
0
std::copy(file, std::find(file, file+500, ' '),
          std::ostream_iterator<char>(std::cout, ""));
Peter Wood
  • 23,859
  • 5
  • 60
  • 99