Scanf for reading string and int array in brackets - c

I've been trying to come up with solution for reading input which contains string and then brackets with array of numbers (I don't know how many numbers will be inputed.
Input could look like:
sacrifice (1, 2, 4, 2)
I am wondering if it is possible to achieve with scanf. I've been looking for different functions such as getline, sscanf, fgets and so on. But I couldn't come up with solution.
My code looks like this:
scanf("%[^(]", command);
while ( ( c = getchar() ) != ')' )
{
scanf("%d", weights[pos]);
pos++;
}
Which should read string until the bracket is found and then I tried to load the numbers in array as long as it doesn't reach the ')'. Yet it doesn't seem to work.
Is scanf viable to achieve this? Could anyone point me in better direction if not please?

I think it would be simpler to read the complete line from stdin and then parse it by hand using strtok or strcspn. Something like below could be done.
Disclaimer: This is just some sample code and doesn't handle all possible inputs and will crash with invalid input, it is just to give you an idea about how to do it. If you want to go this way, you would have to handle various error conditions, such as:
checking return value of malloc/getline/realloc
instead of atoi using a better function like strtol (which allows error checking),
handling white spaces in the input and
handling input which does not contain any parenthesis
Those are some of the many things which you would have to think about.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static int *parse_numbers(char *numstr, size_t *size)
{
char *p;
char *s = numstr;
char *last;
size_t array_size = 10;
int *numbers = malloc(sizeof(int) * array_size);
size_t offset = 0;
for (p = strtok_r(s, ",", &last); p; p = strtok_r(NULL, ",", &last)) {
if (offset == array_size) {
array_size *= 2;
numbers = realloc(numbers, sizeof(int) * array_size);
//TODO do error check
}
numbers[offset++] = atoi(p); //strtol would be a better choice
}
*size = offset;
return numbers;
}
int main()
{
char *s = NULL;
char *p;
char *last;
int i = 0;
int *numbers;
size_t size;
size_t linesize = 0;
getline(&s, &linesize, stdin);
for (p = strtok_r(s, "(", &last); p; p = strtok_r(NULL, "(", &last)) {
if (i++ == 0) {
//This is the part of the string before '('
cmd = p;
} else {
// This is the part of the string after '('
numbers = parse_numbers(p, &size);
}
}
for (i = 0; i < size; i++) {
printf("%d\n", numbers[i]);
}
free(numbers);
free(s);
return 0;
}

Separate input from parsing. Far easier to handle the various issues of command processing. Concerning "don't know how many numbers will be inputed", IMO, a reasonable upper bound should be established. Else code is susceptible to overwhelming memory resources due to user input - a hacker exploit.
char command[1000];
while (fgets(command, sizeof command, stdin)) {
Now process the command using sscanf(), strtok() or your own code. The best method depends on maybe things not posted by OP, especially error handling.
int cmd_start;
int cmd_end;
int n = 0;
// sacrifice (1, 2, 4, 2, ...)
// +----------------- skip optional white space
// |+---------------- record scan position
// || +-------------- scan, but not save, lower case letters
// || | +------- record scan position
// || | | +----- skip optional white space
// || | | |+---- scan (
// || | | ||+--- skip optional white space
// || | | |||+-- record scan position
sscanf(command, " %n%*[a-z]%n ( %n", &cmd_start, &cmd_end, &n);
if (n == 0) {
printf("Invalid command '%s'\n", command);
continue;
}
int x[sizeof command / 2];
int x_count = 0;
char *p = &command[n]; // pick up where previous scan ended.
char sep[2] = {0};
while (sscanf(p, "%d %1[,)] %n", &x[x_count], sep, &n) == 2) {
x_count++;
p += n;
if (sep[0] == ')') break;
}
if (*p || sep[0] != ')') {
printf("Invalid separator '%s'\n", command);
continue;
}
// Use command
command[cmd_end] = '\0';
Process_Command(&command[cmd_start], x, x_count);
}

scanf("%d", weights[pos]); --> scanf("%d", &weights[pos]); – BLUEPIXY
That's indeed adequate to make the code work, provided a sufficiently dimensioned weights array.

Related

Read an input that is separated by spaces, parenthesis, and commas with scanf() and fgets()

I have the following input:
1 (2 ,3 ,4) lantern
The number of int inputs between the parenthesis is unknown, and could extend for a while.
My original thought was to scanf() the first int, then create a while loop to determine when the closed paranethsis is scanned. Then finally use fgets() to get the string at the end, something similar to this.
scanf("%d", &address); //first input
scanf("%c", &paren); //scan the '(' or ',' or ')'
int current_room = 0; //index for array inside parenthsis
while(paren == '(' || paren == ','){
scanf("%d,", adjoined_room[current_room]); //scan am int
scanf("%c", &paren); //scan a ',' or ')'
current_room++; //increase the index
}
This however prints the following output when I print my address, array, and string:
Address: 1
Item: (2 ,3 ,4) lantern
The inputted ints between the parenthesis were never set to the array. Is there a better way to determine when ')' is inputted?
The problem is that scanf("%c", will read the very next character in the input, without skipping any whitespace. If you want to skip whitespace, you need a space in the format, eg scanf(" %c",. You should also check the scanf return value to make sure that you got an integer
Adding that to your code gives you something like:
if (scanf("%d", &address) != 1) { //first input
fprintf(stderr, "syntax error\n");
return; // not an integer -- do something else
}
scanf(" %c", &paren); //scan the '(' or ',' or ')'
int current_room = 0; //index for array inside parenthsis
while(paren == '(' || paren == ','){
if (scanf("%d", adjoined_room[current_room]) == 1) { //scan an int
current_room++; //increase the index
}
scanf(" %c", &paren); //scan a ',' or ')'
if (paren != ',' && paren != ')') {
fprintf(stderr, "syntax error\m");
return;
}
}
If you want to do this with interactive input, you should probably use fgets or getline to read entire lines and sscanf to parse each line independently so you don't confuse your user when there's an error in the middle of a line. The "read line + sscanf" is also very useful if you have a number of different patterns that you want to try (sscanf on the same line with different formats to find the first one that matches).
scanf should never be used. Ever. But....you might try something like:
#include <err.h>
#include <stdio.h>
#include <stdlib.h>
void * xrealloc(void *buf, size_t num, size_t siz);
int
main(void)
{
size_t cap = 4;
char buf[1024];
int *x = xrealloc(NULL, cap, sizeof *x);
if( scanf("%d ( %d", x, x + 1) != 2 ){
errx(EXIT_FAILURE, "Ivalid input");
}
int *y = x + 2;
while( scanf(",%d", y) == 1 ){
if( ++y == x + cap ){
cap += 4;
x = xrealloc(x, cap, sizeof *x);
}
}
if( scanf(")%1023s", buf) != 1 ){
errx(EXIT_FAILURE, "Ivalid input");
}
for( unsigned i = 0; i < y - x; i += 1 ){
printf("x[%d] = %d\n", i, x[i]);
}
printf("%s\n", buf);
return 0;
}
void *
xrealloc(void *buf, size_t num, size_t siz)
{
char *b = buf;
b = realloc(b, num * siz);
if( b == NULL ){
perror("realloc");
exit(EXIT_FAILURE);
}
return b;
}
This does not correctly handle input with a trailing comma like: 1 (2 ,3 ,4, ) lantern, and I'm sure there are many other inputs that it does not like. Exercise left for the reader.
You probably don't want to use an initial capacity as small as 4, but it's convenient for simple testing.
This may not be the most popular answer, and it may or may not help your immediate goals, but I am of the philosophy to read input as a stream of bytes and parse via (crude or sophisticated) state machine:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define process_word(x) (printf("Got string \'%s\'\n", x))
#define process_number(x) (printf("Got number %lu\n", strtoul(x, NULL, 10)))
int main(void) {
int c;
int depth = 0;
size_t i;
char digitbuffer[256];
char alphabuffer[256];
while ((c = fgetc(stdin)) != EOF) {
switch (c) {
case ' ':
case ',':
break;
case '(':
depth++;
break;
case ')':
if (depth == 0) perror("Mismatched parenthesis, skipping");
else depth--;
break;
default:
if (isalpha(c)) {
memset(alphabuffer, 0, 256);
alphabuffer[0] = c;
i = 1;
while ((c = fgetc(stdin)) != EOF &&
isalpha(c) &&
i < 255) {
alphabuffer[i++] = c;
}
if (!isalpha(c) && c != EOF) ungetc(c, stdin);
process_word(alphabuffer);
}
else if (isdigit(c)) {
memset(digitbuffer, 0, 256);
digitbuffer[0] = c;
i = 1;
while ((c = fgetc(stdin)) != EOF &&
isdigit(c) &&
i < 255) {
digitbuffer[i++] = c;
}
if (!isdigit(c) && c != EOF) ungetc(c, stdin);
process_number(digitbuffer);
}
break;
}
}
return 0;
}
This gives you the most control over handling your specific data format, in my opinion.
You can define your own process_word() and process_number() functions, of course. process_number() might assign the number to the address field of a record if depth == 0, for example, or add it to adjacent_room[] if depth == 1. process_word() might add the string to the item field of the same record. Completely up to you. ¯\_(ツ)_/¯

C Programming: Counting word length occurences in a string

How would you be able to count word lengths and output their occurrences from a string using gets() or fgets()? For example, here is code doing so but using getchar()below. I think writing it in gets() would make it easier to incorporate all of the delimiters in the program rather than having to manually set if statements for each one of those would it not?
#include <string.h>
#include <ctype.h>
const char delim[] = ", . - !*()&^%$##<> ? []{}\\ / \"";
#define SIZE 100
int main(void){
int length[SIZE] = { 0 };
int name[SIZE];
int i = 0, ch, word_len = 0;
int count = 0;
printf("enter sentence: ");
while (1){
ch = getchar();
if (isalpha(ch)){
++word_len;
}
else if (ch == ' ' || ch == '.'){
if (word_len)
length[word_len - 1]++;//-1: to 0 origin
if (ch == '.')
break;
word_len = 0;
}
}
printf("Word Length \tCount \n");
for (i = 0; i<sizeof(length) / sizeof(*length); ++i){
if (length[i])
printf(" %d \t\t%d\n", i + 1, length[i]);
}
return 0;
}
You can build your custom delimiter detection function.
// globals
const char *delim = " .,;:!?\n\0";
const int n_delim = 9;
int is_delim(int c)
{
register int i;
for (i = 0; i < n_delim; i++)
if (c == delim[i]) return 1;
return 0;
}
This function will return 1 every time it can match c with delim. So you can use it like this:
fgets(buffer, 200, stdin);
for (i = 0; i < strlen(buffer); i++) {
if (is_delim(buffer[i])) {
wl[words++] = length;
length = 0;
continue;
}
length++;
}
I'm assuming you're familiar with the fgets function.
You basically will loop through your buffer, making comparisons with each character. Every loop iteration you check if the current character is a word delimiter, if it is, you save the current length and set length=0 for a new word, and at every iteration you increment the length.
You'll need to come up with a way of either not inserting the zero length values due to double delimiters or just ignore them when you're printing the results.
Basically you want to split a string into words, based on some delimiters, and compute their length. The C standard library provides the strtok function, which does exactly what you need: it splits the given string into multiple tokens.

Using Scanf to read in an equation of random length

I am trying to read in an equation, then take each part separately, however then user can enter as big or small equation as they like (for example. 3+7, 2+-9+8 or even 2). I have this however it doesn't seem to be working.
printf("Please enter an equation\n");
scanf("%f", &num);
//printf("%f", num);
while ( num != '\n'){
scanf("%f", &num);
scanf("%c", &op);
//printf("%c %f \n", op, num);
}
when i output what i have got it is not the same as the input.
You may wish to read How to read a line from the console in C? for the full details, but basically you just do this:
char * getline(void) {
char * line = malloc(100), * linep = line;
size_t lenmax = 100, len = lenmax;
int c;
if(line == NULL)
return NULL;
for(;;) {
c = fgetc(stdin);
if(c == EOF)
break;
if(--len == 0) {
len = lenmax;
char * linen = realloc(linep, lenmax *= 2);
if(linen == NULL) {
free(linep);
return NULL;
}
line = linen + (line - linep);
linep = linen;
}
if((*line++ = c) == '\n')
break;
}
*line = '\0';
return linep;
}
You are trying to take the complete expression in a float variable (num, in your code). If you do a scanf("%f", &num); in while loop then you are just overwriting the values in num. You need to take the expression in a char array or char*. Then you need to have an algrithm to seperate the operators and numbers, convert the numbers to desired type and solve the euation.
If you want to read an expression and have your program understand that, you need severely heavier machinery. Either this is an XY problem, i.e., you need to rethink the problem and find another approach; or you should look into the whole parsing/compiling area.
Scripting languages (like Python or Perl) have some sort of eval builtin, so you can take a snippet of code as text and get it evaluated (run). Perhaps using one of those is a better match to your problem? But take care, blindly running anything the user inputs is a huge risk...
To read an arbitrary-length line with scanf, you can use
scanf("%[^\n]", equation);
This regular expression means "read everything until you find the '\n' character".
Keep in mind that this is not secure though, since the user can easily overflow the "equation" buffer. If you want to avoid that, I would suggest reading char by char in a loop, like so:
for(i=0; i < MAX_EQ_SIZE; i++)
{
char tmp;
scanf("%c", &tmp);
if(tmp == '\n')
break;
equation[i] = tmp;
}
Since you are asking just how to read, I'm not going into parsing the read equation.
Here is a code example:
#include <stdio.h>
#define MAX_EQ_SIZE 1024
void parse(char * eq)
{
// Do the processing
}
int main()
{
char equation[MAX_EQ_SIZE];
scanf("%[^\n]", equation); // Read a whole line
scanf("%*c"); // Read and ignore the \n
puts(equation);
parse(equation);
}
Use fgets() to read the line of input.
Use the return value from sscanf() to determine if number or operator.
int Eval(void) {
char buffer[100];
char *p = buffer;
printf("Please enter an equation\n");
if (fgets(buffer, sizeof buffer, stdin) == NULL)
return -1; // no more input
float num;
char op;
int n;
while (*p) {
if (sscanf(p, "%f %n", &num, &n) == 1) {
printf("num %f\n", num);
p += n;
}
if (sscanf(p, " %c %n", &op, &n) == 1) {
printf("op %c\n", op);
p += n;
} else if (*p) {
printf("Error '%s'\n", p);
return 0;
}
}
return 1;
}

Error in C executable file

My program is up to date and works fine when I am running on Turbo C.
Once I compile and run the program, executable file gets created.
When I run executable file it should work, but for following program it always gives "false" answer.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *BoyerMoore( unsigned char *data, unsigned int dataLength, unsigned char *string, unsigned int strLength )
{
unsigned int skipTable[256], i;
unsigned char *search;
register unsigned char lastChar;
if (strLength == 0)
return NULL;
// Initialize skip lookup table
for (i = 0; i < 256; i++)
skipTable[i] = strLength;
search = string;
// Decrease strLength here to make it an index
i = --strLength;
do
{
skipTable[*search++] = i;
} while (i--);
lastChar = *--search;
// Start searching, position pointer at possible end of string.
search = data + strLength;
dataLength -= strLength+(strLength-1);
while ((int)dataLength > 0 )
{
unsigned int skip;
skip = skipTable[*search];
search += skip;
dataLength -= skip;
skip = skipTable[*search];
search += skip;
dataLength -= skip;
skip = skipTable[*search];
if (*search != lastChar) /*if (skip > 0)*/
{
// Character does not match, realign string and try again
search += skip;
dataLength -= skip;
continue;
}
// We had a match, we could be at the end of the string
i = strLength;
do
{
// Have we found the entire string?
if (i-- == 0)
return search;
} while (*--search == string[i]);
// Skip past the part of the string that we scanned already
search += (strLength - i + 1);
dataLength--;
}
// We reached the end of the data, and didn't find the string
return NULL;
}
void chomp(char *s) {
int n = strlen(s);
while (n && (s[n-1]==10 || s[n-1]==13)) s[--n] = 0;
}
int main(void)
{
char target[200];
char *ch = target,*str;
char pattern[20];
int i,k,count,l;
chomp(target);
chomp(pattern);
str = BoyerMoore( target, strlen(target), pattern, strlen(pattern) );
printf("Enter the string: \n");
fgets(target,100,stdin);
//scanf ("%[^\n]%*c", target);
printf("Enter the string to be matched: \n");
fgets(pattern,20,stdin);
//scanf ("%[^\n]%*c", pattern);
if (str == NULL)
puts( "String not found" );
else
puts( "true" );
getch();
return 0;
}
The calls to chomp are being passed arrays of uninitialised chars. The calls to strlen will then have undefined results, including very possibly reading/writing beyond the end of your buffers.
After this, you call BoyerMoore, passing in these still (at least partially) uninitialised buffers.
After this, you read pattern and target but don't do anything with them.
You don't say what the code is supposed to do but at the least I guess you need to
remove the calls to chomp
call fgets to initialise pattern and target before calling BoyerMoore
If things don't work after this, try using a debugger or adding printf statements to trace program progress.

Performing arithmetic on Characters in C

I am trying to write a program that adds, subtracts, multiplies, and divides a string of characters. Where I'm at now with the program is figuring out how to split the input string into two strings, and then perform the appropriate +-/*.
The input should look like this abc+aaa
and the output for that should be abc + aaa = bcd
How do I convert character strings into integer strings?
#include <stdio.h>
#include <math.h>
#include <string.h>
int main() {
printf("This is a pseudo arithmetic program");
char input[10];
input[10] = '\0';
char first [9];
first[9] = '\0';
char last [9];
last[9] = '\0';
int i = 0;
int b;
int e;
while (input[0] != '0') {
if (input[0] == 0){
return -1;
}
printf("\nEnter a math problem in SOS format using only lowercase letters up to 9 characters");
printf("\nEx: abc+abc... type '0' to quit \n");
scanf("%s", input);
int x = 0;
x = strlen(input);
if (strchr(input, '+')){
for (i = 0; i <= x; i++) {
if (i == '+')
strncpy(first, &input[0], i-1);
i = 0;
}
for (i = x; i >= input[0]; i--) {
if (i == '+')
strncpy(last, &input[i], x);
i = 0;
}
printf("%s", first);
printf(" + ");
printf("%s", last);
printf(" = %d", first + last);
}
There seems to be multiple problems with your code:
There is a array out of bounds happening for almost all the arrays:
char input[10];
input[10] = '\0';
In this if you want to initialize the last character with '\0' then it should be
input [9] = '\0'
Arrays indexes always start from 0.
It is not clear what is the use of below lines:
while (input[0] != '0') { if (input[0] == 0){ return -1; }
When taking input for a string, why are prompting users to enter a 0 to end it?
strrchr returns the pointer from where the searched character begins. So, you can that itself to determine where the '+' symbol is and two split the strings instead of your while loop. See strrchr man page
Also, your idea of adding characters is not clear. From your example, it appears you are considering a = 1, b = 2 etc. In such a case, if your code is case insensitive, then you can convert all your input to upper case and then do (input[0] - 'A')+1 to convert your letters like a, b, c to 1, 2, 3 etc.
Hope these pointers help. Suggest you check your problem statement again and refactor your code accordingly.

Resources