-4

I have a 100 char string with few '\n' characters in it , I want to extract the characters between the first '\n' and the second '\n' and store them in another char array , how can i do that?

please note that i cant use iostreams or vectors as I am using AVR GCC. i can only use strok() or strcpy()

Ahmad S
  • 21
  • 6

2 Answers2

0

If to use character arrays then you can use the following approach

#include <iostream>
#include <cstring>

int main()
{
    char s[100] = "begin\nmiddle\nend";
    char t[100];
    t[0] = '\0';

    if ( char *p = strchr( s, '\n' ) )
    {
        if ( char *q = strchr( ++p, '\n' ) )
        {
            std::strncpy( t, p, q - p );
            t[q - p] = '\0';
        }
        else
        {
            strcpy( t, p );
        }
    }

    std::cout << "\"" << t << "\"" << std::endl;
}    

The program output is

"middle"

If you want to get an array of strings separated by the new line character then you can use the following approach

#include <iostream>
#include <sstream>
#include <vector>
#include <string>
#include <iterator>

int main()
{
    char s[100] = "begin\nmiddle\nend";
    std::istringstream is( s );

    std::vector<std::string> v( ( std::istream_iterator<std::string>( is ) ),
                                std::istream_iterator<std::string>() );

    for ( const std::string &item : v ) std::cout << '\"' << item << '\"' << std::endl;
}    

The program output is

"begin"
"middle"
"end"

But it does not make great sense to use this approach if you need just to copy one substring from one character array to another.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
0

A basic Version is this one:

#include <iostream>
#include <string>
#include <sstream>
#include <vector>

using std::string;
using std::cout;

void base_ansi_c()
{
    const char * source = "one\ntwo\nthree\n";
    char target[1024];
    const char * c;
    for (c = source; c && *c != 0 && *c != '\n'; ++c); //skip until first '\n'
    if (c && *c == '\n') ++c; // skip '\n'
    int n = 0;
    for (; c && *c != 0 && *c != '\n' && n < 1024; ++c, ++n) //copy until second '\n'
    {
        target[n] = *c;
    }
    target[n] = 0;
    cout << "'"  << target << "'\n";
}

void base_cpp_sstream()
{
    std::vector<string> cpp_array;
    std::string test = "one\ntwo\nthree\n";
    std::istringstream is(test);

    std::string part;

    while (std::getline(is, part, '\n'))
    {
        cpp_array.emplace_back(part);
        std::cout << "  " << part << "  ";
    }
    std::cout << "\n";
    std::cout << "The second element is: '" << cpp_array.at(1) << "'\n";
}

int main()
{
    std::cout << "\nbase_cpp_sstream\n";
    base_cpp_sstream();
    std::cout << "\nbase_ansi_c\n";
    base_ansi_c();
}

If it gets more complex you may want to switch to either boost::tokenizer or boost::spirit::qi.

Since you asked for a different version where the positions are more relevant to the algorithm I added an ansi-c style iterating through the string.

Edit: Some detail about the code above as you requested in the comment. I think explaining this line for (c = source; c && *c != 0 && *c != '\n'; ++c); will be enough to get you started.

The statement c = source just copies the pointer at the beginning of the loop.

At every iteration including the first the following is checked: c && *c != 0 && *c != '\n' The detail here is that c will be dereferenced so it can not be (char*)0. 0 is false, every other value is true. If c is false the chained together values using && are not evaluated. So there is no risk of dereferencing a null pointer. *c != 0 checks if the end of the c-string is reached. In that case no \n was found. *c != '\n' checks if a new line character is reached.

At the end of an iteration the pointer is incremented. ++c this moves the c pointer to the next element of the array. Since c is a char the pointer is incremented by 1. sizeof(char) evaluates to 1. (always). If the array elements were of a different type the increment would also move the pointer to the next element. (does not work with void*).

If '\n' is found there is no increment afterwards. The for loop just ends. since c was declared outside of the loop the value remains preserved and can be used by the subsequent algorithms.

Johannes
  • 6,490
  • 10
  • 59
  • 108
  • basically i need the position of the first occurance of '\n' which i can get using strchr() but how do i get the second occurence of '\n\ ? – Ahmad S Jan 26 '16 at 19:40
  • oh now i see your asnwer , thanks a lot, how does it work can you please explain ? void base_ansi_c() – Ahmad S Jan 26 '16 at 21:01