I was working on file inputs. I wanted to store each line as a string in array. For example: if the file has lines:
This is line 1.
This is line 2.
This is line 3.
The string should contain:
char str[][] = {"This is line 1.", "This is line 2.", "This is line 3."};
When I was trying out with extra spaces:
This is line 1.
This is line 2.
This is line 3.
The output was in the same format.
I want to delete those extra empty lines from my array of sentences, so that the output is same as before. How should I do that?
[EDIT] I am using following loop to enter sentences from file to the array:
while (fgets(str[i], LINE_SIZE, fp) != NULL)
{
str[i][strlen(str[i]) - 1] = '\0';
i++;
}
You should use an intermediate one-dimensional character array in the call of fgets like for example
for ( char line[LINE_SIZE]; fgets( line, LINE_SIZE, fp) != NULL; )
{
if ( line[0] != '\n' )
{
line[ strcspn( line, "\n" ) ] = '\0';
strcpy( str[i++], line );
}
}
If a line can contain blanks you can change the condition of the if statement the following way
for ( char line[LINE_SIZE]; fgets( line, LINE_SIZE, fp) != NULL; )
{
size_t n = strspn( line, " \t" );
if ( line[n] != '\n' && line[n] != '\0' )
{
line[ n + strcspn( line + n, "\n" ) ] = '\0';
strcpy( str[i++], line );
}
}
In the above code snippet you can substitute this statement
strcpy( str[i++], line );
for this statement if you want that the string would not contain leading spaces.
strcpy( str[i++], line + n );
Related
Need to skip entire line (comment) if the first character is #
Some solutions in other posts suggested fgets
but in my case fscanf is the preferred option as I need to parse each word 1 by 1 later. How can this be done with just fscanf ?
Thank you.
File to be read
#This line is a comment <== skip this entire line
BEGIN {
THIS IS A WORD
}
CODE
void read_file(FILE *file_pointer, Program *p)
{
char buffer[FILESIZE];
int count = 0;
while (fscanf(file_pointer, "%s", buffer) != EOF)
{
if (buffer[0] == '#')
{
continue; <============ need to skip until the end of the line
}
else
{
strcpy(p->wds[count++], buffer);
}
}
}
How can this be done with just fscanf?
fscanf(stdin, "%*[^\n]"); will read all characters other than a new-line character, until an error or end-of-file occurs.
* says to suppress assignment of the data being read.
By default, [ starts a list of characters to accept. However, ^ negates that; [^\n] says to accept all characters other than a new-line character.
Some solutions in other posts suggested fgets but in my case fscanf is the preferred option as I need to parse each word 1 by 1 later. How can this be done with just fscanf ?
I recommend that you use fgets to read a whole line and then you can use sscanf instead of fscanf to read that line word by word.
#include <stdio.h>
void read_file( FILE *file_pointer )
{
char line[100];
while ( fgets( line, sizeof line, file_pointer) != NULL )
{
char *p = line;
char word[50];
int chars_read;
//skip line if it starts with "#"
if ( line[0] == '#' )
{
continue;
}
//read all words on the line one by one
while ( sscanf( p, "%49s%n", word, &chars_read ) == 1 )
{
//do something with the word
printf( "Found word: %s\n", word );
//make p point past the end of the word
p += chars_read;
}
}
}
int main( void )
{
//this function can also be called with an opened file,
//however for simplicity, I will simply pass "stdin"
read_file( stdin );
}
With the input
This is a test.
#This line should be ignored.
This is another test.
this program has the following output:
Found word: This
Found word: is
Found word: a
Found word: test.
Found word: This
Found word: is
Found word: another
Found word: test.
As you can see, the line starting with the # was successfully skipped.
Use fgets() after you've read the first word to read the rest of the line.
while (fscanf(file_pointer, "%s", buffer) != EOF)
{
if (buffer[0] == '#')
{
fgets(file_pointer, buffer, sizeof buffer);
}
else
{
strcpy(p->wds[count++], buffer);
}
}
Hello I am new in c and ı have homework about tcp program and one poin in this project I cant pass can anywone help me please
StartsWithDEL() this function catch DEL user.txt like return true
trim() like trim and give only file name user.txt
BUT when I write client line DEL user.txt is not going delete
if (StartsWithDEL(line,"DEL") == 1)
{
char *deltoken = strtok(line, "DEL");
char *itemDeleting = trim(deltoken);
//in this section I cach file name but cant delete it
remove(itemDeleting);
send(client, "\n" ,strlen("\n"),0);
}
Your call to strtok() in incorrect. The second argument is a string or allowed token delimiters, which in your case a . If you call it with "DEL", it will overwrite the D with \0 and deltoken will point to that empty string.
If you choose to use strtok() then:
char* token = strtok( line, " " ) ;
if( strcmp( token, "DEL" ) == 0 )
{
char* itemDeleting = strtok( NULL, " " ) ;
remove(itemDeleting);
send(client, "\n" ,strlen("\n"),0);
}
However if is simpler to avoid the complexity of strtok(), and the fact that it modifies line by inserting nuls makes it undesirable in many cases. The code above also won't work if a filename may contains spaces.
There are many alternative solutions, for example:
size_t delimiter_index = strcspn( line, " " ) ;
if( strncmp( line, "DEL", delimiter_index ) == 0 )
{
char* itemDeleting = &line[delimiter_index] ;
while( *itemDeleting == 0 && *itemDeleting != '\0' ) itemDeleting++ ;
remove(itemDeleting);
send(client, "\n" ,strlen("\n"),0);
}
Since I have no idea what StartsWithDEL() or trim() so I have avoided them.
In this code, the problem which I am facing is, it only accepts the first word which has a comma at the end. The file has many words with commas at the end but it is accepting the first one. For example, if I gave the option to enter your ID card number which is not the first word. It could be the 2nd or 3rd word in the file then how I would handle it?
1st part
#define STRING_SIZE 49
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void RemoveNewLines( char * buffer ){
char * ptr;
ptr = strchr( buffer, '\n' );
if( ptr )
* ptr = 0;
ptr = strchr( buffer, '\r' ); // in case you see carriage returns also
if( ptr )
* ptr = 0;
}
2nd part
int main(){
char instr[STRING_SIZE+1], string[STRING_SIZE+1];
FILE * fr = NULL;
int flag = 0;
size_t length = 0;
fr = fopen("file.csv","r");
if( fr == NULL ){
printf( "Unable to open file\n" );
return 1;
}
printf("Enter your name: ");
fgets( instr, STRING_SIZE, stdin);
RemoveNewLines( instr );
strcat( instr, "," ); // append a comma to the user's entry
length = strlen( instr );
while( fgets( string, STRING_SIZE, fr ) ){
RemoveNewLines( string );
if( strncmp( instr, string, length ) == 0 ){
flag = 1;
break; } }
fclose(fr);
if( flag == 1 ) // I prefer positive logic{
printf( "Your details :" );
printf( "'%s'\n", string );
return 0;
}
printf("Access denied.\n");
return -1;
}
Well, you are comparing the beginning of a line in the file with whatever that was provided plus a , appended. So it is really what you asked it to do.
If you want to search on arbitrary fields, rather than this approach, I would split the line read from the csv, and compare the nth field with what was provided. Assuming this csv file is a basic one (no quotes or embedded commas/new-lines), you can easily do that by performing N strtok() operations on string.
So let's say that a file has multiply lines each containing one word. I want to store the characters of every word in every line in a array. The code below clearly doesn't work because the -i is zeroed in every loop and the program starts storing characters in the 1st position of the array again. The code is:
while(1)
{
if(fgets(str, 50, fp) == NULL)
break;
for(i=0; i<strlen(str); i++)
p[i] = str[i];
}
you have separate counter variable for p and keep incrementing it to avoid
overwritting, like below.
int write_position = 0;
while(1)
{
if(fgets(str, 50, fp) == NULL)
break;
for(i=0; i<strlen(str); i++)
p[write_position++] = str[i]; // you will not lose previous ones here
}
at the end lenght of the array p is equal to write_position
Fix your file reading loop like this;
while (fgets(str, sizeof(yourString), fp) != NULL)
{
yourString[strlen(yourString) - 1] = '\0'; // delete the new line
printf("%s\n", yourString);
}
So simply in the above code, your while loop will be working until there is no another line to read in the file. In each turn of while loop, it will take one line from your file, and add it to your yourString char array. Notice that, fgets() will be taking newline characters too (\n) for every line in the file, so that we need to remove this characters from the array before we add another line in it.
Before the while loop, You need to declare a char array to store each line in it such as;
char yourString[stringSize];
You need to determine a stringSize for your array to make it has enough storage for your file.
the following proposed code snippet
performs the desired functionality
assumes that the array 'p[]' is an array of char pointers to pointers and contains (at least) enough entries to hold all the lines in the input file
no line in the input file is longer than 48 characters + newline
And now the proposed code:
#define MAX_LINE_LEN 50
char **p;
p = calloc( NUM_LINES_IN_FILE, sizeof( char * ) );
if( !p )
{
perror( "calloc failed" );
exit( EXIT_FAILURE );
}
// implied else, calloc successful
FILE *fp;
if( !(fp = fopen ( "inputFileName", "r" )) )
{
perror( "fopen failed" );
exit( EXIT_FAILURE );
}
// implied else, fopen successful
char str[ MAX_LINE_LEN ];
for( int i=0; fgets(str, sizeof( str ), fp); i++ )
{
// remove trailing newline char
str[ strcspn( str, '\n' ) ] = '\0';
p[i] = strdup( str );
}
fclose( fp );
struct DVDInfo *ReadStruct( void ) {
struct DVDInfo *infoPtr;
int num;
char line[ kMaxLineLength ];
char *result;
infoPtr = malloc( sizeof( struct DVDInfo ) );
if ( NULL == infoPtr ) {
printf( "Out of memory!!! Goodbye!\n" );
exit( 0 );
}
printf( "Enter DVD Title: " );
result = fgets( line, kMaxLineLength, stdin );
line[ strlen( line ) - 1 ] = '\0';
infoPtr->title = MallocAndCopy( line );
printf( "Enter DVD comment: " );
result = fgets( line, kMaxLineLength, stdin );
line[ strlen( line ) - 1 ] = '\0';
infoPtr->comment = MallocAndCopy( line );
do {
printf( "Enter DVD Rating (1-10): " );
scanf( "%d", &num );
Flush();
}
while ( ( num < 1 ) || ( num > 10 ) );
infoPtr->rating = num;
printf( "\n----------\n" );
return( infoPtr );
}
I asked a different question about this code in another thread on stackoverflow but didn't want to double up on that one - why is the terminating zero being added to the end of these files read in by fgets? fgets adds the terminating zero anyway, isn't this overkill?
Generally, you replace the newline character that fgets adds to the string with a NUL character. In all cases, fgets will NUL-terminate.
See: http://www.opengroup.org/onlinepubs/009695399/functions/fgets.html
fgets writes a nul terminator into the buffer you provide (if you specify the buffer size as larger than 0). Otherwise you could not call strlen() on it, strlen() expects a string, and if it isn't nul terminated it is not a string.
You're asking about
line[ strlen( line ) - 1 ] = '\0';
This strips off the last character in line .If you've read a line, it replaces the last character, presumably a \n with a nul terminator.
Consider that fgets just read a line, e.g. your line buffer now contains the string "Hello\n" (the \n is just the escape sequence here, it's actually just 1 character, not 2)
strlen ("Hello\n") is 6, and 6-1 is 5, so the 5. index is replaced by 0
"Hello\n"
^
|
Add 0 terminator
Result:
"Hello"
Just be careful:
you don't want to do line[ strlen(line) - 1 ] = '\0'; on an empty string, in that case you'll end up doing line[-1].
You should check if fgets succeds. You don't want to poke around in line if fgets failed, and didn't write anything to your buffer.
You might want to check whether a whole line actually got read. IF the line you read is larger than
kMaxLineLength ,or e.g. if the last "line" in the file doesn't have a trailing \n , strlen(line) -1 will not be a \n (newline).
Your
result = fgets( line, kMaxLineLength, stdin );
is Ok since the size of line is kMaxLineLength.
fgets reads in at most one less than size characters from stream and stores them into the buffer ...
The line[ strlen( line ) - 1 ] = '\0'; are unnecessary (and insecure — strlen() isn't going to work properly if the string isn't already nul-terminated). fgets() will nul-terminate the buffer. Also, you should be checking that result != NULL before attempting to copy line. fgets() returns NULL at end-of-file or if an error occurs.
Yes, it's overkill.
One suggestion to make it more robust against code rot... change
result = fgets( line, kMaxLineLength, stdin );
to
result = fgets( line, sizeof(line), stdin );