pointer to pointer problem, please advice 
Author Message
 pointer to pointer problem, please advice

I don't understand why my code is printing only the first
word in the last line of the file times
the number of lines, and not the first word of each line.

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

#define FILE "somefile"
#define MAXLINE 50

int main(void)
{
        FILE *file;
        char *temp, *tptr, **ptr, **firstwords;
        int linecount=0, namecount=0, namemax=0;

        if((file=fopen(FILE,"a+"))==NULL) {
                perror("fopen");
                exit(-1);
        }

        temp=malloc(MAXLINE); /* error check is missing */
        rewind(file);
        while(fgets(temp,MAXLINE-1,file)!=NULL) {
                while(*temp++!=0x20&&*temp!=0xa) namecount++;
                if(namecount>namemax) namemax=namecount;
                linecount++; namecount=0;
        }
        free(temp);                                    
        temp=malloc(MAXLINE);  
        rewind(file);
        firstwords=malloc(linecount*namemax); /* error check */
        ptr=firstwords;
        while(fgets(temp,100,file)!=NULL) {
                tptr=temp;
                while(*tptr!=0x20&&*tptr!=0xa) *tptr++;
                *tptr=0x0;
                *ptr++=temp;
        }
        while(*firstwords)
         printf("%s\n",*firstwords++);

        return 1;

Quote:
}

Also, does the double while(fgets ... ) is really necessary ? what is a
better/faster way to implement this ? (I only want to implement it using
pointers, not arrays, but I'd like to hear if array implementation is better)

Thanks
-r.



Mon, 10 Nov 2003 22:34:33 GMT  
 pointer to pointer problem, please advice

Quote:
> I don't understand why my code is printing only the first word
> in the last line of the file times the number of lines, and not
> the first word of each line.

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

> #define FILE "somefile"
> #define MAXLINE 50

> int main(void)
> {
>    FILE *file;
>    char *temp, *tptr, **ptr, **firstwords; int linecount=0,
>    namecount=0, namemax=0;

>    if((file=fopen(FILE,"a+"))==NULL) {
>            perror("fopen");
>            exit(-1);
>    }

>    temp=malloc(MAXLINE); /* error check is missing */
>    rewind(file);
>    while(fgets(temp,MAXLINE-1,file)!=NULL) {
>            while(*temp++!=0x20&&*temp!=0xa) namecount++;

That above line is relying on systems specific character
encoding. You don't have a guarantee that 0x20 is the character
you expect to have read. Use a literal character in singel
quotes instead. ' ' and '\n' in your case probably.

Also after a (temp++) expression your program will lose
any reference to the previously allocated memory. If you pass
temp to free() later on you may get a segmentation fault.
Use some index variable instead or another temporary pointer
to recall the start of the allocated buffer afterwards.

Quote:
>            if(namecount>namemax) namemax=namecount;
>               linecount++; namecount=0;
>    }
>    free(temp);

Why would you free the buffer, if you just one line later are
going to allocate the same amount of memory again?

Quote:
>    temp=malloc(MAXLINE);

Just remove the above two lines of code and take care to
leave a reference to the buffer until you free the allocated
memory.

Quote:
>    rewind(file);
>    firstwords=malloc(linecount*namemax); /* error check */

So you are allocating for an array of pointers to char (probably
an array of pointers to strings)? You are expecting how many
strings to be stored, (linecount*namemax)? From the later code
I'ld guess that you only need exactly linecount pointers to
strings or char arrays.

Quote:
>    ptr=firstwords;
>    while(fgets(temp,100,file)!=NULL) {

Hey, temp is a buffer of MAXLINE chars, and MAXLINE isn't 100.
You've used the fgets() function correctly above, why not here?

Quote:
>            tptr=temp;
>            while(*tptr!=0x20&&*tptr!=0xa) *tptr++;
>               *tptr=0x0;

the above two/three lines can be replaced with

if(tptr = strchr(temp, ' ')) tptr = 0;
else temp[strlen(temp) - 1] = 0;

Note that if a line is longer than MAXLINE you'll
have some problems with the whole loop.
I have not considered this case.

Quote:
>            *ptr++=temp;

This does not copy the string stored in temp to
where ptr points to, but sets a reference to the
buffer, which obviously isn't what you wanted.

You'll have to use a strcpy() function to here.

  *ptr = malloc(strlen(temp) + 1);
  strcpy(*ptr, temp);

Quote:
>    }
>    while(*firstwords)
>     printf("%s\n",*firstwords++);

Again, you've lost all references to the allocated memory so
you'll never be able to free that memory.

Quote:

>    return 1;

BTW, returning nonzero-values from main usually
indicates an error to the underlaying system.

Quote:
> }

> Also, does the double while(fgets ... ) is really necessary ?
> what is a better/faster way to implement this ?

No its not necessary. You don't need to first store all
"firstwords" in a large char array to write them to stdout
later on. You can easily read the first line, get the first
lines first word and print that on stdout, than read the next
line...

Here is how I'ld do it:

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

#define MAXLINE 80

int main(void)
{

  FILE *fp;
  char buf[MAXLINE], *tmp;

  if((fp = fopen("somefile", "r")) == NULL) {
    fputs("Can't open file somefile\n", stderr);
    return EXIT_FAILURE;
  }

  while(NULL != fgets(buf, sizeof buf, fp)) {
    if(buf[strlen(buf) - 1] != '\n') {
      fputs("line to long", stderr);
      return EXIT_FAILURE;  
                    /* you may want to insert some
                    extra code for recovery here */
    }

    buf[strlen(buf) - 1] = 0; /* to remove newlines in
                              lines that have only one word */

    if(NULL != (tmp = strchr(buf, ' '))) *tmp = 0;
    puts(buf);
  }

  return 0;

Quote:
}

--

"LISP  is worth learning for  the profound enlightenment  experience
you will have when you finally get it; that experience will make you
a better programmer for the rest of your days."   -- Eric S. Raymond


Tue, 11 Nov 2003 20:41:55 GMT  
 pointer to pointer problem, please advice
Once upon a while "Zoran Cutura"

...

Quote:
>> #define FILE "somefile"

As an extra point, it is probably the worst idea
to call the macro FILE since there is a datatype named
FILE in the standard library.

--

"LISP  is worth learning for  the profound enlightenment  experience
you will have when you finally get it; that experience will make you
a better programmer for the rest of your days."   -- Eric S. Raymond



Tue, 11 Nov 2003 20:44:29 GMT  
 pointer to pointer problem, please advice

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

> #define FILE "somefile"

          ^^^^
#define FILE1 "somefile"

Quote:
> #define MAXLINE 50

> int main(void)
> {
>    FILE *file;
>    char *temp, *tptr, **ptr, **firstwords;
>    int linecount=0, namecount=0, namemax=0;

Add two variables: char *temp1;    int i;

Quote:

>    if((file=fopen(FILE,"a+"))==NULL) {

                       ^^^^
if((file=fopen(FILE1,"a+"))==NULL) {

Quote:
>            perror("fopen");
>            exit(-1);
>    }

>    temp=malloc(MAXLINE); /* error check is missing */

change it to: temp1=malloc(MAXLINE);

Quote:
>    rewind(file);
>    while(fgets(temp,MAXLINE-1,file)!=NULL) {

change it to: while(temp=temp1, fgets(temp,MAXLINE-1,file)!=NULL) {

Quote:
>            while(*temp++!=0x20&&*temp!=0xa) namecount++;
>            if(namecount>namemax) namemax=namecount;
>            linecount++; namecount=0;
>    }
>    free(temp);    

change it to: free(temp1);

Quote:
>    temp=malloc(MAXLINE);

        ^^^^^^^^^^^^^^^^^^^^^
Delete this line!

Quote:
>    rewind(file);
>    firstwords=malloc(linecount*namemax); /* error check */

correct it to: firstwords=malloc(linecount * sizeof(*firstwords));

Quote:
>    ptr=firstwords;
>    while(fgets(temp,100,file)!=NULL) {

correct it to:
        while(temp=malloc(MAXLINE),fgets(temp,MAXLINE-1,file)!=NULL) {

Quote:
>            tptr=temp;
>            while(*tptr!=0x20&&*tptr!=0xa) *tptr++;
>            *tptr=0x0;
>            *ptr++=temp;
>    }
>    while(*firstwords) printf("%s\n",*firstwords++);

It doesn't work!
Change it to:
        for (i=0;i<linecount;i++) printf("%s\n",firstwords[i]);  

To free() the memory pointed by "firstwords" is your homework.
paiyi

Quote:

>    return 1;
> }



Tue, 11 Nov 2003 20:59:07 GMT  
 pointer to pointer problem, please advice

Quote:

>      if((file=fopen(FILE,"a+"))==NULL) {
>           perror("fopen");
>           exit(-1);
>      }

One note:

fopen isn't required to set errno to anything so you should
#include <errno.h> and set errno to zero before the function
you wish to check, and then call perror only if errno is
nonzero.

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

int main(void)
{
    FILE *fp;
    char *filename = "thisisatest.bogus";

    errno = 0;
    /* in this case probably not necessary because
       the implementation is required to set errno
       to zero at program startup, but good practice */
    fp = fopen(filename, "r");
    if(!fp)
    {
        fprintf(stderr, "error opening %s\n", filename);
        if(errno)
            perror(filename);
        return EXIT_FAILURE;
    }
    fclose(fp);

    return 0;

Quote:
}

--
386

Just the FAQ Jack:
http://www.eskimo.com/~scs/C-faq/top.html



Tue, 11 Nov 2003 22:44:09 GMT  
 pointer to pointer problem, please advice

Quote:

> I don't understand why my code is printing only the first
> word in the last line of the file times
> the number of lines, and not the first word of each line.

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

> #define FILE "somefile"
> #define MAXLINE 50

> int main(void)
> {
>    FILE *file;

How does this even /compile/?  Your macro above will expand this line
to:

"somefile" *file;

Which is a syntax error.

Quote:
>    char *temp, *tptr, **ptr, **firstwords;
>    int linecount=0, namecount=0, namemax=0;

>    if((file=fopen(FILE,"a+"))==NULL) {
>            perror("fopen");
>            exit(-1);
>    }

Why are you opening it in such a bizarre mode?  You are not writing to
the file, and yet you open it in /append/ mode, with read capability
patched in?  Why not open it with "r" instead, saving yourself one of
the rewind()s below?

Quote:

>    temp=malloc(MAXLINE); /* error check is missing */
>    rewind(file);
>    while(fgets(temp,MAXLINE-1,file)!=NULL) {

Why MAXLINE-1?  fgets() already reads one less than the size
specified, tacking a '\0' afterwards.

Quote:
>            while(*temp++!=0x20&&*temp!=0xa) namecount++;
>            if(namecount>namemax) namemax=namecount;
>            linecount++; namecount=0;
>    }

You're sure that there are no lines longer than 47 characters (not
counting newline and the null character)?  Because if there are any,
then one of the fgets will start reading from the middle of the line,
but your program will think it's a seperate line!

Quote:
>    free(temp);                                    
>    temp=malloc(MAXLINE);  
>    rewind(file);
>    firstwords=malloc(linecount*namemax); /* error check */
>    ptr=firstwords;
>    while(fgets(temp,100,file)!=NULL) {

Why did you use MAXLINE before, and now 100?  THIS IS A BUFFER
OVERRUN! BAD!

Quote:
>            tptr=temp;
>            while(*tptr!=0x20&&*tptr!=0xa) *tptr++;

Ick!  Don't do that - if you want characters, /use/ characters; ' '
and '\n' are much more readable (and portable) than 0x20 and 0xa.

But you're not allowing for other whitespace characters - the best
solution is to #include <ctype.h> and use isspace() instead.

Quote:
>            *tptr=0x0;

I see no purpose in this line ^^^

Quote:
>            *ptr++=temp;

And here is the likely cause of your problem.  You are assigning a
pointer to temp to *ptr; but on the next iteration of while, temp's
contents will be overwritten with a new line.  So you have linecount
pointers, each one pointing to the same buffer (temp) - since temp's address
doesn't change, but it's contents do, they all point to the same word,
which is the last word found in the while() loop.  So you need to make
a new copy of each word you find - into a new string, and put /that/
string's pointer into the array.  Make sure and free all of those,
though, too.

Quote:
>    }
>    while(*firstwords)
>     printf("%s\n",*firstwords++);

>    return 1;
> }

> Also, does the double while(fgets ... ) is really necessary ? what is a
> better/faster way to implement this ? (I only want to implement it using
> pointers, not arrays, but I'd like to hear if array implementation is better)

C90 arrays are generally useful only when you know the size ahead of
time - since you can't know the number of lines in the file ahead of
time, the pointers are a good idea.  But as has been pointed out, they
are being used somewhat incorrectly.

Also, the double while, as you suspected, is unnecessary - you end up
reading the entire file just to count lines, and then rereading it
again.  A better approach is probably to allocate space as you need
it.  For instance:

1) Allocate arbitrary space in firstwords, say, enough for 50
   pointers.

2) Read in up to 50 words, duplicating them each time they're found.

The duplicating code could be something like:

char *
clone_word (const char *string)
{
  size_t length;
  char *retval;

  length = get_word_length (string);
  retval = malloc (length + 1);
  if (retval != NULL)
    {
      strncpy (retval, string, length);
      retval[length] = '\0';
    }

  return retval;

Quote:
}

and the code for get_word_length():

size_t
get_word_length (const char *string)
{
  size_t retval = 0;

  while (string[retval] != '\0' && ! isspace (string[retval])
    retval++;

  return retval;

Quote:
}

Not forgetting to #include <ctype.h> and <string.h>, being sure to
check the return value of clone_word(), and freeing anything you get
from it.

3)  After you've read the 50 words, use realloc() to make space for 50
    more words - go back to 1).

Give it a try, and post your attempt!

Micah

--
By pride comes only contention, but with the well-advised
is wisdom.
                                        Proverbs 13:10



Wed, 12 Nov 2003 03:08:25 GMT  
 
 [ 6 post ] 

 Relevant Pages 

1. Dereferencing f-pointers, arrays of f-pointers, pointers to f-pointers

2. memory leak: pointer->pointer->pointer->struct

3. Pointer of Pointers was Pointer of arrays...

4. memory block containing pointers, aka pointer to pointer i believe

5. pointers pointers pointers!!!

6. memory Leak: pointer->pointer->pointer->struct

7. Pointer Functions and Pointers to Pointer Functions

8. Pointer to Pointer to Pointer....

9. Question on pointer-to-pointer-to-pointer

10. How to use (pointer to function), and function and pointer to (pointer to function)

11. double pointer (or pointer to pointer)

12. Pointers: return of pointer to array of pointers to main

 

 
Powered by phpBB® Forum Software