How to extract multi-digit numbers from a string? - c

Firstly, I know similar questions have been asked before but I believe my case is different.
My input string is:
(5,7) (1,6) (2,4) (10,14) (8,9)
I wrote the following code for extraction into an array.
main(){
char s[100];
int i=0,x,n=0;
int a[20];
printf("Enter the sets:");
gets(s);
x=strlen(s);
while(i<x){
if((s[i]=='(' && s[i+2]==',') || (s[i]==',' && s[i+2]==')'))
{
a[n]=s[i+1]-'0';
n++;
}
i++;
}
for(i=0;i<n;i++){
printf("%d\n",a[i]);
}
}
The output I get is:
5 7 1 6 2 4 8 9
I understand why my code will skip numbers having 2 or more digits.
Please suggest some minor changes to the present code to fix this limitation.
P.S.- I'm looking for a solution which doesn't depend on length of the number.

Since you only care about the numbers and not any of the delimiters, you can use strtok, which allows for a set of delimiters.
Use the following in place of you existing while loop:
char *p = strtok(s, "(), ");
while (p) {
a[n++] = atoi(p);
p = strtok(NULL, "(), ");
}
Output:
5
7
1
6
2
4
10
14
8
9
If on the other hand you are particular about the format, you can do the following:
char *start = s, *p1 = NULL, *p2 = NULL, *p3 = NULL;
if (start) p1 = strchr(start, '(');
if (p1) p2 = strchr(p1+1, ',');
if (p2) p3 = strchr(p2+1, ')');
while (p1 && p2 && p3) {
a[n++] = atoi(p1+1);
a[n++] = atoi(p2+1);
start = p3+1;
if (start) p1 = strchr(start, '(');
if (p1) p2 = strchr(p1+1, ',');
if (p2) p3 = strchr(p2+1, ')');
}

I have used a different approach to the problem, but I have solved it and it works. Consider trying this. Btw I have used char *s as a string literal but you can keep it like yours.
main(){
char *s="(5,7) (1,6) (2,4) (10,14) (8,9)";
int i=0,x,n=0;
char a[20];
x=strlen(s);
while(i<x){
if (isdigit(s[i])) {
a[n]=s[i];
if (s[i+1]==',' || s[i+1]==')') {
a[n+1]=' ';
n++;
}
n++;
}
i++;
}
printf("%s\n", a);
}
output:
tenshi#mashiro:~/projects/test$ ./test
5 7 1 6 2 4 10 14 8 9

#include <stdio.h>
int main(void) {
// your code goes here
char s[100];
int i=0,x,n=0;
int a[20];
printf("Enter the sets:");
gets(s);
x=strlen(s);
while(i<x-1){
if(isdigit(s[i]))
{
if(isdigit(s[i+1]))
{
a[n]=(s[i]-'0')*10 +(s[i+1]-'0');
i++;
}
else
{
a[n]=s[i]-'0';
}
n++;
}
i++;
}
printf("\n");
for(i=0;i<n;i++){
printf("%d\n",a[i]);
}
return 0;
}
What about the above code, unfortunately C doesn't have simple string functions like split with Regex(it has split function but i didn't understand well). Alternatively, here is ideone for it https://ideone.com/eRKTbD

If the input is in the exact format as in the question, then you can add two loops inside the main while loop to read one set at a time.
while (i < x)
{
if (s[i] == '(')
{
// temporary var to store number
int num = 0;
// read first number
while (s[++i] != ',')
num = num*10 + s[i]-'0';
a[n++] = num;
num = 0;
// read second number
while (s[++i] != ')')
num = num*10 + s[i]-'0';
a[n++] = num;
}
i++;
}

If you always have the same format (a,b)(c,d)...(y,z) and the same number of values then this solution works :
char * arr = "(5,7)(1,6)(2,4)(10,14)(8,9)";
int a,b,c,d,e,f,g,h,i,j;
sscanf(arr,"(%d,%d)(%d,%d)(%d,%d)(%d,%d)(%d,%d)",&a,&b,&c,&d,&e,&f,&g,&h,&i,&j);
printf("%d %d %d %d %d %d %d %d %d %d\n", a, b, c, d, e, f, g, h, i, j);

Related

I want to compare multiple strings using the strcmp and display the output after it succesfully verify both inputs

typedef struct uLogin
{
char user1,user2,user3,user4;
} uLogin;
void loginUser() {
uLogin x1;
int i, m, n;
char pass_list[20] = "12345678",name[10],pass[10];
x1.user1 = "DSET2G1";
x1.user2 = "DSET2G2";
x1.user3 = "DSET2G3";
x1.user4 = "DSET2G4";
printf("\nEnter username: ");
scanf("%s",&name);
fflush(stdout);
printf("\nEnter Password :");
scanf("%s",&pass);
fflush(stdout);
m = (strcmp(name,x1.user1)==0 && strcmp(name,x1.user2)==0 && strcmp(name,x1.user3)==0 && strcmp(name,x1.user4)==0);
n = strcmp(pass,pass_list);
if(m == 0 && n == 0)
{
system("CLS");
printf("Hello");
}
else
{
system("CLS");
printf("Bye");
}
}
Im trying to get this code to work but I dont understand why does the code terminates after typing the username and password for this simple user login page. Any ideas and can someone explain whats wrong? Sorry for bad english
the first thing that you should notice is that the member of your struct are just char, and you are trying to assign a full string to them. You should see that from the compiler warnings.
However, I saw several issues in your code and I provide here an improved version which should be more safe/stable in terms of memory corruption. Note that I used a fixed memory length for the strings, you can upgrade the code with dynamic memory but only if you know what you are doing.
See comments in the code for the description of the changes:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_USERNAME_LEN 256
// Change 1 -> Declare the member of the struct as pointers to char
typedef struct uLogin
{
char* user1,*user2,*user3,*user4;
} uLogin;
void loginUser() {
uLogin x1;
int i, m, n;
char pass_list[MAX_USERNAME_LEN] = "12345678";
char name[MAX_USERNAME_LEN],pass[MAX_USERNAME_LEN];
// Change 2: declare the stings as local variables,
//then assign the address of them to the struct members
char s1[MAX_USERNAME_LEN] = "DSET2G1";
char s2[MAX_USERNAME_LEN] = "DSET2G2";
char s3[MAX_USERNAME_LEN] = "DSET2G3";
char s4[MAX_USERNAME_LEN] = "DSET2G4";
x1.user1 = s1;
x1.user2 = s2;
x1.user3 = s3;
x1.user4 = s4;
// Change 3: use a safer way to read the input
// I leave the error handling to you
char line[MAX_USERNAME_LEN];
if (fgets(line, sizeof(line), stdin)) {
if (1 == sscanf(line, "%s", (char*)&name)) {
/* i can be safely used */
}
}
if (fgets(line, sizeof(line), stdin)) {
if (1 == sscanf(line, "%s", (char*)&pass)) {
/* i can be safely used */
}
}
// Change 4 - Use strncmp to compare exactly MAX_USERNAME_LEN bytes
// Change 5 - Fix the logic to have at least one combination right
int ret1 = strncmp(name,x1.user1,MAX_USERNAME_LEN)==0;
int ret2 = strncmp(name,x1.user2,MAX_USERNAME_LEN)==0;
int ret3 = strncmp(name,x1.user3,MAX_USERNAME_LEN)==0;
int ret4 = strncmp(name,x1.user4,MAX_USERNAME_LEN)==0;
m = ret1 || ret2 || ret3 || ret4;
n = strncmp(pass,pass_list,MAX_USERNAME_LEN) == 0;
printf("%d %d %d %d -> m %d n %d \n",ret1,ret2,ret3,ret4,m,n);
if(m == 1 && n == 1)
{
//system("CLS");
printf("Hello\n");
}
else
{
//system("CLS");
printf("Bye\n");
}
}
int main(){
while(1)
loginUser();
}
Some output samples:
DSET2G1
12345678
1 0 0 0 -> m 1 n 1
Hello
DSET2G1
fdgsfhjsdf
1 0 0 0 -> m 1 n 0
Bye
DSET2G6
12345678
0 0 0 0 -> m 0 n 1
Bye

GPS MODULE DATA - solution?

Here are the datas that we receive from GNSS module:
#include <stdio.h>
#include <stdlib.h>
//$GPGLL,,,,,,V,N*64
//$GaabL,,,,,,V,N*5D
char Received[] = { "Odetnij to jak mozesz$GaabL,,,,,,V,N*5D" };
int main(void)
{
int i = 0;
int b;
int c;
int super_atoi;
int wynik;
int xor = 0;
while (Received[i] != '$')
{
printf("%c", Received[i]);
i++;
}
i++;
printf("%c\n ");
while (Received[i] != '*')
{
printf("%c", Received[i]);
xor ^= Received[i];
i++;
}
printf("\n XOR = %d", xor);
printf("\n XOR w hex = %#02x ", xor);
printf("\n XOR w dec = %d ", xor);
if (Received[i] == '*')
{
i++;
b = Received[i];
printf("\n 1 znak w kodzie za * = %c", b);
i++;
c = Received[i];
printf("\n 2 znak w kodzie za * = %c", c);
}
char a[3] = { b, c };
super_atoi = atoi(a);
super_atoi = strtol(a, NULL, 16);
printf("\n ATOI = %s ", a, super_atoi);
if (xor == super_atoi)
{
printf("%c\n ");
printf("\n WORKING!");
}
else
{
printf("%c\n ");
printf("\n not working");
}
return 0;
}
To count the sumcheck of each we've got to xor char's between "$" and "*". My program for that is:
DEMO
Basically we check each char if its "$" then xor elements till we receive *.
However i've small problem... I need to check every single line of data - NEO-7 transmit pack of [280]+ chars each certain period of time, which include 11"$: and 11 *. There are two ways of checking everything that i can think of:
Checking every single byte (char), start counting when "$" appears, finishes when * appears, compare the results with 2 elements after "*".
(More suitable for my program) Receive array[35] from GPS module, create seperate array in which i will include what's left from previous sumcheck, put next pack of data that arrives from GPS, repeat. Could you please tell me what's better? also How to create these solutions?

How to split a string into int[3]

I have a string, like "101 1 13" and I need to split it to a int aux[3] --> resulting in aux[0] = 101, aux[1] = 1 and aux[2] = 13 (in this case). How can
I do that?
In the example of the code below I get op as a String and want to get the value of the INTs in there. Each int is divided in the string by a white space(" ").
Another detail: I need the code to compile with flag -std=c99, so the answer that was accepted would not work.
#include <stdio.h>
#include <stdlib.h>
//example of str = "101 1 14" (char *)
// example of output = {101, 1, 14}(int *)
int* stoi(char *str) {
// function to split str into 3 ints
}
int main() {
char op[10];
int num[3];
scanf("%s\n", op);
num = stoi(op);
printf("%d %d %d", num[0], num[1], num[2]);
return 0;
}
First you need to tokenize your input (break apart the input into distinct elements). Then you need to parse/integerize the individual tokens by converting them from strings to the desired format.
Sample Code
#include <stdio.h>
#include <string.h>
#define BUF_LEN (64)
int main(void)
{
char buf[BUF_LEN] = { 0 };
char* rest = buf;
char* token;
int i = 0;
int iArr[100] = { 0 };
if ( fgets(buf, BUF_LEN, stdin) != NULL )
{
strtok(buf, "\n"); // Remove newline from input buffer in case we want to call fgets() again.
while ( (token = strtok_r(rest, " ", &rest)) != NULL )
{
iArr[i] = strtol(token, NULL, 10);
printf("Token %d:[%d].\n", i, iArr[i]);
i++;
}
}
return 0;
}
Sample Run
1231 12312 312 1232 1312
Token 0:[1231].
Token 1:[12312].
Token 2:[312].
Token 3:[1232].
Token 4:[1312].
Try to replace your code by following code.
The new code works only if input contains only single space between integers.
Your code:
while(op[cont] != '\0') {
for(i = 0; op[cont] != ' '; i++, cont++) {
num[i] += op[cont];
}
printf("num[i] = %d\n", num[i]);
}
New code:
while(op[cont] != '\0')
{
if(op[cont] != ' ')
num[i] = num[i]*10 + (op[cont]- '0');
else
i++;
cont++;
}
See this example of how to do that:
char string [10] = "101 1 666"
int v [3], n=0, j=0;
int tam = strlen(string);
int current_Len = 0;
for(i=0; i<tam; i++){
//32 = ascii for White space
if(string[i] != 32){
n = n*10 + string[i] - '0';
current_len++;
} else if (current_len > 0){
v[j++] = n;
current_len = 0;
n=0;
}
}
if (current_len > 0){
v[j++] = n;
}
This answer is assuming you know how much integers your string contain at the time of writing your code. It also uses specific clang/gcc extension (typeof) and may not be portable. But it may be helpful to someone (I mainly wrote it because I had nothing good to do).
#include <stdio.h>
#include <string.h>
struct {int _[3];} strToInt3(const char (*pStr)[])
{
int result[3] = {0}, *pr = result;
for(register const char *p = *pStr; *p; ++p)
{
if(*p == ' ') ++pr;
else
*pr *= 10,
*pr += *p - '0';
}
return *(__typeof__(strToInt3(0)) *)result;
}
int main()
{
char op[10];
int num[3];
scanf("%10[^\n]", op),
//memcpy(num, strToInt3(op)._, sizeof(num));
//or
*(__typeof__(strToInt3(0)) *)num = strToInt3(op);
printf("%d %d %d", num[0], num[1], num[2]);
}
I've commented the copying of returned array using memcpy and added a structure assignment. Although both must be valid (not standard I guess but working in most cases) I prefer the second option (and maybe some compiler optimizers will).
Also I assume ASCII character set for chars.
I found an easier approach to the problem. I insert a scanf, that don't catch the space blanket and convert it using atoi. As it is just 3 ints it doesn't become so bad to use this simple, repetitive way of catching the values. And it work with the -std=c99 flag, that I needed to use.
scanf("%s[^ ]\n", op);
num[0] = atoi(op);
scanf("%s[^ ]\n", op);
num[1] = atoi(op);
scanf("%s[^ ]\n", op);
num[2] = atoi(op);
printf("%d\n", num[0]);
printf("%d\n", num[1]);
printf("%d\n", num[2]);

How to read 2 lines of integer input in C?

I'm doing a project for my algorithms class and I'm having a lot of trouble with inputs. I'm trying to read an input like this:
6 0 2 3 1 3
5 9 2 1 3
The integers will need to go to
int num1; // num1 = 6
int num2; // num2 = 5
int array1[100]; // array1 = {0, 2, 3, 1, 3, 0, 0, ...}
int array2[100]; // array2 = {9, 2, 1, 3, 0, 0, ...}
The input will come from standard input, in the form of a file. So in terminal running the program would look like this:
cat input.txt | ./a.out
Where input.txt contains the two lines of integers.
Here is my flawed attempt so far:
while(scanf("%d%c", &temp, &ch) > 1){
if (ch != '\n'){
one[count] = temp;
}
else if (ch == '\n'){
count = 0;
two[count] = temp;
}
one[count] = temp;
count++;
if (ch != ' ')
{
printf("Invalid input. Please do int + space.\n");
return -1;
}
if ((temp >= 100) || (temp <= -100))
{
printf("Input is too big, must be between -100, 100.\n");
return -1;
}
if (one[0] < 1){
printf("Input for n cannot be smaller than one!");
return -1;
}
}
I think the main issue is that I'm just not sure how to deal with multiple lines of input. One line of input is fine by me but multiple lines is what trips me over.
You could fetch an entire line of input using the getline function and then iterate over that line, scanning one number at a time using the strtol function.
From the example in your question I assume that you want all remaining entries in the two arrays to be zero so don't forget to zero them out (either manually or using the memset function.).
And also don't forget to free() the buffer getline gave you.
Actually I ended up using scanf, here is the working code below. It really helped to read some of these comments and also refer to K&R
#include <stdio.h>
#include <string.h>
#define ARRAY_SIZE 100
void shiftArrayBackByOne(int a[]){
for(int i = 1; i <= ARRAY_SIZE; i++){
a[i - 1] = a[i];
}
}
void printArray(int a[], int n){
for(int i = 0; i < n; i++){
printf("%d ", a[i]);
}
putchar('\n');
}
int main(){
int isLineTwo = 0;
int countOne = 0;
int countTwo = 0;
int inputNum;
int num1;
int num2;
int array1[ARRAY_SIZE];
int array2[ARRAY_SIZE];
char ch;
while(scanf("%d%c", &inputNum, &ch) > 0){
//Puts the input into different arrays depeding
//on value of isLineTwo
if (isLineTwo){
array2[countOne] = inputNum;
countOne++;
} else {
array1[countTwo] = inputNum;
countTwo++;
}
//Increment isLineTwo if ch is a 'newline'
if (ch == '\n')
{
isLineTwo++;
}
//Check if user inputs more than 2 lines
if (isLineTwo > 1){
printf("Hey, no more than 2 input lines!\n");
}
}
printArray(array1, countOne);
printArray(array2, countTwo);
num1 = array1[0];
num2 = array2[0];
shiftArrayBackByOne(array1);
shiftArrayBackByOne(array2);
printf("num1 = %d\n", num1);
printf("num2 = %d\n", num2);
printArray(array1, countOne);
printArray(array2, countTwo);
}
Look at my code below. Maybe it helps you.
Generally, if you know how many numbers will be inputted, you can read numbers one by one using scanf("%d", ...) and use fflush() when the expected amount is met to clear any other numbers in the buffer. This example assumes that the first two numbers are the respective lengths of each line. The input could look like:
// example input:
// 4
// 3
// 1 2 3 4
// 5 6 7
int main()
{
int it;
int it1 = 0;
int it2 = 0;
int line1[100];
int line2[100];
scanf("%d", &it1); // amount of line 1 numbers
scanf("%d", &it2); // amount of line 2 numbers
it = 0;
do
{
scanf("%d", &line1[it]);
} while (++it < it1);
fflush(stdin); // clear input buffer
it = 0;
do
{
scanf("%d", &line2[it]);
} while (++it < it2);
return 0;
}

How to read numbers separated by space using scanf

I want to read numbers(integer type) separated by spaces using scanf() function.
I have read the following:
C, reading multiple numbers from single input line (scanf?)
how to read scanf with spaces
It doesn't help me much.
How can I read numbers with space as delimiter. For e.g. I have following numbers as input 2 5 7 4 3 8 18 now I want to store these in different variables.
Please help.
I think by default values read by scanf with space/enter. Well you can provide space between '%d' if you are printing integers. Also same for other cases.
scanf("%d %d %d", &var1, &var2, &var3);
Similarly if you want to read comma separated values use :
scanf("%d,%d,%d", &var1, &var2, &var3);
scanf uses any whitespace as a delimiter, so if you just say scanf("%d", &var) it will skip any whitespace and then read an integer (digits up to the next non-digit) and nothing more.
Note that whitespace is any whitespace -- spaces, tabs, newlines, or carriage returns. Any of those are whitespace and any one or more of them will serve to delimit successive integers.
int main()
{
char string[200];
int g,a,i,G[20],A[20],met;
gets(string);
g=convert_input(G,string);
for(i=0;i<=g;i++)
printf("\n%d>>%d",i,G[i]);
return 0;
}
int convert_input(int K[],char string[200])
{
int j=0,i=0,temp=0;
while(string[i]!='\0')
{
temp=0;
while(string[i]!=' ' && string[i]!='\0')
temp=temp*10 + (string[i++]-'0') ;
if(string[i]==' ')
i++;
K[j++]=temp;
}
return j-1;
}
It should be as simple as using a list of receiving variables:
scanf("%i %i %i", &var1, &var2, &var3);
With this solution, it's possible to read positive and negatives integers:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define BUFFER_SIZE 50
int convert_input (int * v, char * buffer) {
int len = 0, i = 0, temp = 0, positive_or_negative_one = 1;
while(buffer[i]!='\0') {
temp = 0;
if (buffer[i] == '-'){
positive_or_negative_one = -1;
i++;
} else {
while(buffer[i] != ' ' && buffer[i] != '\0')
temp = temp*10 + (buffer[i++]-'0');
if(buffer[i]==' ')
i++;
v[len++] = temp * positive_or_negative_one;
positive_or_negative_one = 1;
}
}
return len;
}
int main(int argc, char const *argv[]) {
int *a = NULL;
int count_a, len=0;
char buffer[BUFFER_SIZE];
printf("Input numbers here: ");
gets(buffer);
for (int i = 0; i < strlen(buffer); i++) {
if (buffer[i] == ' '){
len+=1;
}
}
a = (int*) malloc(sizeof(int) * len + 1);
count_a = convert_input(a, buffer);
for (int i = 0; i < count_a; i++) {
printf("%d\n", a[i]);
}
free(a);
return 0;
}
Input and output example:
Input numbers here: 1 2 3 -4 10
1
2
3
-4
10

Resources