Extract a multi-digit decimal from a string in c [closed] - c

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed last year.
Improve this question
I have a buffer containing a null terminated string buf[100].
I am using fgets to read from a fd into the buffer in a while loop.
Here is an example string that might be read into the buffer
Sundaresan Sulochana 579 917 8024
All strings follow this convention of "last first area_code ...". I want to extract the area code as a decimal (so in this case 579). I am currently iterating through the string looking for spaces, finding the start of the area code, reading 3 characters, then converting to decimal, but I was wondering if there is a more efficient way. I tried sscanf but was getting unexpected results.
Thanks!
input_data = fdopen(in_p[0], "r");
int i, j;
while (fgets(buf, 100, input_data) != NULL) {
if (sscanf(buf, "%*s%*s%d", &new_code) == 1){
printf("code = %d\n", new_code);
}
else
{
printf("Error scanning area code\n");
}
/*
for (i=0,j=0;buf[i] != '\n'; i++){
if (buf[i] == ' '){
j++;
}
if (j == 4){
for(j=0; j<3; j++){
str_code[j] = buf[j+i+1];
}
str_code[3] = '\n';
new_code = atoi(str_code);
break;
}
}*/

User input is best done using a combination of fgets() and strtok(), IMHO. For example, if you with to read a record exactly as you described:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
printf( "last first area_code ... ? " );
fflush( stdout );
char s[1000] = {0};
fgets( s, sizeof(s), stdin );
const char * delimiters = " \t";
char * last_name = strtok( s, delimiters );
char * first_name = strtok( NULL, delimiters );
char * area_code_s = strtok( NULL, delimiters );
int area_code = area_code_s ? atoi( area_code_s ) : 0;
//...
// (Make sure to check that nothing is NULL before trying to print it.
// You should be able to do this when using a code snippet online.)
printf( "%s %s's area code is %d.\n", first_name, last_name, area_code );
}
If you are reading records, it is worth your time to make a struct:
struct person
{
char last_name[50];
char first_name[50];
int area_code;
...
};
And a function to convert a string to a struct:
bool s_to_person( char * s, struct person * p )
{
if (!s) return false;
// ...
// use strtok(), etc here. Make sure to watch out for errors, and
// return true only if nothing went wrong.
return true;
}
Which you can then use in a loop. For example, to fill an array of people:
enum { MAX_PEOPLE = 1000 };
struct person people[MAX_PEOPLE];
int npeople = 0;
char s[1000];
while ((npeople < MAX_PEOPLE)
and s_to_person( fgets( s, sizeof(s), stdin ), people+npeople ))
{
npeople += 1;
}
Make sure to keep your reference handy and avoid passing NULL values as argument to standard functions taking strings.

Related

Spilting strings in C with mulitple delimiters [duplicate]

This question already has answers here:
split char string with multi-character delimiter in C
(5 answers)
Closed 1 year ago.
so i need to split the string given with:
const char *inputs[] = {"111adbhsd111gfhds","goal!","zhd!111oosd","111let111"};
to ouput:
char *outputs[]={"adbhsd","gfhds","goal!","zhd!","oosd","let"}
where the delimiter is : "111" .
I tried with strtok , but as the delimiter is of mulitple character , it did't work!
any idea, how it might give the output, will help!
what i have did till now:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
size_t split(
char **outputs, // outputs
const char *separator, // the delimiter
const char **inputs,
size_t num_inputs // no. of input strings, given in input array
){
size_t num_outputs = 0;
int l= 0;
for(size_t i = 0; i < num_inputs ; i++){
if(strstr(*(inputs+i), separator) != NULL){ // to check, if the string of the given input array has the delimiter
char* pos = strstr( *(inputs+i), separator);
//having problem in this part
}
else
{
strcpy( outputs[l] , *(inputs+i));;
l++;
num_outputs++;
}
}
return num_outputs;
}
int main(){
const char *inputs[] = {
"111abdhsd111gfhds",
"goal!",
"zhd!111oosd",
"111let111"
};
char *outputs[] ={malloc(1000),malloc(1000),malloc(1000),malloc(1000),malloc(1000),malloc(1000)};
split(outputs, "111", inputs, 4);
for(int i =0; i < 6; i++)
{
printf("The output[%d] is : %s" ,i, outputs[i]);
free(outputs[i]);
}
return 0;
}
NOTE: The following answer refers to revision 2 of the question, which is before OP added code to the question which already uses the function strstr.
If the string is delimited by a substring instead of a single character, you can use the function strstr to find the delimiter substrings:
#include <stdio.h>
#include <string.h>
int main( void )
{
const char input[] = "111adbhsd111gfhds", *p = input;
const char *const delim = "111";
//remember length of delimiter substring
const size_t delim_length = strlen( delim );
for (;;) //infinite loop, equivalent to "while ( 1 )"
{
//attempt to find next delimiter substring
const char *q = strstr( p, delim );
//break loop if this is last token
if ( q == NULL )
break;
//print token
if ( q == p )
printf( "Found token: <empty>\n" );
else
printf( "Found token: %.*s\n", (int)(q-p), p );
//make p point to start of next token
p = q + delim_length;
}
//print last token
printf( "Found token: %s\n", p );
}
This program has the following output:
Found token: <empty>
Found token: adbhsd
Found token: gfhds
Since the sample input starts with the delimiter "111", the first token is empty. If you don't want empty tokens to be printed, you can simply remove the first printf statement in the code.
This is not a full solution to your problem, as your task seems to consist of multiple input strings instead of only one, and writing to output arrays instead of printing to the screen. In accordance with the community guidelines for homework questions, I will not provide a full solution to your problem at this time. Instead, for now, I have only provided a solution to the problem that you stated that you had trouble with (which was using strtok with substring delimiters). If necessary, I can add additional code later.

How to make the code to accept the next word not just the first one?

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.

C file compiling but not running [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Closed 6 years ago.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
This question does not appear to be about a specific programming problem, a software algorithm, or software tools primarily used by programmers. If you believe the question would be on-topic on another Stack Exchange site, you can leave a comment to explain where the question may be able to be answered.
Improve this question
So my program takes a file as input and parses out spaces. Tokens are saved into an array. I have a function to print out the contents of the array to test if the parser works. The code compiles with gcc -o filename filename.c . But when I run the program and give it a filepath, I get a pop up window indicating filename.exe has stopped working : A problem caused the program to stop working correctly. Windows will close the program and notify you if a solution is available.
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
char file_name[100];
char *token_array[256];
int main()
{
char ch;
FILE *fp;
int n=0;
char *str;
printf("Enter filepath\n");
gets(file_name);
fp = fopen(file_name,"r");
if( fp == NULL )
{
perror("Error opening the file.\n");
exit(EXIT_FAILURE);
}
int i = 0;
char *p;
while( ( ch = fgetc(fp) ) != EOF )
{
char *fgets(char *str, int n, FILE *stream);
p = strtok(str, " ");
i=0;
while(p!=NULL)
{
strcpy(token_array[i], p);
}
i++;
}
for(n=0;n<256;n++)
{
printf("%s", &token_array[n]);
}
return 0;
}
You can try this code instead. I changed your program so that it can read and tokenize the file.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *trim(char *s) {
int i = strlen(s) - 1;
if (s[i] == '\n')
s[i] = '\0';
return s;
}
#define BUFFER_SIZE 100
char *token_array[256];
int main( int argc, char** argv ){
const char *delimiter_characters = " ";
char *filename = malloc(BUFFER_SIZE);
int i = 0;
printf("Enter filepath\n");
fgets(filename, 100, stdin);
FILE *input_file = fopen( trim(filename), "r" );
char buffer[ BUFFER_SIZE ];
char *last_token;
if( input_file == NULL ){
fprintf( stderr, "Unable to open file %s\n", filename );
}else{
// Read each line into the buffer
while( fgets(buffer, BUFFER_SIZE, input_file) != NULL ){
// Write the line to stdout
//fputs( buffer, stdout );
// Gets each token as a string and prints it
last_token = strtok( buffer, delimiter_characters );
while( last_token != NULL ){
//printf( "%s\n", last_token );
token_array[i] = malloc(100);
strcpy(token_array[i], last_token);
i++;
last_token = strtok( NULL, delimiter_characters );
}
}
if( ferror(input_file) ){
perror( "The following error occurred" );
}
fclose( input_file );
}
int n;
for(n=0;token_array[n] != NULL && n<256;n++)
{
printf("%s", token_array[n]);
free(token_array[n]);
}
free(filename);
return 0;
}
data.txt
Hello Foo Bar
How are you?
Test
Debug/gnu
Enter filepath
data.txt
HelloFooBar
Howareyou?
Process finished with exit code 0
The contents of the array are
n[0] Hello
n[1] Foo
n[2] Bar
n[3] How
n[4] are
n[5] you?
You can see the contents of the array if you add debug info:
printf("n[%d] %s\n", n, token_array[n]);
This line does nothing:
char *fgets(char *str, int n, FILE *stream);
As written, that line is nothing but a declaration of a function, probably not what you want.
If you're going to use fgets(), use fgets() alone and don't mix it with fgetc():
char str[1024];
while ( fgets( str, sizeof( str ), fp )
{
.
.
.
fgets() returns NULL upon EOF or an error condition. And note that str is not a char *, it's a char array. An even better solution would be to use getline() because fgets() with a fixed-length buffer can only read entire lines that fit into the buffer. Longer lines will be split.
fgetc() returns int, not char. But you don't shouldn't use fgetc() when reading lines from a file with fgets(). Pick one and use that. But if you use fgetc(), you'll need to write code to put together each line as you read it character-by-character.
And what does token_array[i] point to? You declare token_array as an array of pointers:
char *token_array[256];
But you never allocate any memory for each pointer in the array to point to.
The easiest solution is to change
strcpy(token_array[i], p);
to
token_array[i] = strdup(p);
assuming your platform has strdup(), which is equivalent to a malloc() and strcpy() to the memory returned by malloc(), so you need to call free() on the string you get from strdup().
Your use of strtok() is wrong. See How does strtok() split the string into tokens in C? for examples of proper strtok() usage.
And since token_array is an array of char * pointers, this
printf("%s", &token_array[n]);
will take the address of the actual pointer itself, and not the string it's supposed to point to. It will then try to print out a "string" in the memory containing the pointer variable. That's won't work well. Since it's already a char *, all you need is this:
printf("%s", token_array[n]);

What will cause fgets() to continuously wait for input?

I am trying to put together a program that will ask the user to enter song titles for a set list to be printed in a random order. The program uses fgets() to take in the song titles. It also uses memory allocation to put each song in. It is similar to:
argv[0] = song1, argv[1] = song2, argv[2] = song3 (etc.)
The problem I am running into is when the program is executed fgets() waits continuously for input, when it is only a total of five songs to be entered. I want to know what will cause fgets() to continuously wait for input? Thanks for your help.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
int main( void ){
printf("\tPlease enter the songs you want to play!\n");
printf("\tI will create the set list and randomize it for you!\n");
printf("\t(enter all songs with a space in between each and then press 'enter')\n");
int s = 5; //Here we declare number of songs to be entered
int set = 5;//This is set list size
char input[100];
char *argv[ s ];
char *token;
/* get the input and perform memory allocation */
fgets(input, s, stdin);
token = strtok(input, " ");
int i=0;
while( token != NULL ) {
argv[i] = malloc(strlen(token) + 1);
memcpy(argv[i], token, strlen(token)+1);
i++;
token = strtok(NULL, " ");
}
argv[i] = NULL; //argv ends with NULL
unsigned int setList[ s ];
memset( setList, 0, s*sizeof(unsigned int) );//Must manually initalize array
srand( time( NULL ) ); // seed random-number generator
/*Begin Randomize Code*/
size_t column;
size_t c;
size_t c1;
size_t column1;
for ( c = 1; c <= set; ++c ) {
do {
column = rand() % s;
} while( setList[ column ] != 0 );
setList[ column ] = c;
}//end of for
/*End Randomize Code*/
/*Begin Code to Print SetList*/
for ( c1 = 1; c1 <= set; ++c1 ) {
for ( column1 = 0; column1 < s; ++column1 ) {
if ( setList[ column1 ] == c1 ) {
printf( "%s\n", argv[ column1 ]);
}//end of for (oops if)
}//end of for
}//end of if (oops for)
/*End Code to Print SetList*/
}//end of main
Actually, the problem is right here:
fgets(input, s, stdin); <-- you tell fgets to only read 5 characters (actually only 4, the fifth character is the null terminator); this means that your tokenization will fail and not allocate memory for all five elements of argv, causing an access violation in your printf call later.
Change it to:
fgets(input, sizeof(input), stdin); and you get this:
Some other problems with the code:
argv is, by convention, the name of the tokenized command line string passed to your main function, so don't name your variables like this, it's confusing
instead of using a variable for things like the maximum size of something, use #define, e.g. #define MAX_SONGS 5
it is very buggy and will crash if bad input is given, you should validate it (for instance, if I enter more than 5 songs, you'll overflow your buffer and most likely crash)

C String parsing

It's a relatively simple thing to do, but I've been having problems separating a string from a file into multiple variables. I've tried strtok and sscanf with delimiters, but I seem to be doing something wrong.
#define MAX 40
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
int main()
{
char brd_str[26];
char board[26], Res[26], Ind[26], Cap[26];
int i=0, n=0;
FILE *data;
data = fopen ("C:\\datafile.txt", "rt");
fgets(brd_str, 26, data);
sscanf(brd_str,"%d[^,],%f[^,],%e[^,],%e[^,]", &board, &Res, &Ind, &Cap);
printf("%3d %6d %8e %8e", board, Res, Ind, Cap);
fclose(data);
printf("\nPlease enter something for the program to exit");
scanf("%d", &i);
return(0);
}
The string itself looks like this 2,4.57,2.01e-2,5.00e-8. The comma would be the delimiter in this case. When I compile it I have really large numbers which are incorrect.
This would have to be done multiple times (up to 40), and the variables themselves will be used for calculations.
There seems to be something wrong with the sscanf statement I've put in. I'm not really sure what the problem is.
Change:
char board[26], Res[26], Ind[26], Cap[26];
to:
int board;
float Res;
float Ind;
float Cap;
And, change:
printf("%3d %6d %8e %8e", board, Res, Ind, Cap);
to (perhaps):
printf("%3d %6f %8e %8e", board, Res, Ind, Cap);
Basically, your most immediate problem is
char board[26], Res[26], Ind[26], Cap[26];
So, you have strings ...
sscanf(brd_str,"%d[^,],%f[^,],%e[^,],%e[^,]", &board, &Res, &Ind, &Cap);
you can't read with "%e" into (addresses of) strings!
printf("%3d %6d %8e %8e", board, Res, Ind, Cap);
you can't print strings with "%e"
Also there are quite a few more problems with your code.
Just for a hint at coding style, take a look at the following code...
#include <stdio.h>
#include <stdlib.h>
int main( int argc, char **argv )
{
FILE *file;
int c, cp;
char *buf = (char*)malloc( sizeof( char ) * 100 );
for (c = 0; c < 100; c++ )
{
buf[c] = 0;
}
file = fopen( "input.txt", "r" );
cp = 0;
while( ( c = fgetc( file ) ) != EOF )
{
if ( c != ',' )
{
buf[cp] = (int)c;
cp++;
}
printf( "%c", c );
}
for (c = 0; c < 100; c++ )
{
printf( "Buf%d: %c\n", c, buf[c] );
}
free( buf );
return 0;
}
This code loads characters in from file. If you are wanting strings, consider simply that strings are arrays of characters... There are quite a few examples online you can look at including the following...
Read .CSV file in C
I hope this helps...
You may not combine a scanset format-specifier with other types of format-specifiers like that. Just like you may not have "%df" as a format-specifier for integer float (???), or "%si" for string integer (???), you may not have things like "%d[^,]".
"%d" alone would already abort reading when it encounters a ',' or any other non-digit character, so what you are trying to do there is extra and invalid precaution. Having that "[^,]" next to it, will cause sscanf to look for a '[' then '^' then ',' then ']' inside that string.
So, in short, you should rather be having something rather simple like the following:
#include<stdio.h>
int main( ){
int board;
float Res, Ind, Cap;
scanf( "%d,%f,%e,%e", &board, &Res, &Ind, &Cap );
// reads digit sequence until the non-digit input
// reads that number into board as an integer
// consumes a comma character
// and so on...
printf( "%d\n%f\n%e\n%e", board, Res, Ind, Cap );
return 0;
}
Addressing only:
...I've tried strtok ... but I seem to be doing something wrong....
And
This would have to be done multiple times (up to 40)
It sounds like you have an input file with a variable number of inputs, up to 40?
So the way the data is read should accommodate, and stop reading at end of data.
Here is an example doing these things using strtok():
With a file containing these values:
1.2,345,23,78,234,21.4567,2.45566,23,45,78,12,34,5.678
I also verified it works with exponential notation, such as:
1.2,345,23,7.8e3,2.34e-2,21.4567,2.45e-8,2.3e3,45,78,12,34,5.678
And using this code, strtok will parse through using ", \n" as delimiters:
#include <ansi_c.h>
int main(void)
{
FILE *fp;
char *tok;
double numbers[100];
char tempBuf[260], lineBuf[260];
int i=0;
memset(numbers, 0, sizeof(numbers)/sizeof(numbers[0])*sizeof(int));
fp = fopen("F:\\play3\\numbers.txt", "r");
while(fgets (lineBuf, sizeof(lineBuf), fp))
{
tok = strtok(lineBuf, ", \n");
while(tok)
{
strcpy(tempBuf, tok);
if(strlen(tempBuf)>0)
{
numbers[i++] = strtod(tempBuf, NULL);
}
tok = strtok(NULL, ", \n");
}
}
fclose(fp);
return 0;
}
With the following results:

Resources