LinuxQuestions.org
Help answer threads with 0 replies.
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 01-03-2005, 11:40 AM   #1
exvor
Senior Member
 
Registered: Jul 2004
Location: Phoenix, Arizona
Distribution: Gentoo, LFS, Debian,Ubuntu
Posts: 1,537

Rep: Reputation: 87
Problem with C program


This is a problem im doing for the ctutorial questions. It asked me to write a program that takes input from the user and removes all the spaces and replaces them with newlines. I did this to solve the problem but im getting one issue.

It displayes the error "Error Reading file for input" this is the error i told it to put if the open command return with a null.

problem is with the this part "temp = fopen ("temp.str","w");" in theory acording to my tutorial this should find the file if it exists remove its contents and open it for writeing.

problem is thats not what is occuring. its just apending the file not removing the current contents.

even if the file does not exist i still get the message. mentiond above when trying to read the file.

all and all the program works correctly ?

so do i just need to abandon my quest with high level file routines and go low level or am i doing something wrong ?

here is the code

Code:
/* program takes input from user and strips */ 
/* All of the spaces out and replaces them with newlines */ 


#include <stdio.h> 

char *typed; 
int errchk;
int SIZE = 100; 

void gettyped(char*);
void striprint(char*); 
 


int main()
{
    typed = (char *) malloc (SIZE); 
    
    gettyped(typed); 
    striprint(typed); 
     
    
    return 0; 
}

void gettyped(char *typed)
{
    /* This function gets values from the user */ 
    
    errchk = getline(&typed,&SIZE,stdin); 
        if (errchk == -1) 
	    {
		puts("Invalid input.");
	    }
}

void striprint(char *typed)
{
    FILE *temp;
    char *typedread;
    int err2chk;
    typedread = (char*) malloc(100);
    
   /* Opens a file for tempoary holding space */      
    
    temp = fopen ("temp.str","w");
    if (temp == NULL) 
	{
	    puts ("Error opening temporary file space"); 
	}
    fprintf(temp,typed); 
    errchk = 0; 
    
    errchk = fclose (temp); /* This action closes the file to write it */ 
    if (errchk == -1) 
	{
	    puts ("Failed to close file");
	}
    
    /* we need to reopen the file to parse it for the strings */ 
    
    temp = fopen ("temp.str","r"); 
      if (temp == NULL); 
        { 
	    puts("Error Reading file for input"); 
	} 
    /* file should be opened at this point */ 
    /* I probably should have made this a seperate function and may */ 
    /* do that later if i find it eazier to maintain */ 
    err2chk = 0; 
    /* The below code does the actual printing and adding a new line */ 
    do 
    { 
    
    err2chk = fscanf (temp,"%s",typedread);
    if (err2chk != -1)
	{
	printf("%s\n",typedread); 
	}
    }
 while (err2chk != -1);
 errchk = fclose (temp);
 if (errchk == -1) 
   {
    puts("error closeing file");
    }
}
 
Old 01-03-2005, 12:52 PM   #2
itsme86
Senior Member
 
Registered: Jan 2004
Location: Oregon, USA
Distribution: Slackware
Posts: 1,246

Rep: Reputation: 59
What's the getline() function?
 
Old 01-03-2005, 12:56 PM   #3
Hko
Senior Member
 
Registered: Aug 2002
Location: Groningen, The Netherlands
Distribution: Debian
Posts: 2,536

Rep: Reputation: 111Reputation: 111
Quote:
It displayes the error "Error Reading file for input" this is the error i told it to put if the open command return with a null.
Yes, it will allways print that error, even when everything is OK. This s because you need to remove the ; after the "if"-statement (see commented code below)

Quote:
problem is with the this part "temp = fopen ("temp.str","w");" in theory acording to my tutorial this should find the file if it exists remove its contents and open it for writeing.
This works OK on my computer. Try fixing the other mistakes (see comments in the code below, and then try again.

But why are you writing the input to a file and then read it back in? Once the input from the user is read into the buffer (the char *typed is the buffer) you can parse it for spaces from that buffer! Why first writing it to a file and then reading it into another buffer before parsing it?

The getline() function is an advanced version of fgets(), and does some memory-fiddling if the buffer is not large enough to hold the data read. You are not using or checking for this, and I think you don't understand what its memory-fiddling feature is about (you have a mistake in your code caused by this, see comment below). Also getline() is a GNU-only function (it's not a commonly used function), which means your program will not compiled and run correctly on UNIX-like OS's that have not the GNU libc installed. In other words: it's not portable.

I'd recommend fgets() instead of getline(), unless you have special reasons (which you don't in this case).

One more thing:
When you compile with "-Wall" you get all compiler warnings. This will give you more clues about mistakes.

Code:
/*
 * program takes input from user and strips 
 * All of the spaces out and replaces them with newlines 
 */

/* #define added for getline() (see it man page) 
 * Must go before #include <stdio.h>
 */
#define _GNU_SOURCE

#include <stdio.h>

/* Header added for malloc() and free() */
#include <stdlib.h>

char *typed;
int errchk;
int SIZE = 100;

void gettyped(char *);
void striprint(char *);

int main()
{
    typed = (char *) malloc(SIZE);

    gettyped(typed);
    striprint(typed);

    /* Make a good habit of freeing malloc()ed memory.
     * While it does not matter really in this program,
     * not freeing malloc() memory is a popular way of 
     * introducing bugs, especially memory-leaks..
     */
    free(typed);

    return 0;
}

void gettyped(char *typed)
{
    /* This function gets values from the user  */

    /* It would have been better if you declared SIZE of type "size_t"
     * instead of int if you want it to use it here in getline().
     * If you compile with gcc's --Wall option ("Warnings-all") you get
     * a warning about this.
     *
     * Better though to use fgets() instead of getline(). You can then leave
     * it an int.
     */
    errchk = getline(&typed,  &SIZE, stdin);

    if (errchk == -1) {
        puts("Invalid input.");
    }
}

void striprint(char *typed)
{
    FILE *temp;
    char *typedread;
    int err2chk;

    typedread = (char *) malloc(100); /* Better use SIZE here instead of 100 */

    /* Opens a file for tempoary holding space */

    temp = fopen("temp.str", "w");
    if (temp == NULL) {
        puts("Error opening temporary file space");
    }
    fprintf(temp, typed);
    errchk = 0;

    errchk = fclose(temp);  /* This action closes the file to write it */
    if (errchk == -1) {
        puts("Failed to close file");
    }

    /* we need to reopen the file to parse it for the strings */
    /* You could have opened it for reading AND writing instead, and "rewind"
     * it here to start reading from the start by calling rewind() or fseek().
     * (see the man pages of those functions for more info)
     */

    temp = fopen("temp.str", "r");
    if (temp == NULL) ; /* <-- Remove the ';' here or the "if" won't work, so
                               error will print allways without reason! */
    {
        puts("Error Reading file for input");
    }
    /* file should be opened at this point  */
    /* I probably should have made this a seperate function and may */
    /* do that later if i find it eazier to maintain */
    err2chk = 0;
    /* The below code does the actual printing and adding a new line */
    do {

        err2chk = fscanf(temp, "%s", typedread);
        if (err2chk != -1) {
            printf("%s\n", typedread);
        }
    } while (err2chk != -1);
    errchk = fclose(temp);
    if (errchk == -1) {
        puts("error closeing file");
    }
    free(typedread); /* Again, a good habit */
}

Last edited by Hko; 01-03-2005 at 01:14 PM.
 
Old 01-03-2005, 01:13 PM   #4
exvor
Senior Member
 
Registered: Jul 2004
Location: Phoenix, Arizona
Distribution: Gentoo, LFS, Debian,Ubuntu
Posts: 1,537

Original Poster
Rep: Reputation: 87
Yea seams to me im not totaly grasping the whole sizeof thing yet. Im just learning c and this is the first problem that was semi advanced that i have tried to tackle. The tutorial praises getline that is why i tried to use it instead of other methods. It doesent even mention fgets.


as for why i did not use the buffer im still a little in the fog on buffers. And file postion. I figured i would need to make a file because im using file postion to determine where the next word typed is.

Is there a better way to replace a character in a string of undetermined length rather then the model that i have created ??
 
Old 01-03-2005, 01:27 PM   #5
Hivemind
Member
 
Registered: Sep 2004
Posts: 273

Rep: Reputation: 30
And remove the casts of malloc()'s return value:

Code:
typed = (char *) malloc (SIZE);
should be
Code:
typed =  malloc (SIZE);
The code compiles without the cast as long as you have the proper header (stdlib.h) included. If you don't have stdlib.h included (or a header that includes it), a compilation error is generated. If you cast what malloc() returns an error indicating that the proper header hasn't been included won't appear and you're left with a compilable, but non-working program.

I wonder why people insist on casting...must be alot of crappy tutorials out there. I know you have to cast in C++ but in C++ you should use new/delete because malloc/free doesn't understand constructors.
 
Old 01-03-2005, 01:35 PM   #6
exvor
Senior Member
 
Registered: Jul 2004
Location: Phoenix, Arizona
Distribution: Gentoo, LFS, Debian,Ubuntu
Posts: 1,537

Original Poster
Rep: Reputation: 87
Yea stupid tutorial never even explained what the (char * ) even was just that it needed to be in front of malloc.


I dident see why i needed to put it there either ???
 
Old 01-03-2005, 01:37 PM   #7
exvor
Senior Member
 
Registered: Jul 2004
Location: Phoenix, Arizona
Distribution: Gentoo, LFS, Debian,Ubuntu
Posts: 1,537

Original Poster
Rep: Reputation: 87
The header and the ; in front of the if statement was my own bad :P and i think i tracked my less on the file problem down. Its less thats messed up not my data file that was created :P


STUPID LESS BUFFER !!
 
Old 01-03-2005, 01:51 PM   #8
Hko
Senior Member
 
Registered: Aug 2002
Location: Groningen, The Netherlands
Distribution: Debian
Posts: 2,536

Rep: Reputation: 111Reputation: 111
Quote:
Originally posted by exvor
The tutorial praises getline that is why i tried to use it instead of other methods. It doesent even mention fgets.
OK. I had never heard of getline() before. Now that I read its man page, I realize it can be really useful. May be better to stick with it during the tutorial. But realize it can also be very tricky: Your program has a hard to understand-find-and-solve bug only because you use getline(). (this bug will only appear when the user type more than 100 characters). It's too far fetched to try explain this here, while you're still "in the fog" about buffers. To solve this, just remove the gettyped() function and put everyting that was in gettyped() into main(). Like this:
Code:
int main()
{
    typed = (char *) malloc(SIZE);
    errchk = getline(&typed, &SIZE, stdin);
    if (errchk == -1) {
        puts("Invalid input.");
    }
    striprint(typed);
    free(typed);
    return 0;
}

void striprint(char *typed)
{
  /* ..... left out code ......*/
}
And important in this case: use SIZE instead of 100 everywhere the buffer size is needed.

Quote:
I figured i would need to make a file because im using file postion to determine where the next word typed is.
Better use an variable (int) as an index to the buffer-chars for that. Reading files is slow compared to memory reading (not to mention first writing the file)

Quote:
Is there a better way to replace a character in a string of undetermined length rather then the model that i have created ??
Yes. By using the buffer. Much easier, faster & shorter. You can replace your striprint() function with just this:
Code:
void striprint(char *typed)
{
    int i;

    for (i = 0; i < SIZE; ++i) {
        if (typed[i] == ' ') {
            typed[i] = '\n';
        }
    }
    printf(typed);
}
You said: "...in a string of undetermined length". This is where getline() comes in really handy. When you really have no idea how long the input will be, and you don't want to put a limit on it, getline() can save a lot of troubles and opportunities to put bugs in a program. On the other hand getline() opens up a few bug-opportunities itself, but this is definately more managable if you understand how it works. BTW Note that this getline stuff only applies to C. Other, higher level, languages (java, python, perl, php...) have easier solutions. AFAIK even C++-strings make this GNU-getline() a non-option (when using C++ that is).

Last edited by Hko; 01-03-2005 at 02:23 PM.
 
Old 01-03-2005, 02:46 PM   #9
jlliagre
Moderator
 
Registered: Feb 2004
Location: Outside Paris
Distribution: Solaris 11.4, Oracle Linux, Mint, Debian/WSL
Posts: 9,789

Rep: Reputation: 492Reputation: 492Reputation: 492Reputation: 492Reputation: 492
Quote:
I wonder why people insist on casting...must be alot of crappy tutorials out there.
Hmm, or perhaps some crappy comments ...

"Man malloc" or "grep malloc /usr/include/stdlib.h" will show you that malloc returns a void*, so it must be casted to the destination pointer type, unless it is a void*.
Not doing it will trigger a C compiler warning.
 
Old 01-03-2005, 03:00 PM   #10
itsme86
Senior Member
 
Registered: Jan 2004
Location: Oregon, USA
Distribution: Slackware
Posts: 1,246

Rep: Reputation: 59
Quote:
Originally posted by jlliagre
Hmm, or perhaps some crappy comments ...

"Man malloc" or "grep malloc /usr/include/stdlib.h" will show you that malloc returns a void*, so it must be casted to the destination pointer type, unless it is a void*.
Not doing it will trigger a C compiler warning.
That applies to C++ only, not C. A void * pointer can be assigned to any other type of pointer type without the need for a cast. You can see it in action here:
Code:
itsme@dreams:~/C$ cat nowarn.c
#include <stdio.h>

void *func(void)
{
  void *ptr;

  return ptr;
}

int main(void)
{
  int *num;

  num = func();

  return 0;
}
itsme@dreams:~/C$ gcc -Wall -ansi -pedantic nowarn.c -o nowarn
itsme@dreams:~/C$
 
Old 01-03-2005, 03:06 PM   #11
exvor
Senior Member
 
Registered: Jul 2004
Location: Phoenix, Arizona
Distribution: Gentoo, LFS, Debian,Ubuntu
Posts: 1,537

Original Poster
Rep: Reputation: 87
LOL this is so much eazier

Code:
void striprint(char *typed)
{
    int i;

    for (i = 0; i < SIZE; ++i) {
        if (typed[i] == ' ') {
            typed[i] = '\n';
        }
    }
    printf(typed);
}

silly me forgetting strings are arrays
 
Old 01-03-2005, 03:14 PM   #12
itsme86
Senior Member
 
Registered: Jan 2004
Location: Oregon, USA
Distribution: Slackware
Posts: 1,246

Rep: Reputation: 59
Or you could just do it on-the-fly while printing the output:
Code:
{
  int i;

  for(i = 0;typed[i];++i)
    putchar(typed[i] == ' ' ? '\n' : typed[i]);
}
 
Old 01-03-2005, 03:40 PM   #13
exvor
Senior Member
 
Registered: Jul 2004
Location: Phoenix, Arizona
Distribution: Gentoo, LFS, Debian,Ubuntu
Posts: 1,537

Original Poster
Rep: Reputation: 87
Actually theres a problem with doing this way. What happens is because the size of the buffer is 100 it asumes the string is 100 so it loops untill it gets to 100 rather then stopping at the end of the input. Maybe this is why i dident do it this way?
 
Old 01-03-2005, 03:46 PM   #14
exvor
Senior Member
 
Registered: Jul 2004
Location: Phoenix, Arizona
Distribution: Gentoo, LFS, Debian,Ubuntu
Posts: 1,537

Original Poster
Rep: Reputation: 87
upon setting malloc to 1 i get some very strange results.
 
Old 01-03-2005, 03:54 PM   #15
exvor
Senior Member
 
Registered: Jul 2004
Location: Phoenix, Arizona
Distribution: Gentoo, LFS, Debian,Ubuntu
Posts: 1,537

Original Poster
Rep: Reputation: 87
never mind i wasent minding wehre the } are



it seams to work ok but i wonder if you make malloc too big would it continue to loop untill it got to 100
 
  


Reply


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
How this program is working ? C - Problem indian Programming 2 10-07-2005 03:22 PM
program problem megadeth Linux - Software 1 05-24-2005 09:58 PM
su program problem xaos5 Linux - Software 6 03-17-2005 01:02 PM
simple C program problem mined Programming 2 05-08-2004 05:42 AM
C program problem.. Winter Programming 5 05-08-2002 05:10 PM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 08:06 AM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration