I'm reading:
22:5412:99:00 (...)
From a text file using (ch=fgetc(fp)) != EOF because I don't have only those numbers to read.
Identifying a number is easy with if(ch >= 48 && ch <= 57) but the thing is I want to put those numbers 22, 5412 into an array of integers. However when I read a char it reads part of number since each number is char.
It gets 2 (and not 22 like I want to) and in the next iteration reads the other 2. How can I save each set of numbers into it's own integer?
I hope I was clear enough, thanks!
My idea is to read in each char, and if it is a digit append it to a buffer. Whenever we get a non-digit, we just read the contents of the buffer as a string using sscanf, and clear the buffer for the next value.
#include <stdio.h>
#include <stdlib.h>
int read_buffer(char* buffer, int* sz)
{
int ret;
if (*sz==0) return 0;
buffer[*sz]='\0'; //end the string
sscanf(buffer,"%d", &ret); //read the contents into an int
*sz=0; // clear the buffer
return ret;
}
int main()
{
char buffer[1000];
int sz=0;
char ch;
FILE* input=fopen("input.txt","r");
// "input.txt" contains 22:5412:99:00
while ((ch=fgetc(input))!=EOF)
{
int number;
if (isdigit(ch))
{
buffer[sz++]=ch; // append to buffer
}
else
{
printf("Got %d\n",read_buffer(buffer,&sz)); // read contents of buffer and clear it
}
}
if (sz) // check if EOF occured while we were reading a number
printf("Got %d\n",read_buffer(buffer,&sz));
fclose(input);
return 0;
}
You would need to store the numbers as a string or a char* and use atoi to actually convert it to a number. http://www.cplusplus.com/reference/clibrary/cstdlib/atoi/
Assuming your pattern is of the type NN:NNNN:NN:NN, parse on the delimiter, feeding characters into a buffer:
int idx = 0, nIdx = 1;
int firstN, secondN, thirdN, fourthN;
char buf[5];
...
while ((ch=fgetc(fp)) != EOF) {
if (ch != ':') {
buf[idx++] = ch;
}
else {
buf[idx] = '\0';
idx = 0;
switch (nIdx++): {
case 1: firstN = atoi(buf); break;
case 2: secondN = atoi(buf); break;
case 3: thirdN = atoi(buf); break;
}
}
}
buf[idx] = '\0';
fourthN = atoi(buf);
...
I did a full program out of the previous post -- and some testing :-)
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
/* fill `array` with at most `siz` values read from the stream `fp` */
/* return the number of elements read */
size_t fillarray(int *array, size_t siz, FILE *fp) {
int ch;
size_t curr = 0;
int advance_index = 0;
while ((ch = fgetc(fp)) != EOF) {
if (isdigit((unsigned char)ch)) {
array[curr] *= 10;
array[curr] += ch - '0';
advance_index = 1;
} else {
if (advance_index) {
advance_index = 0;
curr++;
if (curr == siz) { /* array is full */
break;
}
}
}
}
return curr + advance_index;
}
int main(void) {
int array[1000] = {0};
int n, k;
n = fillarray(array, 1000, stdin);
if (n > 0) {
printf("%d values read:\n", n);
for (k=0; k<n; k++) {
printf(" %d", array[k]);
}
puts("");
} else {
fprintf(stderr, "no data read\n");
}
return 0;
}
And a test run
$ ./a.out
24555:76423 foobar 76235 jgfs(8) jhg x86-64 passw0rd RS232
[CTRL+D]
8 values read:
24555 76423 76235 8 86 64 0 232
Related
I have a char array, where should be only numbers (10 digits). If the user enters letters or special characters (even among those digits) the program should prompt the user again to enter the number.
I tried so many ways of doing it, but still couldn't find a way.
That's what I could do so far:
int f = 1;
int i = 0;
int flag =1;
char num[11];
printf("Enter a number: ");
while (f == 1) {
scanf("%10s", num);
while (flag == 1 && isdigit(num[i])) {
i++;
if (i == 10) {
f = 0;
flag =0;
}
}
if (!isdigit(num[i])) {
printf("Enter numerical char: ");
}
}
After I enter incorrect value it displays an empty line. If I put any value to that empty line, only then it says "Enter numerical char: " and prompts to enter the num again.
P.S. I know there is a way of ensuring that only numerical values entered, considering the fact that characters, unlike numbers are included in single quotes. (have no idea how to do this tbh)
Thanks in advance!
There are a couple of ways to do this.
The simple way is to use fgets to get a string.
Then, we can use strtol to decode the number [and we check the ending char for validity].
To do it completely manually, we can use isdigit in a loop, building up the number one digit at a time.
Here's some example code that is annotated and shows both ways:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <ctype.h>
#include <termios.h>
// getstr -- get a string with prompt
// RETURNS: length or (<0 -> error)
int
getstr(char *buf,int buflen,const char *prompt)
{
char *cp;
int ret = 0;
// decide if stdin is:
// (1) a TTY
// (2) a [redirected] file (e.g. invoked with ./myprogram < input)
static int echoflg = -1;
if (echoflg < 0) {
struct termios tio;
echoflg = (tcgetattr(fileno(stdin),&tio) < 0);
}
// NOTE: usage of the error codes in errno.h is arbitrary
while (ret <= 0) {
// ensure buffer has enough space
if (buflen < 2) {
ret = -ENOMEM;
break;
}
// output prompt
printf("%s: ",prompt);
fflush(stdout);
// get a line
cp = fgets(buf,buflen,stdin);
// EOF
if (cp == NULL) {
ret = -ENODATA;
break;
}
// echo file input to simulate TTY input
if (echoflg)
fputs(buf,stdout);
// get buffer length
ret = strlen(buf);
// empty string
if (ret <= 0)
continue;
// point to last char
cp = &buf[ret - 1];
// ensure we got a newline -- if not, fgets had to chop the line (i.e.)
// the line is too long to fit in the buffer
if (*cp != '\n') {
ret = -ENOSPC;
break;
}
// strip the newline -- we are done
*cp = 0;
--ret;
}
return ret;
}
// getnum_strtol -- get number using strtol
long
getnum_strtol(const char *prompt)
{
int len;
int readflg = 1;
char *cp;
char buf[100];
long num = 0;
while (readflg) {
len = getstr(buf,sizeof(buf),prompt);
if (len < 0)
exit(1);
num = strtol(buf,&cp,10);
// ensure we got a least one digit
if (cp <= buf)
continue;
switch (*cp) {
case ' ':
case '\t':
case 0:
readflg = 0;
break;
default:
printf("getnum_strtol: not a valid number -- buffer '%s', invalid '%s'\n",
buf,cp);
break;
}
}
return num;
}
// getnum_manual -- get number _not_ using strtol
long
getnum_manual(const char *prompt)
{
int len;
int readflg = 1;
int sign = 0;
int valid;
int chr;
char *cp;
char buf[100];
long num = 0;
while (readflg) {
len = getstr(buf,sizeof(buf),prompt);
// fatal error
if (len < 0)
exit(1);
// point to buffer start
cp = buf;
// find first non-whitespace character
valid = 0;
while (1) {
chr = *cp;
// end of string
if (chr == 0)
break;
// found character
valid = ((chr != ' ') && (chr != '\t'));
if (valid)
break;
++cp;
}
if (!valid)
continue;
// reset the accumlated number and the sign
num = 0;
sign = 0;
valid = 0;
// loop through all characters in buffer
while (1) {
chr = *cp++;
// get the sign of the number (and skip an explicit sign)
if (sign == 0) {
switch (chr) {
case '+':
sign = 1;
chr = *cp++;
break;
case '-':
sign = -1;
chr = *cp++;
break;
default:
sign = 1;
break;
}
}
// stop decoding number on whitespace
switch (chr) {
case ' ':
case '\t':
chr = 0;
break;
}
// check for clean end of number
if (chr == 0) {
if (valid) {
readflg = 0;
break;
}
}
// not a valid digit
if (!isdigit((unsigned char) chr)) {
cp -= 1;
printf("getnum_manual: not a valid number -- buffer '%s', invalid '%s'\n",
buf,cp);
break;
}
// add digit to number
num *= 10;
chr -= '0';
num += chr;
// we got at least one valid digit
valid = 1;
}
}
// apply sign
num *= sign;
return num;
}
int
main(int argc,char **argv)
{
char *cp;
int opt_s = 0;
long num;
// skip over program name
--argc;
++argv;
// get options
for (; argc > 0; --argc, ++argv) {
cp = *argv;
if (*cp != '-')
break;
cp += 2;
switch (cp[-1]) {
case 's': // use strtol
opt_s = !opt_s;
break;
}
}
while (1) {
if (opt_s)
num = getnum_strtol("Enter number [strtol]");
else
num = getnum_manual("Enter number [manual]");
printf("The number entered is: %ld\n",num);
if (num == 999)
break;
}
return 0;
}
Edit: Added code to replay/echo input from file.
Working with input from stdin in C can be a pain. I tried to explain what needs to be done in the comments while maintaining your variables in the manner in which you wanted them to be used. But I did need to add int ch to capture the input from stdin. The manner in which I captured input is FAR! from ideal but it illustrates the idea and does what you need it to do. But, to improve on your answer I'd suggest moving it into it's own function. Also, it ignores input of digits greater than 10 characters, so if for example you input 012345678901234567 it would just ignore the input beyond the 10th digit but still pass the test per your variables and flags. The comments should be self explanatory. I did not test this other than to make sure it compiled and once for digits and once for digits and text, but the idea is there, and you should be able to expand on it to match your requirements.
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h> /* for fflush */
int main()
{
int f = 1; /* set f on */
int i = 0;
int flag = 0; /* set flag OFF */
char num[11];
int ch; /* adding ch to read characters from stdin */
printf("Enter a number: "); /* flush stdout if no newline */
fflush(stdout);
while(f == 1) {
/* you need to read stdin to the newline */
/* but not exceed the bounds of num */
ch = fgetc(stdin);
while(ch != '\n' && ch != EOF) {
if(i < 10) /* reusing your i variable that you set to 0, don't exceed 10 to save space for '\0' */
num[i] = ch;
i++;
ch = fgetc(stdin); /* get another character */
}
/* now add '\0' to terminate your string */
/* but not beyond num[10] */
if(i > 10) {
num[10] = '\0';
} else {
num[i] = '\0';
}
/* now that we are done reading stdin reset i to 0 to restore how you had it */
i = 0;
/* lets test num working with your variables */
while(num[i] != '\0' && flag == 0) {
/* test for digit at num[i] */
if(!isdigit(num[i]))
flag = 1; /* not a digit so set your flag variable on */
i++;
}
/* process your flag variable */
if(flag == 0) { /* flag is off so everything is ok */
f = 0; /* turn f off to exit loop */
} else { /* flag is on, so get another number */
printf("Enter numerical char: "); /* flush stdout if no newline */
fflush(stdout);
flag = 0; /* turn your flag variable back off */
i = 0; /* reset i to 0 to check the next input */
}
}
/* let's see what we got in num */
printf("%s\n", num);
return 0;
}
So i need to get number from user and i want to check if the number is int:
char temp;
int num;
int res = scanf("%d%c", &num, &temp);
if (res == 2)
{
}
else
{
}
The problem is that even if the input is double for example 2.2 the if executed.
I also try this:
int n = atoi(&temp);
scanf is difficult to use if you want a very strict validation of the input typed by the user.
Instead you could you use getc to read the input char-by-char and do the validation and value calculation yourself.
Another approach could be fgets combined with sscanf. That could be something like:
#include <stdio.h>
#include <string.h>
#define MAX_LEN 8
int main(void) {
char str[MAX_LEN];
int d, n;
int flag = 0; // Assume it isn't an int
if (fgets(str, MAX_LEN, stdin)) // Read into str
{
size_t l = strlen(str);
if (l > 0) // Check that we did read something
{
if (str[l-1] == '\n') // Last char must be new line
{
if (sscanf(str,"%d%n", &d, &n) == 1) // Try to scan the str into an int
{
if (n == l-1) // Check that all chars was used
{
flag = 1; // It is an int so set the flag
}
}
}
}
}
if (flag)
{
printf("%d\n", d);
}
else
{
printf("Not an int\n");
}
return 0;
}
I am building a C program which gets a .txt file as an argument. Inside the .txt there are rows of integer numbers, with a space between them, like this:
1 2 3 4
5 6 7 8
...
I am supposed to find out, if a non-integer-character shows up inside the .txt file, like this:
1 2 a 4
...
Since there is no instanceof operator in C, I use an array which contains the numbers from 0-9 and check each character of the .txt-file, if it is either a space or an integer. If it is neither, the program is supposed to exit.
If there are no problems in the file, the program calculates a median and prints the line to stdout.
This is my code:
#include <stdio.h>
#include <ctype.h>
int arrayContains(char value);
int main(int argc, char **argv) {
const int LINESIZE = 255;
if (argc != 2) {
printf("wrong args!");
return -1;
}
char *command1 = argv[1];
FILE *handle = fopen(command1, "r");
if (!handle) {
printf("file not found!");
return -1;
}
int count = 0;
int sum = 0;
int median;
char string[LINESIZE];
while (fgets(string, LINESIZE, handle) != NULL) {
for (int i = 0; i <= sizeof(string) / sizeof(string[0]) - 1; i++) {
printf("%c", string[i]);
if (string[i] == ' ') {
i++;
}
else if (arrayContains(string[i]) == 0) {
count++;
sum += (int)string[i];
}
else {
printf("non-integer-character found!\n");
return -1;
}
}
median = sum / count;
printf("%s\n", string);
printf("%d\n", median);
}
}
int arrayContains(char value) {
const char numbers[10] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'};
for (int i = 0; i <= 9; i++) {
if (numbers[i] == value) {
return 0;
}
}
return -1;
}
Now the output of the program is always the first number of the txt-file and immediately after that: "non-integer-character found!".
Which tells me that the comparison between the element of the string from gets() and an element from the constant "numbers" array inside the arrayContains() function, will always result in a return of -1 from the arrayContains() function.
What am I doing wrong?
You should really check out isdigit C function!
#include <ctype.h>
int hasDigit(const char *s)
{
while (*s) {
if (isdigit(*s++) == 0) return 0;
}
return 1;
}
Code above returns 1 on empty string. Watch out! You can use my function instead of your arrayContains. If you want to use your routine, please check out my "version":
int arrayContains(char value) {
return isdigit(value)?0:-1;
}
There are several problems with your code.
This bit matches a space, but will result in you skipping the following character because your loop will also do i++.
if (string[i] == ' ') {
i++;
}
This is not the right way to turn a digit into a number. What you're getting here is the ASCII value of the character rather than the value of the digit. So for example if you have a '1' you're adding 49 to sum rather than 1.
sum += (int)string[i];
As discussed elsewhere, you're better off using isdigit() to identify if you've got a digit character. You can also use isspace() to test to see if you have a space or '\n' character (it covers all whitespace). Which would make your loop statement a lot less complicated as you can process the whole string and easily handle lines that are longer than the size of your buffer.
This code corrects the problems you have
while (fgets(string, LINESIZE, handle) != NULL) {
for (char *pos=string; *pos!='\0'; pos++) {
printf("%c", *pos);
if (isdigit(*pos)) {
count++;
sum += *pos-'0';
} elseif(!isspace(*pos)) {
printf("non-integer-character found!\n");
return -1;
}
}
median = sum / count;
printf("%s\n", string);
printf("%d\n", median);
}
I seem to have solved it:
#include <stdio.h>
#include <ctype.h>
int arrayContains(char value);
int main(int argc, char **argv) {
const int LINESIZE = 255;
if (argc != 2) {
printf("wrong args!");
return -1;
}
char *command1 = argv[1];
FILE *handle = fopen(command1, "r");
if (!handle) {
printf("file not found!");
return -1;
}
int count = 0;
int sum = 0;
int median;
char string[LINESIZE];
while (fgets(string, LINESIZE, handle) != NULL) {
for (int i = 0; i <= sizeof(string) / sizeof(string[0]) - 1; i++) {
printf("%c\n", string[i]);
if (isspace(string[i]) == 0) {
i++;
}
else if (isdigit(string[i]) == 0) {
count++;
sum += (int)string[i];
}
else {
printf("non-integer-character found!\n");
return -1;
}
}
fgets(string, LINESIZE, handle);
}
median = sum / count;
printf("%s\n", string);
printf("%d\n", median);
}
it now kinda does the job as expected.
You use the operator sizeof() which won't return the length of the String but the memory size of the pointer (a size_t so 8 bytes).
I suggest you to use this for your for loop:
for (int i = 0; string[i] != '\0' && string[i] != '\n'; i++) {
...
}
String in C are just a part of memory, it's just like an array and the only way to get the length is to find the end ('\0')
I also suggest you to directly search into the ASCII table. Characters are just number between 0 and 127. Digits are between 48 and 57, a simple condition does the stuff !
if (string[i] <= 48 || string[i] >= 57) {
...
}
Hi i have this text document
Now i want to store only the numbers in an array how can i do it in c language??
www.google.com *** 64
www.victoria.org **** 118
www.example.org *** 120
This should do it:
#include <stdio.h>
// read in up to 10 lines
int LINES[10];
int main(){
int current = 0;
// open file for reading
FILE* file;
file = fopen("file.txt", "r");
// read whole file one char at a time
while (1){
char ch;
if(!fread(&ch, 1, 1, file)){
break;
}
if (ch >= '0' && ch <= '9'){
int val = ch - '0';
LINES[current] *= 10;
LINES[current] += val;
}else if (ch == '\n'){
current += 1;
}
}
// Looping over the results
for (int i = 0; i <= current; i += 1){
printf("Line %d = %d\n", i, LINES[i]);
}
}
There are multiple ways you can do this.
One way is to read the numbers into a temporary char[] array one character at a time with fgetc, then convert it to an int with the use of atoi().
To test if characters are integers, you can use the isdigit function from <ctype.h>, or you can simply test ch >= '0' && ch <= '9', either way works.
Here is some sample code:
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#define NUMLINES 10
#define NUMLEN 5
int main(void) {
FILE *fp;
int LINES[NUMLINES], i, count = 0, ch, blen = 0;
/* static temp buffer, make it bigger if integers will be more than 5 digits */
/* dynamic memory allocation always possible here */
char buffer[NUMLEN+1];
/* opening the file, with error checking */
fp = fopen("urls.txt", "r");
if (!fp) {
fprintf(stderr, "%s\n", "Error reading file");
return 1;
}
/* read each character until EOF */
while ((ch = fgetc(fp)) != EOF) {
/* digit found. add to temp buffer */
if (isdigit(ch)) {
buffer[blen++] = ch;
}
/* stop adding to buffer, now convert and add to array */
if (ch == '\n') {
buffer[blen] = '\0';
LINES[count++] = atoi(buffer);
blen = 0;
}
}
/* print the array */
for (i = 0; i < count; i++) {
printf("LINES[%d] = %d\n", i, LINES[i]);
}
return 0;
}
Which should output:
LINES[0] = 64
LINES[1] = 118
LINES[2] = 120
For example, the user shall put the input like that, "ABC123," but not "ABC 123" or "A BC123."
Here is my code:
unsigned int convert_to_num(char * string) {
unsigned result = 0;
char ch;
//printf("check this one %s\n", string);
while(ch =*string++) result = result * 26 + ch - 'A' + 1;
return result;
}
int main()
{
char input_string[100];
char arr_col[100] = {'\0'};
char arr_row[100] = {'\0'};
int raiseflag;
int started_w_alpha =0;
int digitflag = 0;
while(scanf("%s", &input_string) != EOF) {
int i = 0, j = 0, digarr = 0;
while (i <=5) {
if (input_string[i] == '\0') {printf("space found!");}
if ((input_string[i] >= 'A' && input_string[i] <= 'Z') && (digitflag == 0)) {
started_w_alpha = 1;
arr_col[j] = input_string[i]; j++;
}
//printf("something wrong here %s and %d and j %d\n", arr_holder, i, j);
if (started_w_alpha == 1) {
if (input_string[i] >=48 && input_string[i]<=57){ digitflag = 1; arr_row[digarr] =input_string[i]; digarr++; }
}
i++; if (i == 5) { raiseflag =1; }
}
printf(" => [%d,%s]\n", convert_to_num(arr_col), arr_row);
if (raiseflag == 1) { raiseflag = 0; memset(arr_col, 0, 5); memset(input_string, 0, 5); memset(arr_row, 0, 5); digitflag = 0; started_w_alpha = 0; }
}
return 0;
}
Apparently, \0 doesn't work in my case because I have an array of 5 and user can put 2 chars. I want to exit the loop whenever a space is found in between the characters.
This is the whole code. I added {'\0'} my array because of the extra characters I get when there is less than 5 characters.
Thanks!
Since the index is starting from 0 and input_string[5]; array size is 5, the only valid indexes are from 0 to 4.
but your loop while (i <=5) { go till 5, it is mean you exceed the array.
If you insert 5 characters to the string, the terminating null is the 6th.
Since you exceed the array it written over some other variable. but you still can find it when you check input_string[5]
So if you want to insert 5 characters you array size should be at least 6
char input_string[6];
if you want to check only the first 5 elements you'll have to change the loop to:
while (i < 5) {
and as I wrote in the comment if you find the terminating null, no use to continue the loop, since it contain garbage or leftover from the previous iteration.
Therefor you should break if it found, like this:
if (input_string[i] == '\0') {printf("space found!"); break;}
EDIT
check this program: it use fgets to read the whole input, then search for white spaces.
Note it doesn't trim the input, means it won't remove spaces when thay appear at the beginning or at the end of the input.
#include <ctype.h>
#include <string.h>
#include <stdio.h>
int main()
{
int i ,size;
char input_string[100];
fgets(input_string,100,stdin);
i=0;
size = strlen(input_string);
while (i<size-1){ //enter is also count
if (isspace(input_string[i]))
{
printf("space found!");
break;
}
i++;
}
return 0;
}
EDIT2
Now with a trim, so it will remove leading and ending spaces:
#include <ctype.h>
#include <string.h>
#include <stdio.h>
char* trim(char *input_string)
{
int i=0;
char *retVal = input_string;
i = strlen(input_string)-1;
while( i>=0 && isspace(input_string[i]) ){
input_string[i] = 0;
i--;
}
i=0;
while(*retVal && isspace(retVal[0]) ){
retVal ++;
}
return retVal;
}
int main()
{
int i ,size;
char input_string[100],*ptr;
fgets(input_string,100,stdin);
ptr = trim(input_string);
i=0;
size = strlen(ptr);
while (i<size){
if (isspace(ptr[i]))
{
printf("space found!");
break;
}
i++;
}
return 0;
}