Valhalla Legends Forums Archive | C/C++ Programming | c++ string manipulation

AuthorMessageTime
ArticMoogle
Im currently working on an input that allows a user to enter multiple variables at a time, in sets of two.

An example would be: 1d 2a 3e 4a 5d 6t

What needs to happen then is the values must be assorted according to their corresponding character type, say d represented dogs.

So how would i take all that input and break it down, and would i use a switch to distribute the data according to its corresponding type?

Please let me know what you think, or if you need a better explanation.
October 8, 2003, 10:02 PM
Adron
[code]
char buf[] = "1d 2a 3e 4a 5d 6t";
char *p = buf;
while(*p && p[1]) {
switch(p[1]) {
case 'd': printf("%d dogs\n", *p-'0');
break;
// insert more cases...
}
p += 2;
while(*p == ' ') p++;
}
[/code]

That's all using C string manipulation, and assuming that the values follow the pattern <digit><char><space(s)>.

October 8, 2003, 10:15 PM
ArticMoogle
Thanks for your help Adron.
October 8, 2003, 10:39 PM
ArticMoogle
I just want to definitely make sure I understand what you've given me, so let me break it down...

[code] char buf[] = "1d 2a 3e 4a 5d 6t"; [/code]

The above stament declares buf as an array and sets its value to "1d 2a 3e 4a 5d 6t"

[code]char *p = buf;[/code]

I think this means that *p points to the address of buf???

[code]while(*p && p[1]) {[/code]
This initiates the loop, and the middle stuff im not too sure about.

[code] switch(p[1]) {
case 'd': printf("%d dogs\n", *p-'0');
case 'D':
       break;[/code]

These statements start the switch while in the loop, and printf is some kind of formatting i guess, and again im unsure about the things in parenthesis.

I'm sure this gives you a pretty good view of my knowledge in c++, I'd appreciate whatever you decide to elaborate on, some of it, none of it. Thanks! :)
October 8, 2003, 11:34 PM
iago
buf is a pointer to a list of characters (ie, your string). *p dereferences the address of buf, which would return the character.

One note about adron's code: if one of the numbers is >10, it won't work right.
October 8, 2003, 11:42 PM
Adron
Which is why I noted that it worked if the format was <digit><char>, as opposed to <number><char> :P

*p and p[1] verifies that there are at least two more non \0 characters in the string.

printf, well, that's too complex a function - you should just look up how the formatting strings work in the online help.
October 8, 2003, 11:59 PM
ArticMoogle
Ok, i've think got the way of it now...Thanks much!

But now i have another question ;D

Inside the switch im sending the data to a struct, say pet. So one of the cases would be...

case d: pet.dogs=p[1]

also. if i used double buf[] it would work with >10 as well?

Sorry if im exasperating you all :)
October 9, 2003, 12:25 AM
iago
No, because the *p line (which, in my opinion, shoudl be if p[0] && p[1] for the sake of consistancy) returns a single character. To do any more would take a little more effort to parse; in fact, I'm not sure if there's any good way unless you force them to put a space between the number and letter, such as "1 d 2 c ..."etc. or on seperate lines, like this:
-----
1 d
2 c
4 b
-----

In that case, you could do this (assuming that the string is coming from a file):
[code]int num;
char code;
FILE *File = fopen("pets.dat", "r");
// error checking goes here if File is NULL fail
while(fscanf(File, "%d %c", &num, &code) == 2)
{
switch code:
case 'd':
mything.dogs += num;
break;
// case ....
}
[/code]
October 9, 2003, 2:57 AM
iago
Another (in my opinion, better) way to do it, instead of using a struct, would be like this:

[code]enum AnimalTypes { Dog, Cat, Beaver, Hippo, Giraffe, Oprah, NUM_ANIMALS };

int MyAnimals[NUM_ANIMALS];

bool CountAnimals(char *Filename)
{
int Num;
char Type;
FILE *File = fopen(Filename, "r");
if(File == NULL)
return false;

while(fscanf(File, "%d %c", &Num, &Type) == 2)
{
switch(Type)
{
case 'd':
MyAnimals[Dog] += Num;
break;
case 'c':
MyAnimals[Cat] += Num;
break;
//...etc.
}
}
return true;
}[/code]

Note that this is untested, but I'm reasonably sure it should work (logically anyway, I may have made a typo).
October 9, 2003, 3:02 AM
Kp
You could instead use strtoul to convert the number into internal representation; doing so permits you to have one or multiple digits, and to express it in any base between 2 and 36 inclusive. Further, doing so gets rid of the need for a space to separate the count and the type specifier.
October 9, 2003, 4:51 AM
iago
[quote author=Kp link=board=5;threadid=3003;start=0#msg23533 date=1065675117]
You could instead use strtoul to convert the number into internal representation; doing so permits you to have one or multiple digits, and to express it in any base between 2 and 36 inclusive. Further, doing so gets rid of the need for a space to separate the count and the type specifier.
[/quote]

aah, you're right.. atoi (or itoa.. I forget) would also work, and is a little easier to use.
October 9, 2003, 4:59 AM
Kp
[quote author=iago link=board=5;threadid=3003;start=0#msg23535 date=1065675554]aah, you're right.. atoi (or itoa.. I forget) would also work, and is a little easier to use.[/quote]itoa makes internal representations printable; atoi converts strings to internal representation. However, it is inferior in that a) it does not allow you to specify base and b) it does not provide a mechanism of locating the first non-parsed character in the string. strtoul suffers neither of these problems.
October 9, 2003, 5:13 AM
iago
atoi() is obviously the one I was looking for.

In this case, 1) he'll always be using base 10, and 2) the pointer will always be at the beginning of the string anyway, and 3) he's a newb to programming, and int itoa(char *num) is a lot easier to use :)
October 9, 2003, 5:44 AM
ArticMoogle
Thanks for all the different solutions guys, I was just trying to make sure I understood what was going on instead of copying code you gave me.

Thanks again!
October 9, 2003, 1:31 PM
iago
[quote author=ArticMoogle link=board=5;threadid=3003;start=0#msg23545 date=1065706282]
Thanks for all the different solutions guys, I was just trying to make sure I understood what was going on instead of copying code you gave me.

Thanks again!
[/quote]

That's the impression I got, which is why I posted a couple different solutions. You seemed like you were trying to learn, so I had no problem with writing a little code for you :-)

You're welcome!!
October 9, 2003, 4:39 PM
Kp
[quote author=iago link=board=5;threadid=3003;start=0#msg23538 date=1065678240]atoi() is obviously the one I was looking for.

In this case, 1) he'll always be using base 10, and 2) the pointer will always be at the beginning of the string anyway, and 3) he's a newb to programming, and int itoa(char *num) is a lot easier to use :)[/quote]First you say that atoi was indeed the one you wanted, then you go and call it itoa again? Pay attention! :) Also, the pointer that strtoul provides on return (via the second argument; see documentation for details) will reliably point at the first non-digit for the current base. That enables him to support any 32-bit number, regardless of digits, and not expend additional effort on return locating the type specifier. Using atoi allows any length number, but then requires that he do extra work on return to locate the non-digit (or make the assumption that the number is always a certain quantity of digits long, which is IMO a bad limitation to go imposing if you don't need to do so).
October 10, 2003, 7:47 PM
iago
Fine then, he should use that one. Is that what you wanted me to say? :-P

And I always get itoa and atoi mixed up, never tried to keep them straight, but it's clear which one I mean :P
October 10, 2003, 9:21 PM
Adron
[code]
char buf[] = "123d 36c 25b";
int counts[256] = {0};
for(char *p = strtok(buf, " "); p; p = strtok(0, " ") {
int n;
unsigned char c;
if(sscanf(p, "%d%c", &n, &c) == 2)
counts[c] += n;
}
[/code]
October 11, 2003, 12:25 AM

Search