How can I use strstr() with a filename - c

I'm trying to implement the * shell wildcard in a minishell.
I wrote a program that compares the part after * with the current directory's filenames.
After doing some testing, the part that doesn't seem to work is the strstr function, it sends a NULL pointer even when getting to a filename that contains the input substring:
if (strstr(ent->d_name,wildcard)!= NULL)
For example, if I do cat *filename in a folder containing a file named filename, the program will read "filename", then compare it to "filename" yet will result in a NULL pointer.
This is what the code looks like
int wildcardCheck( char* input ) {
int returnflag;
if( strstr( input, "*" ) != NULL ) {
int i;
char* wildcard;
wildcard = strstr( input, "*" );
strcpy( wildcard, wildcard + 1 ); // +1 excludes wildcard (*)
printf( "it's %s", wildcard );
// Open current directory and get all entities
struct dirent* ent;
DIR* dir = opendir( "." );
char* arg;
while( (ent = readdir( dir )) != NULL ) {
// If the entity filename matches the regular expression
printf( " file %s\n", ent->d_name );
if( strstr( ent->d_name, wildcard ) != NULL ) {
arg = malloc( (sizeof( char ) * strlen( ent->d_name )) + 1 );
strcpy( arg, ent->d_name );
// Substitutes the argument containing the wildcard with the new filename
input = strtok( input, "*" );
// We only substitute one filename in this loop and add the rest later, hence break
input = strcat( input, arg );
printf( "arg is%s\n", arg );
printf( "final input is%s", input );
free( arg );
returnflag = 1;
break;
}
else printf( "didn't enter %d : strstr( %s, %s ) == NULL\n", 3, ent->d_name, wildcard );
}
closedir( dir );
}
Here's the testing of the current program:
mysh-master$ cat *ilename
it's ilename
file filename
didn't enter 3 : strstr( filename, ilename
) == NULL
0
cat: ilename: No such file or directory
Exit status : 1

The debug output:
didn't enter 3 : strstr( filename, ilename
) == NULL
from
else printf( "didn't enter %d : strstr( %s, %s ) == NULL\n", 3, ent->d_name, wildcard );
indicates that wildcard == "ilename\n" - i.e. it has a newline so will not match "filename" without a newline.

Related

splitting a string up using different delimiters in C

I am trying to split up a string by using different delimiters. After hours of trial and error using strtok(), I have finally got a way to make it work. However it uses NULLs in the place of given strings in strtok, and I dont fully understand how it works.
I have tried to split it up so I can save it in separate variables so i can use them to return functions within my main function, but it doesnt work, which leads me to believe it is incredibly flimsy way of splitting the string up.
the input string is read from a config file and is in this format:
(6,2) SLUG 1 0 EAST
the current code i'm using is this:
void createSlug(char* data) {
int slugPosX, slugPosY, slugAge;
char *slugDir;
char *token1;
char *token2;
slugPosX = atoi(strtok(data, "("));
token1 = strtok(data, ",");
slugPosY = atoi(strtok(strtok(NULL, ","), ")"));
token2 = strtok(strtok(NULL, ","), ")");
slugAge = atoi(strtok(token2, " SLUG "));
slugDir = strtok(NULL, " 0 ");
printf("slug position is: (%d,%d), with age %d, and direction: %s", slugPosX, slugPosY, slugAge, slugDir);
}
the output would be printed as:
slug position is: (6,2), with age 1, and direction: EAST
The input file changes but is always in the above format. It is also worth mentioning that the '0' in the input string is always 0, so I ignored that part of it, as I could use it as the delimiter.
Is there an easier way of doing this? I'm very very new to C so any help would be greatly appreciated
The input file changes but is always in the above format
Scanf?
int main() {
int w, x,y,z;
char a[60] = "", b[60] = "";
printf("%d\n", sscanf("(6,2) SLUG 1 0 EAST", "(%d,%d) %s %d%d%s", &w,&x,a,&y,&z,b));
printf("w = %d, x = %d, y = %d, z = %d, a = '%s', b = '%s'\n" ,w,x,y,z,a,b);
}
https://godbolt.org/z/Woa94sb1Y
It's a poor craftsman who blames his tools.
To use strtok() it is probably easiest to only invoke it in one place. The function should "know" the record layout and can be written to "segment" the string to suit.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void createSlug( char* data ) {
enum { ePosx, ePosy, eName, eAge, eXXX, eDir };
// ALWAYS initialise variables to avoid sporadic functioning and possible UB
int slugPosX = 0, slugPosY = 0, slugAge = 0;
char *slugDir = "";
int stage = 0;
for( char *cp = data; ( cp = strtok( cp, "(,) \n" ) ) != NULL; cp = NULL )
switch( stage++ ) {
case ePosx: slugPosX = atoi( cp ); break;
case ePosy: slugPosY = atoi( cp ); break;
case eName: break;
case eAge: slugAge = atoi( cp ); break;
case eXXX: break;
case eDir: slugDir = cp; break;
default:
puts( "Extra fields!" );
break;
}
printf("slug position is: (%d,%d), with age %d, and direction: %s", slugPosX, slugPosY, slugAge, slugDir);
}
int main( void ) {
char str[] = "(6,2) SLUG 1 0 EAST\n";
createSlug( str );
return 0;
}
slug position is: (6,2), with age 1, and direction: EAST
Still using atoi() here, but strtol() may be a better translation function.
If you are sure that the characters '(', ',', ')' and ' ' are only used as delimiters and don't ever occur in the tokens, then you can simply use "(,) " as the delimiter string in all calls to strtok:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void createSlug( char* data )
{
int slugPosX, slugPosY, slugAge;
char *slugDir;
const char *delim = "(,) ";
slugPosX = atoi( strtok(data, delim) );
slugPosY = atoi( strtok(NULL, delim) );
//ignore the "SLUG" token
strtok( NULL, delim );
slugAge = atoi( strtok(NULL, delim) );
//ignore the "0" token
strtok( NULL, delim );
slugDir = strtok( NULL, delim );
printf( "slug position is: (%d,%d), with age %d, and direction: %s", slugPosX, slugPosY, slugAge, slugDir );
}
int main( void )
{
char str[] = "(6,2) SLUG 1 0 EAST";
createSlug( str );
}
However, this program may crash if strtok ever returns NULL due to the input not being in the expected format. Here is a different version which does a lot more input validation and prints an error message instead of crashing:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void createSlug( char* data )
{
int slugPosX, slugPosY, slugAge;
char *slugDir;
char *token, *p;
const char *delim = "(,) ";
//attempt to find first token
token = strtok( data, delim );
if ( token == NULL )
{
fprintf( stderr, "Unable to find first token!\n" );
exit( EXIT_FAILURE );
}
//attempt to convert first token to an integer
slugPosX = strtol( token, &p, 10 );
if ( *p != '\0' )
{
fprintf( stderr, "Unable to convert first token to an integer!\n" );
exit( EXIT_FAILURE );
}
//attempt to find second token
token = strtok( NULL, delim );
if ( token == NULL )
{
fprintf( stderr, "Unable to find second token!\n" );
exit( EXIT_FAILURE );
}
//attempt to convert second token to an integer
slugPosY = strtol( token, &p, 10 );
if ( *p != '\0' )
{
fprintf( stderr, "Unable to convert second token to an integer!\n" );
exit( EXIT_FAILURE );
}
//attempt to find third token
token = strtok( NULL, delim );
if ( token == NULL )
{
fprintf( stderr, "Unable to find third token!\n" );
exit( EXIT_FAILURE );
}
//verify that third token contains "SLUG"
if ( strcmp( token, "SLUG" ) != 0 )
{
fprintf( stderr, "Invalid content of third token!\n" );
exit( EXIT_FAILURE );
}
//attempt to find fourth token
token = strtok( NULL, delim );
if ( token == NULL )
{
fprintf( stderr, "Unable to find fourth token!\n" );
exit( EXIT_FAILURE );
}
//attempt to convert fourth token to an integer
slugAge = strtol( token, &p, 10 );
if ( *p != '\0' )
{
fprintf( stderr, "Unable to convert fourth token to an integer!\n" );
exit( EXIT_FAILURE );
}
//attempt to find fifth token
token = strtok( NULL, delim );
if ( token == NULL )
{
fprintf( stderr, "Unable to find fifth token!\n" );
exit( EXIT_FAILURE );
}
//verify that fifth token contains "0"
if ( strcmp( token, "0" ) != 0 )
{
fprintf( stderr, "Invalid content of fifth token!\n" );
exit( EXIT_FAILURE );
}
//attempt to find sixth token
slugDir = strtok( NULL, delim );
if ( slugDir == NULL )
{
fprintf( stderr, "Unable to find sixth token!\n" );
exit( EXIT_FAILURE );
}
printf( "slug position is: (%d,%d), with age %d, and direction: %s", slugPosX, slugPosY, slugAge, slugDir );
}
int main( void )
{
char str[] = "(6,2) SLUG 1 0 EAST";
createSlug( str );
}
However, a significant amount of the code is now duplicated to a certain degree, so the code is not very maintainable.
Therefore, it may be better to use a more systematic approach, by for example
calling strtok in a loop, and
creating a function for converting tokens to integers, and calling this function multiple times.
Here is an alternative solution which does this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#define NUM_TOKENS 6
// This function will return true if it was able to convert
// the token to an int, otherwise it will return false.
bool convert_token_to_int( char *str, int *result )
{
long num;
char *p;
num = strtol( str, &p, 10 );
if ( p == str || *p != '\0' )
{
return false;
}
*result = num;
return true;
}
void createSlug( char* data )
{
char *tokens[NUM_TOKENS];
int slugPosX, slugPosY, slugAge;
char *slugDir;
const char *delim = "(,) ";
//store all tokens in the array tokens
tokens[0] = strtok( data, delim );
for ( int i = 0; ; )
{
if ( tokens[i] == NULL )
{
fprintf( stderr, "Could not find token #%d!\n", i );
return;
}
//break out of loop after finishing all tokens
if ( ++i == NUM_TOKENS )
break;
//find next token for next loop iteration
tokens[i] = strtok( NULL, delim );
}
//convert the integer tokens
if (
! convert_token_to_int( tokens[0], &slugPosX )
||
! convert_token_to_int( tokens[1], &slugPosY )
||
! convert_token_to_int( tokens[3], &slugAge )
)
{
fprintf( stderr, "Error converting tokens to integers!\n" );
exit( EXIT_FAILURE );
}
//verify that non-variable tokens contain the
//intended values
if (
strcmp( tokens[2], "SLUG" ) != 0
||
strcmp( tokens[4], "0" ) != 0
)
{
fprintf( stderr, "Non-variable tokens do not contain the intended values!\n" );
exit( EXIT_FAILURE );
}
//make slugDir point to the appropriate token
slugDir = tokens[5];
printf( "slug position is: (%d,%d), with age %d, and direction: %s", slugPosX, slugPosY, slugAge, slugDir );
}
int main( void )
{
char str[] = "(6,2) SLUG 1 0 EAST";
createSlug( str );
}

Getting multiple variables from a read in line

I am having trouble getting multiple number vars from a read in line. For a single value I can do strtol(), but how can I get the float and long values of a sentence that is similar to as follows.
Please aim 3.567 degrees at a height of 5 meters.
I tried doing two different calls to my buffer sentence, however it got neither of my values. I have no issues with get single values, but with to, I get 0.000 from my strtof call and 0 from mmy strtol call.
Assuming that the input always starts with the string "Please aim ", followed by a floating-point number, followed by the string " degrees at a height of ", followed by an integer, followed by the string " meters.", then you can use the functions strtof and strtol, but you must skip the strings first, for example like this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main( void )
{
char *line = "Please aim 3.567 degrees at a height of 5 meters.";
char *part1 = "Please aim ";
char *part2 = " degrees at a height of ";
char *part3 = " meters.";
float degrees;
long height;
size_t part1_len = strlen( part1 );
size_t part2_len = strlen( part2 );
size_t part3_len = strlen( part3 );
//make p point to start of line
char *p = line;
char *q;
//verify that the line starts with part1 and skip it
if ( strncmp( p, part1, part1_len ) != 0 )
{
fprintf( stderr, "Unable to find part1!\n" );
exit( EXIT_FAILURE );
}
p += part1_len;
//attempt to convert degrees value and skip it
degrees = strtof( p, &q );
if ( p == q )
{
fprintf( stderr, "Error converting degrees!\n" );
exit( EXIT_FAILURE );
}
p = q;
//verify that the line continues with part2 and skip it
if ( strncmp( p, part2, part2_len ) != 0 )
{
fprintf( stderr, "Unable to find part2!\n" );
exit( EXIT_FAILURE );
}
p += part2_len;
//attempt to convert height value and skip it
height = strtol( p, &q, 10 );
if ( p == q )
{
fprintf( stderr, "Error converting height!\n" );
exit( EXIT_FAILURE );
}
p = q;
//verify that the line continues with part3 and skip it
if ( strncmp( p, part3, part3_len ) != 0 )
{
fprintf( stderr, "Unable to find part3!\n" );
exit( EXIT_FAILURE );
}
p += part3_len;
//verify that we have reached the end of the string
if ( *p != '\0' )
{
fprintf( stderr, "Unexpected character encountered!\n" );
exit( EXIT_FAILURE );
}
//print the results
printf(
"Results:\n"
"Degrees: %f\n"
"Height: %ld\n",
degrees, height
);
}
This program has the following output:
Results:
Degrees: 3.567000
Height: 5

Using fgets and strtok() to read a text file -C

I’m trying to read text from stdin line by line using fgets() and store the text in a variable “text”. However, when I use strtok() to split the words, it only works for a couple lines before terminating. What should I change to make it run through the entire text?
#define WORD_BUFFER_SIZE 50
#define TEXT_SIZE 200
int main(void) {
char stopWords[TEXT_SIZE][WORD_BUFFER_SIZE];
char word[WORD_BUFFER_SIZE];
int numberOfWords = 0;
while(scanf("%s", word) == 1){
if (strcmp(word, "====") == 0){
break;
}
strcpy(stopWords[numberOfWords], word);
numberOfWords++;
}
char *buffer = malloc(sizeof(WORD_BUFFER_SIZE)*TEXT_SIZE);
char *text = malloc(sizeof(WORD_BUFFER_SIZE)*TEXT_SIZE);
while(fgets(buffer, WORD_BUFFER_SIZE*TEXT_SIZE, stdin) != NULL){
strcat(text, buffer);
}
char *k;
k = strtok(text, " ");
while (k != NULL) {
printf("%s\n", k);
k = strtok(NULL, " ");
}
}
char *buffer = malloc(sizeof(WORD_BUFFER_SIZE)*TEXT_SIZE);
char *text = malloc(sizeof(WORD_BUFFER_SIZE)*TEXT_SIZE);
sizeof(WORD_BUFFER_SIZE) is a constant, it's the size of integer. You probably mean WORD_BUFFER_SIZE * TEXT_SIZE. But you can find the file size and calculate exactly how much memory you need.
char *text = malloc(...)
strcat(text, buffer);
text is not initialized and doesn't have a null-terminator. strcat needs to know the end of text. You have to set text[0] = '\0' before using strcat (it's not like strcpy)
int main(void)
{
fseek(stdin, 0, SEEK_END);
size_t filesize = ftell(stdin);
rewind(stdin);
if (filesize == 0)
{ printf("not using a file!\n"); return 0; }
char word[1000] = { 0 };
//while (scanf("%s", word) != 1)
// if (strcmp(word, "====") == 0)
// break;
char* text = malloc(filesize + 1);
if (!text)
return 0;
text[0] = '\0';
while (fgets(word, sizeof(word), stdin) != NULL)
strcat(text, word);
char* k;
k = strtok(text, " ");
while (k != NULL)
{
printf("%s\n", k);
k = strtok(NULL, " ");
}
return 0;
}
According to the information you provided in the comments section, the input text is longer than 800 bytes.
However, in the line
char *text = malloc(sizeof(WORD_BUFFER_SIZE)*TEXT_SIZE);
which is equivalent to
char *text = malloc(800);
you only allocated 800 bytes as storage for text. Therefore, you did not allocate sufficient space to store the entire input into text. Attempting to store more than 800 bytes will result in a buffer overflow, which invokes undefined behavior.
If you want to store the entire input into text, then you must ensure that it is large enough.
However, this is probably not necessary. Depending on your requirements, it is probably sufficient to process one line at a time, like this:
while( fgets( buffer, sizeof buffer, stdin ) != NULL )
{
char *k = strtok( buffer, " " );
while ( k != NULL )
{
printf( "%s\n", k );
k = strtok( NULL, " " );
}
}
In that case, you do not need the array text. You only need the array buffer for storing the current contents of the line.
Since you did not provide any sample input, I cannot test the code above.
EDIT: Based on your comments to this answer, it seems that your main problem is how to read in all of the input from stdin and store it as a string, when you do not know the length of the input in advance.
One common solution is to allocate an initial buffer, and to double its size every time it gets full. You can use the function realloc for this:
#include <stdio.h>
#include <stdlib.h>
int main( void )
{
char *buffer;
size_t buffer_size = 1024;
size_t input_size = 0;
//allocate initial buffer
buffer = malloc( buffer_size );
if ( buffer == NULL )
{
fprintf( stderr, "allocation error!\n" );
exit( EXIT_FAILURE );
}
//continuously fill the buffer with input, and
//grow buffer as necessary
for (;;) //infinite loop, equivalent to while(1)
{
//we must leave room for the terminating null character
size_t to_read = buffer_size - input_size - 1;
size_t ret;
ret = fread( buffer + input_size, 1, to_read, stdin );
input_size += ret;
if ( ret != to_read )
{
//we have finished reading from input
break;
}
//buffer was filled entirely (except for the space
//reserved for the terminating null character), so
//we must grow the buffer
{
void *temp;
buffer_size *= 2;
temp = realloc( buffer, buffer_size );
if ( temp == NULL )
{
fprintf( stderr, "allocation error!\n" );
exit( EXIT_FAILURE );
}
buffer = temp;
}
}
//make sure that `fread` did not fail end due to
//error (it should only end due to end-of-file)
if ( ferror(stdin) )
{
fprintf( stderr, "input error!\n" );
exit( EXIT_FAILURE );
}
//add terminating null character
buffer[input_size++] = '\0';
//shrink buffer to required size
{
void *temp;
temp = realloc( buffer, input_size );
if ( temp == NULL )
{
fprintf( stderr, "allocation error!\n" );
exit( EXIT_FAILURE );
}
buffer = temp;
}
//the entire contents is now stored in "buffer" as a
//string, and can be printed
printf( "contents of buffer:\n%s\n", buffer );
free( buffer );
}
The code above assumes that the input will be terminated by an end of file condition, which is probably the case if the input is piped from a file.
On second thought, instead of having one large string for the whole file, as you are doing in your code, you may rather want an array of char* to the individual strings, each representing a line, so that for example lines[0] will be the string of the first line, lines[1] will be the string of the second line. That way, you can easily use strstr to find the " ==== " deliminator and strchr on each individual line to find the individual words, and still have all the lines in memory for further processing.
I don't recommend that you use strtok in this case, because that function is destructive in the sense that it modifies the string, by replacing the deliminators with null characters. If you require the strings for further processing, as you stated in the comments section, then this is probably not what you want. That is why I recommend that you use strchr instead.
If a reasonable maximum number of lines is known at compile-time, then the solution is rather easy:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_LINE_LENGTH 1024
#define MAX_LINES 1024
int main( void )
{
char *lines[MAX_LINES];
int num_lines = 0;
char buffer[MAX_LINE_LENGTH];
//read one line per loop iteration
while ( fgets( buffer, sizeof buffer, stdin ) != NULL )
{
int line_length = strlen( buffer );
//verify that entire line was read in
if ( buffer[line_length-1] != '\n' )
{
//treat end-of file as equivalent to newline character
if ( !feof( stdin ) )
{
fprintf( stderr, "input line exceeds maximum line length!\n" );
exit( EXIT_FAILURE );
}
}
else
{
//remove newline character from string
buffer[--line_length] = '\0';
}
//allocate memory for new string and add to array
lines[num_lines] = malloc( line_length + 1 );
//verify that "malloc" succeeded
if ( lines[num_lines] == NULL )
{
fprintf( stderr, "allocation error!\n" );
exit( EXIT_FAILURE );
}
//copy line to newly allocated buffer
strcpy( lines[num_lines], buffer );
//increment counter
num_lines++;
}
//All input lines have now been successfully read in, so
//we can now do something with them.
//handle one line per loop iteration
for ( int i = 0; i < num_lines; i++ )
{
char *p, *q;
//attempt to find the " ==== " marker
p = strstr( lines[i], " ==== " );
if ( p == NULL )
{
printf( "Warning: skipping line because unable to find \" ==== \".\n" );
continue;
}
//skip the " ==== " marker
p += 6;
//split tokens on remainder of line using "strchr"
while ( ( q = strchr( p, ' ') ) != NULL )
{
printf( "found token: %.*s\n", (int)(q-p), p );
p = q + 1;
}
//output last token
printf( "found token: %s\n", p );
}
//cleanup allocated memory
for ( int i = 0; i < num_lines; i++ )
{
free( lines[i] );
}
}
When running the program above with the following input
first line before deliminator ==== first line after deliminator
second line before deliminator ==== second line after deliminator
it has the following output:
found token: first
found token: line
found token: after
found token: deliminator
found token: second
found token: line
found token: after
found token: deliminator
If, however, there is no reasonable maximum number of lines known at compile-time, then the array lines will also have to be designed to grow in a similar way as buffer in the previous program. The same applies for the maximum line length.

How to get absolute path of a symbolic link?

How can I get the absolute path of a symbolic link? If I do it in the following way:
char buf[100];
realpath(symlink, buf);
I won't get the absolute path of the symlink, but instead I would get the absolute path this symlink links to. Now my question is: What If I want to get the absolute path of the symlink itself? Is there any function in Linux C that allows me to do so?
Note: What I'd like to achieve is the absolute path of the symbolic link itself, not the path it's pointing to! For example, if the relative path of a symbolic link is Task2/sym_lnk, I want its absolute path, which can be /home/user/kp/Task2/sym_lnk.
You can use realpath() function with the parent folder of the symlink, then you concatenate the symlink name.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <unistd.h>
// Find the last occurrence of c in str, otherwise returns NULL
char* find_last_of( char *str, char c )
{
for( char *i = str + strlen(str) ; i >= str ; i-- )
if( *i == c )
return i;
return NULL;
}
// Does the job
char* getAbsPath( char *path )
{
char *name; // Stores the symlink name
char *tmp; // Aux for store the last /
char *absPath = malloc( PATH_MAX ); // Stores the absolute path
tmp = find_last_of( path, '/' );
// If path is only the symlink name (there's no /), then the
// parent folder is the current work directory
if( tmp == NULL ){
name = strdup( path );
getcwd( absPath, PATH_MAX ); // Is already absolute path
}
else{
// Extract the name and erase it from the original
// path.
name = strdup( tmp + 1 );
*tmp = '\0';
// Get the real path of the parent folder.
realpath( path, absPath );
}
// Concatenate the realpath of the parent and "/name"
strcat( absPath, "/" );
strcat( absPath, name );
free( name );
return absPath;
}
// Test the function
int main( int argc, char **argv )
{
char *absPath;
if( argc != 2 ){
fprintf( stderr, "Use:\n\n %s <symlink>\n", *argv );
return -1;
}
// Verify if path exists
if( access( argv[1], F_OK ) ){
perror( argv[1] );
return -1;
}
absPath = getAbsPath( argv[1] );
printf( "Absolute Path: %s\n", absPath );
free( absPath );
return 0;
}
If you use the above code with directories, it needs an special case for "." and "..", but works with "./" and "../"
You can use the system call readlink():
int readlink(const char* fdpath, char* filepath, size_t pathsize);
fdpath is the path of the symbolic link, something like /proc/pid/fd/link_number.
filepath is the path of the file it's pointing to.
Note that readlink() does not null terminate the output string, but does reports its length in the return value.

Strange behaviour using fgets and strtok_r

This is my code:
#define LEN 40
#define STUDLIST "./students.txt"
int main()
{
FILE * studd;
char del[] = "" " '\n'";
char name[LEN], surname[LEN], str[LEN];
char *ret;
char *tokens[2] = {NULL};
char *pToken = str;
unsigned int i = 0;
/* open file */
if ( (studd = fopen(STUDLIST,"r") ) == NULL )
{
fprintf(stderr, "fopen\n");
exit(EXIT_FAILURE);
}
while((ret = fgets(str, LEN, studd)))
{
if(ret)
{
for( tokens[i] = strtok_r( str, del, &pToken ); ++i < 2;
tokens[i] = strtok_r( NULL, del, &pToken ) );
strcpy(name, tokens[0]);
strcpy(surname, tokens[1]);
printf( "name = %s\n", name );
printf( "surname = %s\n", surname );
}
fflush(studd);
}
fclose(studd);
return 0;
}
Here there is the file students.txt: http://pastebin.com/wNpmXYis
I don't understand why the output isn't correct as I expected.
I use a loop to read each line with fgets, then I have a sting composed by [Name Surname], and I want to divide it in two different strings ([name] and [surname]) using strtok_r. I tried with a static string and it works well, but If I read many strings from FILE the output is not correct as you can see here:
http://pastebin.com/70uPMzPh
Where is my fault?
Why are you using forloop?
...
while((ret = fgets(str, LEN, studd)))
{
if(ret)
{
tokens[0] = strtok_r( str, del, &pToken );
tokens[1] = strtok_r( NULL, del, &pToken );
strcpy(name, tokens[0]);
strcpy(surname, tokens[1]);
printf( "name = %s\n", name );
printf( "surname = %s\n", surname );
}
}
You start i at zero:
unsigned int i = 0;
And later you increment it:
++i < 2;
You never set i back to zero, and in fact, continue incrementing i again for every new line in your file. With 14 names in your input file, I expect i to get to about 14.(or maybe 13 or 15, depending on the exact logic).
So this line:
tokens[i] = strtok_r(...);
ends up putting strtok results into tokens[2..15]. But only tokens[0] and tokens[1] are valid. Everything else is undefined behavior.
Answer: Be sure you reset i to zero when you read a new line of your file.

Resources