I'm having a harsh time achieving this. I read a string of integer, extract them from that chain and put them in an array. I wanted to try something new because a used to read character by character with getChar in the past, but now I find sscanf which handle the job.
From Doc (sscanf) :
On success, the function returns the number of items in the argument list successfully filled. This count can match the expected number of items or be less (even zero) in the case of a matching failure.
In the case of an input failure before any data could be successfully interpreted, EOF is returned.
line : char line[] = "100 185 20 11 1000"; // number of int is unknown, it can differ
Problem: How to make diffrence between end of line and a whatever error
Eg: char line[] = "100 185 abc(not int) 11 1000";
Code :
int main(int argc, char** argv) {
char line[] = "100 185 20 11 1000";
int arrOfInt[10];
char *data = line;
int track, number, index = 0;
while ((sscanf(data, " %d%n", &number, &track)) == 1)
{
arrOfInt[index] = number;
data += track;
index++;
}
return 0;
}
#BLUEPIXY mentioned the correct answer. Just formalizing it here.
If the return value of scanf is EOF that means an EOF is seen. If it is 0 that means some other error has occurred and the value set via %n is undefined(eg. the input does not match the format specified).
The following approach works as long as there are no tokens with mixed alphabets and letter like "hey45hey2".
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char** argv) {
char line[] = "100 185 20 11 1000 sdf 342 hey45hey2";
int arrOfInt[10];
char *data = line;
int track, status = 0, number, index = 0;
// read until an EOF is found
while ((status = sscanf(data, " %d%n", &number, &track)) != EOF)
{
// store only if status is non-zero i.e. sscanf has read according to the format specified
if(status != 0){
arrOfInt[index] = number;
index++;
}
else
track=1;
data += track;
}
// print the array back to check if we read correctly
int i;
for(i=0;i<index;i++)
printf("%d ", arrOfInt[i]);
return 0;
}
The output of this code is:
100 185 20 11 1000 342 45 2
If you want to exclude strings like "hey45hey2" from the output, then use the following.
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char** argv) {
char line[] = " egsdfgfd rgege 100 185 20 11 hey45hey2 0d0 00 sddbrsdtbrtsdbrsf 342";
int arrOfInt[10];
char *data = line;
int track, status = 0, index = 0;
char str[100]; // will fail for tokens of length more than 100
// read until an EOF is found
while ((status = sscanf(data, "%s%n", str, &track)) != EOF)
{
// store only if status is non-zero
if(status != 0){
// check if str is all zeros
int num=(int)strtol(str,0,10);
char *i = str;
if(num == 0){
while(*i){
if(*i != '0') break;
i++;
}
}
if(*i == 0 || num != 0){
// if *i is zero, then num is also zero
arrOfInt[index] = num;
index++;
}
}
else
track = 1;
data += track;
}
// print the array back to check if we read correctly
int i;
for(i=0;i<index;i++)
printf("%d ", arrOfInt[i]);
return 0;
}
Output is 100 185 20 11 0 342
How to make diffrence between end of line and a whatever error
Sorry to say this, but the answer is: Drop sscanf, and do the parsing yourself.
If, for what ever reasons, you need/want to stick to sscanf you could always do a test on the "string" after sscanf is done, to see if there is more after the last token read, as you know the number of tokens parsed. You would do this for example by tokenizing the string beforehand using strtok on whitespaces, if you scanned in few, then you'd advance the string pointer behind the last+1 token and continue using sscanf. But is this sane? ;-)
I achieved what I really wanted to do by using your advice. Just to mention that when I find undesired character I have to leave my loop and show error.
Code(can be useful for others)
int main(int argc, char** argv) {
char line[] = "100 185 20 11 1000"; // or "100 185 abc 11 1000"
int arrOfInt[10];
char *data = line;
int track, number, index = 0;
int statutLine;
while ((statutLine = sscanf(data, " %d%n", &number, &track)) == 1)
{
arrOfInt[index] = number;
data += track;
index++;
}
if(statutLine == 0){
printf("Line invalide");
}
if(statutLine == EOF){
printf("Line valide");
}
return 0;
}
Related
So, I need to use the stdin to read a file that has two columns, the first one is a char, the second is an integer.
The input file is something like this:
i 10
i 20
i 30
i 40
i 50
i 45
r 48
My code currently:
int main(){
char line[MAX];
int n = 0;
while(fgets(line, MAX, stdin)){
printf("string is: %s\n",line);
}
return 0;
The output results in:
string is: i 10
string is: i 20
string is: i 30
string is: i 40
string is: i 50
string is: i 45
string is: r 48
So, what i need to do now is to assign an char array with the first column and an integer array with the second. Something like int V[size] = [10,20,30,40,50,45,48] and char W[size] = [i,i,i,i,i,i,r]. How can I do that?
Use sscanf() to parse the string and extract the data you want.
#include <stdio.h>
#include <stdlib.h>
#define MAX 500
int main(void)
{
int num[MAX] = {0}, lines = 0;
char line[MAX] = {0}, sym[MAX] = {0};
while (fgets(line, MAX, stdin))
{
if (lines >= MAX) /* alternative check comments */
{
fprintf(stderr, "arrays full\n");
break; /* break or exit */
}
if (sscanf(line, "%c %d", &sym[lines], &num[lines]) != 2) /* check return value for input error */
{
/* handle error */
exit(EXIT_FAILURE);
}
lines++;
}
for (int i = 0; i < lines; i++)
{
printf("char: %c | num: %d\n", sym[i], num[i]);
}
exit(EXIT_SUCCESS);
}
You may also use feof() and ferror() to determine if fgets() failed or you reached EOF .
QUESTION:
What is wrong with this code example, what is missing?
Current incorrect output is:
There are 0 words in ""
Code Explanation:
Write a program that reads in a line of text, and prints out the number of words in that line of text. A word contains characters that are alphanumeric. Hint: Use the fgets() function.
Sample run:
Input:
from here to eternity
Output:
4
Input:
start here and turn 180 degrees
Output:
6
Code Snippet:
https://onlinegdb.com/H1rBwB83V
#include <stdio.h>
#include <ctype.h>
#include <stdbool.h>
#include <string.h>
#define MAXLEN 100
int countWords(char str[])
{
int i=0;
int count = 0;
bool flag = false;
while (str[i] != '\0')
{
if (isalnum(str[i]))
{
if (!flag)
{
count++;
flag = true;
}
}
else
flag = false;
i++;
}
return count;
}
int main(int argc, char **argv) {
char str[MAXLEN];
int count;
while (fgets(str, sizeof(str), stdin) != NULL)
{
str[strlen(str-1)] = '\0'; // the last character is the newline. replace with null
count = countWords(str);
printf("There are %d words in \"%s\"\n", count, str);
}
return 0;
}
Similar Tutorial:
https://www.sanfoundry.com/c-program-count-words-in-sentence/
You have an error here:
str[strlen (str - 1)] = '\0'; // the last character is the newline. replace with null
Using the pointer str - 1 leads to undefined behavior, as it points to memory outside the original string.
You actually meant to do this: strlen(str) - 1 (notice the -1 is moved outside the parentheses)
I am able to read chars, words, sentences and integers from separate files but I am struggling to read words and integers from the same file. Let's say my file contains the following:
Patrice 95
Rio 96
Marcus 78
Wayne 69
Alex 67
Chris 100
Nemanja 78
My partial solution (to read in strings) so far was to use fgetc() and check for spaces and or carriage returns in my text file to separate the name from the number.
The main issue with fgetc is that it reads in character by character, and so integers are not meant to be read in like this. As a workaround, I am converting the character to an integer whenever a number is read in.
This is the main code structure:
typedef struct person {
char name[10][10];
char surname[10][10];
int age [10];
} person_t;
FILE *inp; /* pointer to input file */
char c;
int word_count = 0;
int char_count = 0;
int i = 0;
int x;
person_t my_person;
while ((c = fgetc(inp)) != EOF) {
if (c == ' ' || c == '\r') {
printf("\n");
my_person.name[word_count][char_count] = '\0'; //Terminate the string
char_count = 0; //Reset the counter.
word_count++;
}
else {
if (c >= '0' && c <= '9') {
x = c - '0'; //converting to int
my_person.age[i] = x;
printf("%d", my_person.age[i]);
i++;
}
else {
my_person.name[word_count][char_count] = c;
printf("%c",my_person.name[word_count][char_count]);
if (char_count < 19) {
char_count++;
}
else {
char_count = 0;
}
}
}
}
}
for (int i = 0; i<7; i++) {
printf("ages: %d \n",my_person.age[i] ); //never executes
}
Sample Output:
Patrice
95
Rio
96
Marcus
78
Wayne
69
Alex
67
Chris
Full code can be found on pastebin.
Why is the for loop never executing? Any suggestions on what I can improve to read the columns of strings and integers?
Use fgets() to read a whole line.
char line[100];
while (fgets(line, sizeof line, inp)) {
// got a line, need to isolate parts
}
Then, depending on whether the words can have embedded spaces choose one of the strategies below.
a) sscanf() to isolate name and age
while (fgets(line, sizeof line, inp)) {
char name[30];
int age;
if (sscanf(line, "%29s%d", name, &age) != 2) /* error, bad line */;
// ...
}
b) strrchr() to find the last space, then string manipulation to extract name and age.
while (fgets(line, sizeof line, inp)) {
char name[30];
int age;
char *space = strrchr(line, ' ');
if (!space) /* error, bad line */;
if (space - line >= 30) /* error, name too long */;
sprintf(name, "%.*s", space - line, line);
age = strtol(space, NULL, 10); // needs error checking
// ...
}
strategy b) on https://ideone.com/ZOLie9
How can I store a list of strings in an array in c. cause usually the a string e.g:'string' is stored as s|t|r|i|g in array(?). now if i have an array that has 10 index and want to store string in each one of those indexes, how do i do it? if not doable, what other data structure can i use for it.
e.g: array = 'string1'|'string2'|..
i have done something, but its not working:
// Array for name of alphabets, and name of states
35 char *nameOfStates[numStates];
36 char buffer[3];
37
38 // Read the nameOfStates
39 int i;
40 for(i=0;i<numStates;i++){
41 printf("Name of STATES:");
42
43 int z=0;
44 char *buffer2;
45 while(z<2 && fgets(buffer,2,stdin) != NULL){
46
47 buffer2 = strndup(buffer,2);
48 z++;
49 }// End while-loop
50 nameOfStates[i] = buffer2;
51
52 }// End of for-loop to read nameOfStates
EDIT: I realized that array[size] doesn't actually work! I did it cause of my java backgroun d and i thought it might work. so i changed the program but it still is throwing segmentation fault. I post the full(edited) program below:
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
// Function declaration
void analyze(char *string);
void clearNewLines(void);
int main(int argc, char *argv[]){
// Number of states and number of alphabets of DFA
int numStates;
int numAlphabets;
// Read numStates
printf("Enter the number of STATES:");
scanf("%d",&numStates);
// Flush STDIN
clearNewLines();
// Array for name of alphabets, and name of states
char **nameOfStates = malloc(numStates*sizeof(char*));
char *buffer = NULL;
// Read the nameOfStates
int i;
for(i=0;i<numStates;i++){
printf("Name of STATES:");
fgets(nameOfStates[i],2*sizeof(char),stdin);
}// End of for-loop to read nameOfStates
clearNewLines();
// Read numAlphabets
printf("Enter the number of ALPHABETS: ");
scanf("%d", &numAlphabets);
// Flush STDIN
clearNewLines();
// Array for name of alphabets, and name of states
char nameOfAlphabets[numAlphabets];
// Saving transition table
char *transitionTable[numStates][numAlphabets];
// Read name of alphabets
int j;
for(j=0;j<numAlphabets;j++){
printf("Name of ALPHABETS:");
nameOfAlphabets[j] = getchar();
// Flush STDIN
clearNewLines();
}// End for-loop to read alphabets
// Get the transitionTable[states][alphabets]
int row;
for(row=0;row<numStates;row++){
int col;
for(col=0;col<numAlphabets;col++){
printf("Enter Transition From %s to %c: ",nameOfStates[row],nameOfAlphabets[col]);
printf("\n");
}
}
return 0;
}// End of main function
/*
*
* clearNewLines - clear any newline character present at the STDIN
*/
void clearNewLines(void)
{
int c;
do
{
c = getchar();
} while (c != '\n' && c != EOF);
}
First: you cannot define an array size with a variable. I mean: char buf[variable]; doesn't work.
You have to do like this:
char **buf;
buf = malloc(sizeof(char) * number_of_strings);
if (buf == NULL)
return (MALLOC_ERROR);
Or with a macro like this:
// in your header file
#define BUF_SIZE 12
// in your .c file
char *buf[BUF_SIZE];
Then you also have to malloc the 2nd dimension of your array.
For example :
int i;
i = 0
while (buf[i])
{
buf[i] = malloc(sizeof(char) * string_length);
if (buf[i] == NULL)
return (MALLOC_ERROR);
i++;
}
And don't forget to free all dimensions of your array.
An array of arrays is the way to go.
// Array of size 5 (Don't forget to free!)
char **arrayOfStrings = malloc(5*sizeof(char*));
char *aString = "Hi";
arrayOfStrings[0] = aString;
//Literals work too
arrayOfStrings[1] = "Hallo";
aString = "Ahoy";
arrayOfStrings[2] = aString;
ArrayOfStrings values at end: Hi | Hallo | Ahoy | | |
I can have strings containing random 10 digit numbers e.g.
"abcgfg1234567890gfggf" or
"fgfghgh3215556890ddf" etc
basically any combination of 10 digits plus chars together in a string, so I need check the string to determine if a 10 digit number is present. I use strspn but it returns 0
char str_in[] = "abcgfg1234567890gfggf";
char cset[] = "1234567890";
int result;
result = strspn(str_in, cset); // returns 0 need it to return 10
The fact that the following code returns 0 instead of 10 highlights the problem. I asked this previously but most replies were for checking against a known 10 digit number. In my case the number will be random. Any better way than strspn?
It returns 0 because there are no digits at the start of the string.
The strspn() function calculates the length (in bytes) of the
initial segment of s which consists entirely of bytes in accept.
You need to skip non-digits - strcspn - and then call strspn on the string + that offset. You could try:
/* Count chars to skip. */
skip = strcspn(str_in, cset);
/* Measure all-digit portion. */
length = strspn(str_in + skip, cset)
EDIT
I should mention this must be done in a loop. For example if your string is "abcd123abcd1234567890" the first strspn will only match 3 characters and you need to look further.
Just use sscanf():
unsigned long long value;
const char *str_in = "abcgfg1234567890gfggf";
if(sscanf(str_in, "%*[^0-9]%uL", &value) == 1)
{
if(value >= 1000000000ull) /* Check that it's 10 digits. */
{
/* do magic here */
}
}
The above assumes that unsigned long long is large enough to hold a 10-digit decimal numbers, in practice this means it assumes that's a 64-bit type.
The %*[^0-9] conversion specifier tells sscanf() to ignore a bunch of initial characters that are not (decimal) digits, then convert an unsigned long long (%uL) directly after that. The trailing characters are ignored.
How about using a regex?
#include <stdio.h>
#include <stdlib.h>
#include <regex.h>
int
main(int argc, char **argv)
{
char str_in[] = "abcgfg1234567890gfggf";
int result = 0;
const char *pattern = "[0-9]{10}";
regex_t re;
char msg[256];
if (regcomp(&re, pattern, REG_EXTENDED|REG_NOSUB) != 0) {
perror("regcomp");
return(EXIT_FAILURE);
}
result = regexec(&re, str_in, (size_t)0, NULL, 0);
regfree(&re);
if (!result) {
printf("Regex got a match.\n");
} else if (result == REG_NOMATCH) {
printf("Regex got no match.\n");
} else {
regerror(result, &re, msg, sizeof(msg));
fprintf(stderr, "Regex match failed: %s\n", msg);
return(EXIT_FAILURE);
}
return(EXIT_SUCCESS);
}
strspn seems handy for this, but you would have to include it in a loop and search several times. Given the specific requirements, the easiest way is probably to make your own custom function.
int find_digits (const char* str, int n);
/* Searches [str] for a sequence of [n] adjacent digits.
Returns the index of the first valid substring containing such a sequence,
otherwise returns -1.
*/
#include <ctype.h>
int find_digits (const char* str, int n)
{
int result = -1;
int substr_len = 0;
int i = 0;
for(int i=0; str[i] != '\0'; i++)
{
if(isdigit(str[i]))
{
substr_len++;
}
else
{
substr_len=0;
}
if(substr_len == n)
{
result = i;
break;
}
}
return result;
}
(I just hacked this down here and now, not tested, but you get the idea. This is most likely the fastest algorithm for the task, that is, if performance matters at all)
Alternative use of sscanf()
(blatant variation of #unwind)
const char *str_in = "abcgfg0123456789gfggf";
int n1 = 0;
int n2 = 0;
// %*[^0-9] Scan any non-digits. Do not store result.
// %n Store number of characters read so far.
// %*[0-9] Scan digits. Do not store result.
sscanf(str_in, "%*[^0-9]%n%*[0-9]%n", &n1, &n2);
if (n2 == 0) return 0;
return n2 - n1;
Counts leading 0 characters as part of digit count.
Should one wish to avoid sscanf()
char str_in[] = "abcgfg1234567890gfggf";
const char *p1 = str_in;
while (*p1 && !isdigit(*p1)) p1++;
const char *p2 = p1;
while (isdigit(*p2)) p2++;
result = p2 - p1;
for testing a suit of "0123456789" inside a string you can do something like that:
int main()
{
char str_in[] = "abcgfg1234567890gfggf";
char cset[] = "1234567890";
int result;
int i;
int f;
i = 0;
f = 0;
while (str_in[i])
{
if (str_in[i] == cset[f])
{
f++;
if(f == strlen(cset))
return (f);
}
else
f = 0;
i++;
}
}