I'm having a slight problem with the following code, where I attempt
to copy a string up to a certain token, and then print out that
string. I would like to do this without using any of the string
library functions such as strtok(). Please excuse any c.l.c deemed
off-topic code below; my main problem most certainly lies within the
use of the pointers below.
The basic premise of the program is to read a config file in and do
some things with the values, the format of the file is as:
#conf file
rootdir=/test
option1=foo
option2=bar
the code thus far:
---------8<-----------
#define MAXBUF 512
...
int parsecfg()
{
FILE *f;
char *d="cfg";
char *p;
char *q;
if((p=malloc(MAXBUF)) == NULL)
perror("malloc");
if((q=malloc(MAXBUF)) == NULL)
perror("malloc");
if((f=fopen(d,"r+")) < 0)
{
perror("fopen");
exit(1);
};
while(fgets(p,MAXBUF,f) != NULL)
{
while(*p != '\0')
{
if((*q++ = *p++) == '=')
printf("Found option: %s\n",q);
*q='\0';
}
}
return 0;
}
---------->8------------
The output is as follows:
$ ./a.out
Found option:
Found option:
Found option:
$
The "if((*q++ = *p++) == '=')" comparison correctly detects the number
of lines containing '=', but alas q does not seem to be populated with
any of the string.
Any tips on where i'm going wrong will be great, pretty stumped.
thanks
KB.
--
comp.lang.c.moderated - moderation address: cl...@plethora.net -- you must
have an appropriate newsgroups line in your header for your mail to be seen,
or the newsgroup name in square brackets in the subject line. Sorry.
I never liked strtok myself either. strchr and memcpy on the other hand
I do like.
> Any tips on where i'm going wrong will be great, pretty stumped.
You're modifying the value of p and q and as a result can
no longer see what is in the pervious characters.
gratuitous and unfreed malloc is potentially problematic too.
#include <stdio.h>
#include <stdlib.h>
#define MAXBUF 512
int parsecfg()
{
FILE *f;
const char *d="cfg";
char p[MAXBUF];
char q[MAXBUF];
char *s,*t;
if((f=fopen(d,"r+")) < 0)
{
perror("fopen d");
exit(1);
};
while(fgets(p,MAXBUF,f) != NULL)
{
s=p;
t=q;
while(*s != '\0')
{
if((*t++ = *s++) == '=')
{
t[-1]='\0';
printf("Found option: %s\n value: %s\n",q,s);
break;
}
}
}
return 0;
}
main(){ return parsecfg();}
--
⚂⚃ 100% natural
> while(*p != '\0')
> {
> if((*q++ = *p++) == '=')
> printf("Found option: %s\n",q);
> *q='\0';
> }
q is incremented with every iteration, thus when printed it is
pointing to uninitialized memory. You could use a third pointer,
r, set equal to q prior to the loops, and print that.
rootdir=
^ ^
r q
In addition, you need to null-terminate the string _before_ passing
it to printf(). Otherwise, behavior is undefined.
-drl
> while(*p != '\0')
> {
> if((*q++ = *p++) == '=')
> printf("Found option: %s\n",q);
> *q='\0';
> }
>
you advanced q to point to region where data has not been read in yet.
I would try mallocing q as:
original_q = q = malloc(...)
then print original_q instead of q
Two things here:
1. It should be "char const*", you are not allowed to modify string
literals.
2. This one is IMHO a variable where a real name would be in place.
char const* filename = "cfg";
> if((p=malloc(MAXBUF)) == NULL)
> perror("malloc");
>
> if((q=malloc(MAXBUF)) == NULL)
> perror("malloc");
I admire that you check for malloc errors. I don't get why you still
continue then though. What many people do is to define a utility function:
void* xmalloc(size_t size) {
void* res = malloc(size);
if(res == NULL) {
perror("malloc");
exit(EXIT_FAILURE);
}
return res;
}
This is for programs where OOM couldn't be handled except by aborting
anyway, this is not suitable for e.g. library code!
> if((f=fopen(d,"r+")) < 0)
> {
> perror("fopen");
> exit(1);
> };
1. fopen() returns a pointer, NULL in case of failure. You were thinking of
open() with returns an int and a negative value on failure. You could write
an xfopen() similar to xmalloc() above.
2. exit(1) is formally nonportable, using EXIT_FAILURE is. That's not your
problem though. ;)
3. The final ';' after the closing curlies is unnecessary.
> while(*p != '\0')
> {
> if((*q++ = *p++) == '=')
> printf("Found option: %s\n",q);
> *q='\0';
> }
Two mistakes here:
1. When outputting with printf(), q is not zero-terminated and could contain
random garbage.
2. The output you want is actually preceding q, you are sliding the pointer
along the string!
size_t i;
for(i=0; p[i]!='\0'; ++i) {
q[i] = p[i];
if(p[i] == '=') {
q[i] = '\0';
printf("Found option: %s", q);
break;
}
}
Good luck!
Uli
The problem is in the stmt:
while(*p != '\0')
{
if((*q++ = *p++) == '=')
printf("Found option: %s\n",q);
*q='\0';
}
You are incrementing 'q' pointer without maintaining the reference to
the start of the option string.
Try this.
char *ref = q
while(*p != '\0')
{
if((*q++ = *p++) == '=')
{
q = '\0'; //This helps in printing the option string.
printf("Found option: %s\n",ref);
}
if (*(q - 1) == '\n')
{
ref = q;
}
}
*q='\0';
Regards,
Manohar
> comp.lang.c.moderated - moderation address: c...@plethora.net -- you must
In the excerpt above, assuming p points to the null-terminated string
"foo=bar":
- where does q point before the while loop?
- where does p point when printf() is called?
- where does q point when printf() is called?
DES
--
Dag-Erling Smørgrav - d...@des.no
you allocate for p but then you increment it, so you've lost the
original address that was stored in p. i think you need a second
pointer, perhaps named "pMover" that will first be equal to p but then
incremented as you proceed in the array.
regards,
Hubert
> The "if((*q++ = *p++) == '=')" comparison correctly detects the number
> of lines containing '=', but alas q does not seem to be populated with
> any of the string.
Of course it isn't. At the point you do the printout, you haven't
copied any of the contents of p after the '=' over into q. Actually,
your code causes undefined behaviour by printf()ing whatever random
garbage might sit in the part of 'q' you haven't written anything to yet.
In a nutshell: at that point you would have to printf() p, not q.
After "*q++ =" q will point *past* the equals sign to memory you
haven't written yet so the %s in your printf will fail - probably the
byte contains '\0'.
BTW, you should keep track of the start addresses of your malloced
memory so you can free them later.
James
1) Why bother with the mallocs at all just use the stack for 512
bytes.
2) You probably don't need the second buffer see the code below.
int parsecfg()
{
FILE *f;
char *d="cfg";
char *p, buf[MAXBUF];
if((f = fopen(d,"r+")) < 0)
{
perror("fopen");
exit(1);
};
while(fgets(p = buf, MAXBUF, f) != NULL)
{
while(*p++ != '\0')
{
if(*p == '=')
printf("Found option: %s\n",p);
}
}
return 0;
>On Dec 16, 6:46 pm, Krumble Bunk <krumbleb...@gmail.com> wrote:
>> Hi,
>>
>> I'm having a slight problem with the following code, where I attempt
>> to copy a string up to a certain token, and then print out that
>
>1) Why bother with the mallocs at all just use the stack for 512
>bytes.
>2) You probably don't need the second buffer see the code below.
>
>int parsecfg()
>{
> FILE *f;
> char *d="cfg";
> char *p, buf[MAXBUF];
>
> if((f = fopen(d,"r+")) < 0)
If fopen fails, it will return NULL. NULL is guaranteed to compare
equal to 0 in a pointer context. If it compares equal, then it cannot
compare less than. Your if expression will not do what you want.
> {
> perror("fopen");
> exit(1);
> };
>
> while(fgets(p = buf, MAXBUF, f) != NULL)
> {
> while(*p++ != '\0')
For some reason I guess the first character cannot be the '=' of
interest.
> {
> if(*p == '=')
> printf("Found option: %s\n",p);
Did you intend to print the '=' as well the text that follows it?
> }
> }
>return 0;
>
>}
--
Remove del for email
True.
> NULL is guaranteed to compare
> equal to 0 in a pointer context.
True.
> If it compares equal, then it cannot
> compare less than.
Not necessarily. The behavior of applying "<" to two pointer values
that don't point into the same object is undefined. It's possible,
though unlikely, that NULL < NULL will yield a true value.
> Your if expression will not do what you want.
Almost certainly true.
[...]
--
Keith Thompson (The_Other_Keith) ks...@mib.org <http://www.ghoti.net/~kst>
Nokia
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
Hi Barry, You are right on both counts, I simply copied the original
post and changed it just enough to illustrate my point. Should have
spotted the daft fopen test as well.
Jeremy