Newbie help on string splitting

S

Smurff

Hi all,

I have a string with upto 20 ip addresses in seperated by ;

111.111.111.111;222.222.222.222;333.333.333.333

I am trying to get them into an array so I can compare to. This isnt
homework :) Im just trying to learn C and have given myself a small
project.

Any help would be appreciated.

Logically, I have started by trying to find a way of getting the
position of the first ;

char *ipOneline = 111.111.111.111;222.222.222.222;333.333.333.333
/* Routine got from google groups */
int StrPos(const char *s, char c)
{
char *p;
p = strchr(s, c);
return (p) ? (p - s) : -1;
}


pos=StrPos(ipOneLine,';');

which returns 15, so what call can I use to say get a substring from 0
to 15 please?

Please be kind, I am still learning :)

Thanks
Smurff
 
A

Andrew Poelstra

Hi all,

I have a string with upto 20 ip addresses in seperated by ;

111.111.111.111;222.222.222.222;333.333.333.333
Basically, . separates octets, and ; separates addresses.
I am trying to get them into an array so I can compare to. This isnt
homework :) Im just trying to learn C and have given myself a small
project.
Good for you. Good luck!
Any help would be appreciated.

Logically, I have started by trying to find a way of getting the
position of the first ;
Actually, a logical first step would be to find out how to store the
addresses. You can use an unsigned int to store the first and second
halves of each address. Or, you can assume long int is 32 bits and
store the whole address in a variable. (There's a way using special C99
types like int_32fast or something, but I don't remember exactly what
they are called).
char *ipOneline = 111.111.111.111;222.222.222.222;333.333.333.333
/* Routine got from google groups */
int StrPos(const char *s, char c)
{
char *p;
p = strchr(s, c);
return (p) ? (p - s) : -1;
}


pos=StrPos(ipOneLine,';');

As you posted elsethread, strtok will help you out here.
which returns 15, so what call can I use to say get a substring from 0
to 15 please?
....

Please be kind, I am still learning :)
Well, you not only used proper grammar and spelling, you posted your problem
clearly, indicated how urgently you needed the information, and asked for help
kindly. I'd say that you'll get far more helpful answers than one fellow who
insulted Keith Thompson for suggesting he bottom-post. ;-)

A few notes, in case you didn't know: Quote context, and add your reply below
the quotes. Clip signatures and unnecessary quotations.


To your problem, to store an individual IP, load it into an array of four chars
and shift them into a long (long isn't guarunteed to be 32 bits, so wait for a
more portable reply if you wish):

char cip [4] = {127, 0, 0, 1};
long lip;
int ctr;

for (ctr = 0; ctr < 4; ctr++)
{
lip = cip[ctr];
lip <<= 8;
}

How to get the address into an array is up to you; you appear to have found a
solution using strtok(), and I'd hate to interrupt that learning progress with
an answer key.
 
C

CBFalconer

Smurff said:
I have a string with upto 20 ip addresses in seperated by ;

111.111.111.111;222.222.222.222;333.333.333.333

I am trying to get them into an array so I can compare to. This
isnt homework :) Im just trying to learn C and have given myself
a small project.

Any help would be appreciated.

The following routine will do the extraction for you. Try it first
with TESTING defined on compilation, and then without for your own
use. With gcc you define it on the command line by: "gcc -DTESTING
toksplit.c"

/* ------- file toksplit.c ----------*/
#include "toksplit.h"

/* copy over the next token from an input string, after
skipping leading blanks (or other whitespace?). The
token is terminated by the first appearance of tokchar,
or by the end of the source string.

The caller must supply sufficient space in token to
receive any token, Otherwise tokens will be truncated.

Returns: a pointer past the terminating tokchar.

This will happily return an infinity of empty tokens if
called with src pointing to the end of a string. Tokens
will never include a copy of tokchar.

A better name would be "strtkn", except that is reserved
for the system namespace. Change to that at your risk.

released to Public Domain, by C.B. Falconer.
Published 2006-02-20. Attribution appreciated.
*/

const char *toksplit(const char *src, /* Source of tokens */
char tokchar, /* token delimiting char */
char *token, /* receiver of parsed token */
size_t lgh) /* length token can receive */
/* not including final '\0' */
{
if (src) {
while (' ' == *src) *src++;

while (*src && (tokchar != *src)) {
if (lgh) {
*token++ = *src;
--lgh;
}
src++;
}
if (*src && (tokchar == *src)) src++;
}
*token = '\0';
return src;
} /* toksplit */

#ifdef TESTING
#include <stdio.h>

#define ABRsize 6 /* length of acceptable token abbreviations */

int main(void)
{
char teststring[] = "This is a test, ,, abbrev, more";

const char *t, *s = teststring;
int i;
char token[ABRsize + 1];

puts(teststring);
t = s;
for (i = 0; i < 4; i++) {
t = toksplit(t, ',', token, ABRsize);
putchar(i + '1'); putchar(':');
puts(token);
}

puts("\nHow to detect 'no more tokens'");
t = s; i = 0;
while (*t) {
t = toksplit(t, ',', token, 3);
putchar(i + '1'); putchar(':');
puts(token);
i++;
}

puts("\nUsing blanks as token delimiters");
t = s; i = 0;
while (*t) {
t = toksplit(t, ' ', token, ABRsize);
putchar(i + '1'); putchar(':');
puts(token);
i++;
}
return 0;
} /* main */

#endif
/* ------- end file toksplit.c ----------*/

/* ------- file toksplit.h ----------*/
#ifndef H_toksplit_h
# define H_toksplit_h

# ifdef __cplusplus
extern "C" {
# endif

#include <stddef.h>

/* copy over the next token from an input string, after
skipping leading blanks (or other whitespace?). The
token is terminated by the first appearance of tokchar,
or by the end of the source string.

The caller must supply sufficient space in token to
receive any token, Otherwise tokens will be truncated.

Returns: a pointer past the terminating tokchar.

+ This will happily return an infinity of empty tokens if
called with src pointing to the end of a string. Tokens
will never include a copy of tokchar.

released to Public Domain, by C.B. Falconer.
Published 2006-02-20. Attribution appreciated.
*/

const char *toksplit(const char *src, /* Source of tokens */
char tokchar, /* token delimiting char */
char *token, /* receiver of parsed token */
size_t lgh); /* length token can receive */
/* not including final '\0' */

# ifdef __cplusplus
}
# endif
#endif
/* ------- end file toksplit.h ----------*/

--
Some useful references about C:
<http://www.ungerhu.com/jxh/clc.welcome.txt>
<http://www.eskimo.com/~scs/C-faq/top.html>
<http://benpfaff.org/writings/clc/off-topic.html>
<http://anubis.dkuug.dk/jtc1/sc22/wg14/www/docs/n869/> (C99)
<http://www.dinkumware.com/refxc.html> (C-library}
<http://gcc.gnu.org/onlinedocs/> (GNU docs)
<http://clc-wiki.net> (C-info)
 
C

CBFalconer

*** top-posting corrected ***
Smurff said:
.... snip ...

Ok, after a few hours Im nearly there

strtok

Don't top-post. Your answer belongs after, or intermixed with, the
material to which you reply, after snipping irrelevant material.

strtok has the disadvantage of modifying the source string, and
being non-reentrant. My toksplit does not have these
disadvantages.

--
Some useful references about C:
<http://www.ungerhu.com/jxh/clc.welcome.txt>
<http://www.eskimo.com/~scs/C-faq/top.html>
<http://benpfaff.org/writings/clc/off-topic.html>
<http://anubis.dkuug.dk/jtc1/sc22/wg14/www/docs/n869/> (C99)
<http://www.dinkumware.com/refxc.html> (C-library}
<http://gcc.gnu.org/onlinedocs/> (GNU docs)
<http://clc-wiki.net> (C-info)
 
N

Nelu

Smurff said:
Thank you for the kind words. Didnt know about "top posting".
Now that you know about top-posting you should also know that
you should quote some relevant context when you post a
followup so whoever reads the post knows what you are talking about.
Not everybody can (or want to) lookup the previous message in thread.

From the original message:
I have a string with upto 20 ip addresses in seperated by ;

111.111.111.111;222.222.222.222;333.333.333.333
Each component of an address fits in one octet. If the size of one
byte is at least 8 bits (1 octet) then it fits. That means you can use
a 32 bit unsigned integer to store one address. The only problem is that
you have to find that type in a portable manner unless your
compiler is C99 compliant, in which case you can always get the
types from <stdint.h>.
You could take each unsigned integer type and check the size of its
representation and create your own type that you can use throughout the
program to hold an address.
 
B

Barry Schwarz

Hi all,

I have a string with upto 20 ip addresses in seperated by ;

111.111.111.111;222.222.222.222;333.333.333.333

I am trying to get them into an array so I can compare to. This isnt
homework :) Im just trying to learn C and have given myself a small
project.

Any help would be appreciated.

Logically, I have started by trying to find a way of getting the
position of the first ;

char *ipOneline = 111.111.111.111;222.222.222.222;333.333.333.333

I assume the missing quotation marks and semicolon are just a typos.
/* Routine got from google groups */
int StrPos(const char *s, char c)
{
char *p;
p = strchr(s, c);
return (p) ? (p - s) : -1;
}


pos=StrPos(ipOneLine,';');

which returns 15, so what call can I use to say get a substring from 0
to 15 please?

Create a working char* (e.g., ptr).
Initialize it to point to the same place ipOneline points to.
Change your function call to
pos = StrPos(ptr, ';');
At some point between successive calls to the function, increment ptr
to point one beyond the semicolon just found, e.g.,
ptr += pos+1;


Remove del for email
 
F

Frederick Gotham

Smurff posted:
Hi all,

I have a string with upto 20 ip addresses in seperated by ;

111.111.111.111;222.222.222.222;333.333.333.333

I am trying to get them into an array so I can compare to.


I'd change the semi-colons to null characters, then make an array of
pointers to char's. Something like:

(Apologies for anything which isn't valid C... I come from a C++
background)


typedef struct TwentyIPs {

char *array[20];

} TwentyIPs;


TwentyIPs MakeArray( char *p )
{
TwentyIPs tips = { p };

char **current_str = tips.array + 1;

for ( ; *p; ++p )
{
if ( *p == ';' )
{
*p++ = 0;

*current_str++ = p;
}
}

return tips;
}

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

int main(void)
{
char buffer[] = "111.111.111.111;222.222.222.222;333.333.333.333";

TwentyIPs tips = MakeArray( buffer );


char **current_str = tips.array;


printf( "Original String: %s \n \n", buffer );


for( ; *current_str; ++current_str )
{
printf( "%s \n", *current_str );
}


system("PAUSE");
}
 
D

Dave Thompson

On Tue, 13 Jun 2006 03:06:32 GMT, Andrew Poelstra

As you posted elsethread, strtok will help you out here.
Not if the argument points to a string literal (value) as here. If
it's read or moved into a writable buffer, strtok() is one choice.

To your problem, to store an individual IP, load it into an array of four chars
and shift them into a long (long isn't guarunteed to be 32 bits, so wait for a
more portable reply if you wish):

char cip [4] = {127, 0, 0, 1};
long lip;
int ctr;

for (ctr = 0; ctr < 4; ctr++)
{
lip = cip[ctr];
lip <<= 8;
}
long is guaranteed to be at least 32 bits, and long long at least 64.
But that includes the sign bit, and left shift into the sign bit isn't
standardly (portably) required to work, although most machines
nowadays are two's-complement where 'arithmetic' (signed) and
unsigned left shifts are actually the same. Even worse, plain char can
be and sometimes is signed, which will give you grossly wrong results.

It is 'int' that standardly guarantees only 16 bits, although many
platforms, probably most today, provide 32.

And if lip is an auto variable, i.e. within a function (block), you
need to initialize or assign it to 0 before starting the loop.

- David.Thompson1 at worldnet.att.net
 
W

websnarf

Smurff said:
I have a string with upto 20 ip addresses in seperated by ;

111.111.111.111;222.222.222.222;333.333.333.333

I am trying to get them into an array so I can compare to. This isnt
homework :) Im just trying to learn C and have given myself a small
project.

Any help would be appreciated.

Logically, I have started by trying to find a way of getting the
position of the first ;

char *ipOneline = 111.111.111.111;222.222.222.222;333.333.333.333
/* Routine got from google groups */
int StrPos(const char *s, char c)
{
char *p;
p = strchr(s, c);
return (p) ? (p - s) : -1;
}

pos=StrPos(ipOneLine,';');

which returns 15, so what call can I use to say get a substring from 0
to 15 please?

Please be kind, I am still learning :)

Well, when you finally figure it out, you are unlikely to be impressed.
If all you want to do is split a string into an array of strings split
by some token, you can do so with "The Better String Library" (
http://bstring.sf.net/ ) in fairly short code:

#include <stdio.h>
#include "bstrlib.h"

int ipEqStrIp (const bstring a0, const bstring a1) {
bstrlist l0 = bsplit (a0, '.'), l1 = bsplit (a1, '.');
int o0, o1, i, ret = 0;
if (l0 && l1 && l0->qty == l1->qty) {
for (ret = 1, i=0; i < i0->qty; i++) {
if (1 != sscanf(bdatae(a0->entry,"?"), "%d", &o0) ||
1 != sscanf(bdatae(a1->entry,"?"), "%d", &o1) ||
((o0 - o1) % 256) != 0) {
ret = 0;
break;
}
}
}
bstrListDestroy (l0);
bstrListDestroy (l1);
return ret;
}

int main () {
char *resp[2] = {"No", "Yes"};
struct tagbstring ipOneLine = bsStatic \
("111.111.111.111;222.222.222.222;333.333.333.333");
bstrList sl = bsplit (&ipOneLine, ';');
if (sl) {
printf ("%s == %s? %s\n", bdata (sl->entry[0]),
bdata (sl->entry[1]),
resp[ipEqStrIp (sl->entry[0], sl->entry[1])]);
bstrListDestroy (sl);
}
return 0;
}

Notice how short this code is; its fairly easy to understand and
basically *starts* with more useful starting primitives (like a split
function.)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,537
Members
45,022
Latest member
MaybelleMa

Latest Threads

Top