Validating lenght of digits and number - c

I have been struggling with a project, so i have to validate a number of 4 digits in C, i thought about using chars since i need to validate 0001 but no 1. Then i guess i need to convert that into a integer to work with it. Can someone help me?
printf("Enter a number 0 to end:");
gets(str);
while (strcmp(str, "0"))
{
j = 0;
k = 0;
flag = 0;
while (*(cad + j)) {
if (!isdigit(*(cad + j)))
flag = 1;
j++;
k = ++;
}
if (!flag && k == 4) {
i = atoi(cad);
q = newnode();
q->num = i;
stack(&pi,q);
}
else
printf("Wrong number");
printf("Enter a number 0 to end:");
gets(str);
}

I think you want this
#include <stdio.h>
#include <stdlib.h>
int
is_valid_number(const char *const string, int *value)
{
char *endptr;
*value = strtol(string, &endptr, 10);
return (((endptr - string) == 4) && (*endptr == '\0'));
}
int
main(void)
{
int value;
const char *string = "001";
if (is_valid_number(string, &value) != 0)
fprintf(stdout, "it's valid: %d\n", value);
else
fprintf(stdout, "\033[31mINVALID\033[0m\n");
return 0;
}

OP on the right track (aside from gets())
char str[50];
fputs("Enter a number 0 to end:", stdout);
while (fgets(str, sizeof str, stdin) != NULL)) {
str[strcspn(str,"\n")] = '\0'; // lop off potential trailing \n
if (strcmp(str, "0") == 0) {
break;
}
#define N 4
int all_digits = 1;
for (int j = 0; j<N; j++) {
if (!isdigit((unsigned char) str[j])) {
all_digits = 0;
break;
}
}
if (all_digits && str[N] == '\0') {
i = atoi(str);
...
}
else
fputs("Wrong number", stdout);
...

Related

In C, how should I extract coefficients and exponents from polynomial input using strtok?

Say the user enters "-4x^0 + x^1 + 4x^3 - 4x^5 - 3x^7" as an input. I want to extract values from the string and pass them into coef[] and expo[] so it looks like this:
coef = [-4, 1, 0, 4, 0, -4, 0, -3]
expo = [ 0, 1, 2, 3, 4, 5, 6, 7]
Here's what I have so far but I don't know how to use tokens.
int main()
{
char userInput[100];
char temp[100];
printf("Enter the polynomial: ");
scanf("%[^\n]%*c", userInput);
strcpy(temp, userInput);
printf("\n");
int coef[100];
int expo[100];
for (int i = 0; i < 100; i++) {
coef[i] = 0;
expo[i] = 0;
}
char *tok = strtok(temp, "x^");
int counter = 0;
while (tok) {
printf("*%s*\n", tok);
tok = strtok(NULL, "x^");
counter++;
}
return 0;
}
I have tried the following but it didn't work:
int counter = 0;
while (tok) {
printf("*%s*\n", tok);
expo[counter] = atoi(tok);
tok = strtok(NULL, "x^");
counter++;
}
This is a bit trickier problem than I first presumed due to the whitespace in the user-input and the possibility of missing exponents and coefficients -- and coefficients missing due to being 1 and omitted.
This can be done, but it requires a Decorate before you Tokenize where you decorate the string to be tokenized with new delimiters between the exponents and coefficient to ensure you can use strtok(). Otherwise because the +/- must be kept and the input format can be, e.g. "4x^1 + 3x^2" there is no delimiter between the 1 and 3 except for whitespace surrounding the '+' that must be considered part of 3.
A simple way to format the temporary string from the input is to remove all whitespace and add a new 'x' between the exponent and coefficient. That allows you to use the same delimiter string with strtok(), e.g. "x^\n" without adjustment.
The missing coefficients and exponents can be handled by looping from the current index to the exponent assigning 0 for coefficients and the loop counter for the exponent. Then you can add the current coefficient and exponent.
Putting it altogether and using sscanf() to minimally validate each conversion from string to int, you can do something similar to the following:
#include <stdio.h>
#include <string.h>
#define MAXC 1024 /* if you need a constant, #define one (or more) */
#define MAXCOEF 256
#define MAXEXP MAXCOEF
#define DELIM "x^\n"
int main (void) {
char buf[MAXC], tmp[MAXC]; /* input & reformat buffers */
int coef[MAXCOEF] = {0}, /* coefficient array */
expo[MAXEXP] = {0}, /* exponent array */
n = 0, ndx = 0; /* counter and index */
fputs ("enter polynomial: ", stdout); /* prompt */
if (!fgets (buf, MAXC, stdin)) { /* read line in buf/validate */
puts ("(user canceled input)");
return 0;
}
for (int i = 0; buf[i]; i++) { /* loop remormat buf in tmp */
if (buf[i] != ' ') { /* if not space */
if (buf[i] == '-' || buf[i] == '+') { /* if before next coef */
tmp[n++] = 'x'; /* decorate with new 'x' */
}
tmp[n++] = buf[i]; /* add from buf to tmp */
}
else { /* otherwise was ' ' */
if (buf[i+1] == 'x') { /* if next char is 'x' */
tmp[n++] = '1'; /* coef not given - use 1 */
}
}
}
tmp[n] = 0; /* nul-terminate tmp */
/* separate each token with strtok */
for (char *tok = strtok (tmp, DELIM); tok; tok = strtok (NULL, DELIM)) {
int ctmp, etmp; /* temp values for coefficient and exponent */
if (sscanf (tok, "%d", &ctmp) != 1) { /* convert coefficient to int */
fprintf (stderr, "conversion failed for '%s'.\n", tok);
return 1;
}
if (!(tok = strtok (NULL, DELIM))) { /* get exponent token */
break;
}
if (sscanf (tok, "%d", &etmp) != 1) { /* convert exponent to int */
fprintf (stderr, "conversion failed for '%s'.\n", tok);
return 1;
}
for (int i = ndx; i < etmp; i++) { /* loop index to exponent */
coef[ndx] = 0; /* add any missing values */
expo[ndx++] = i; /* increment index */
}
coef[ndx] = ctmp; /* add coefficient & exponent */
expo[ndx++] = etmp; /* increment index */
}
fputs ("\ncoef:", stdout); /* output coefficients */
for (int i = 0; i < ndx; i++) {
printf (" % d", coef[i]);
}
putchar ('\n'); /* tidy up with newline */
fputs ("expo:", stdout); /* output exponents */
for (int i = 0; i < ndx; i++) {
printf (" % d", expo[i]);
}
putchar ('\n');
}
Example Use/Output
$ ./bin/strtokpoly
enter polynomial: -4x^0 + x^1 + 4x^3 - 4x^5 - 3x^7
coef: -4 1 0 4 0 -4 0 -3
expo: 0 1 2 3 4 5 6 7
Which corresponds to your needed output.
Look things over and let me know if you have questions.
strtok() is not a good approach for this problem, especially using "x^" as the list of separators because it will overwrite these characters with null bytes, hence making it impossible to distinguish 2x from 2.
Also note that scanf("%[^\n]%*c", userInput) has undefined behavior if the polynomial entered by the user is longer than 99 bytes. The return value of scanf() should be tested to detect an unexpected end of file. It is safer to use fgets() and test the return value.
To parse the polynomial, it is recommended to test one character at a time and convert numbers with strtol or a similar function.
Here is a modified version:
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
unsigned char skip_spaces(char *p, char **pp) {
unsigned char c;
while (isspace(c = *p))
p++;
*pp = p;
return c;
}
void show_error(const char *error, const char *str, const char *p) {
fprintf(stderr, "error: %s\n%s%*s^\n", error, str, (int)(p - str), "");
}
#define TERM_COUNT 100
int main() {
char userInput[100];
printf("Enter the polynomial: ");
if (fgets(userInput, sizeof userInput, stdin)) {
int coef[TERM_COUNT] = { 0 };
int expo[TERM_COUNT] = { 0 };
int counter;
char *p = userInput;
for (counter = 0; counter < TERM_COUNT; counter++) {
int sign = 1;
unsigned char c = skip_spaces(p, &p);
if (c == '\0')
break;
if (c == '+') {
c = skip_spaces(p + 1, &p);
} else
if (c == '-') {
sign = -1;
c = skip_spaces(p + 1, &p);
}
if (c == '\0') {
show_error("missing term", userInput, p);
break;
}
if (isdigit(c)) {
coef[counter] = sign * strtol(p, &p, 10);
c = skip_spaces(p, &p);
} else {
coef[counter] = sign;
}
if (c == 'x') {
c = skip_spaces(p + 1, &p);
if (c == '^') {
c = skip_spaces(p + 1, &p);
if (isdigit(c)) {
expo[counter] = strtol(p, &p, 10);
c = skip_spaces(p, &p);
} else {
show_error("missing exponent", userInput, p);
break;
}
} else {
expo[counter] = 1;
}
} else {
expo[counter] = 0;
}
if (c != '\0' && c != '+' && c != '-') {
show_error("syntax error", userInput, p);
break;
}
}
for (int i = 0; i < counter; i++)
printf("%+dx^%d", coef[i], expo[i]);
printf("\n");
}
return 0;
}
The above code uses your approach and populates 2 arrays with the coefficients and exponents.
This is a little too complex to do with strtok, as you have all kinds of corner cases with implicit coefficients and such. You could go the full-parsing route and use lex & yacc, but that is probably overkill. A hybrid approach is to use fgets + sscanf to match specific patterns. Something like:
int main() {
char userInput[100] = { 0 };
printf("Enter the polynomial: ");
fgets(userInput, sizeof(userInput), stdin);
printf("\n");
int coef[100] = { 0 };
int expo[100] = { 0 };
int i = 0;
char *p = userInput;
while (p && *p && i < 100) {
int len;
if (i == 0 && sscanf(p, "%d x ^%d %n", &coef[i], &expo[i], &len) == 2)) {
} else if (sscanf(p, " +%d x ^%d %n", &coef[i], &expo[i], &len) == 2)) {
} else if (sscanf(p, " -%d x ^%d %n", &coef[i], &expo[i], &len) == 2)) {
coef[i] = -coef[i];
} else if (i == 0 && sscanf(p, " x ^%d %n", &expo[i], &len) == 1) {
coef[i] = 1;
} else if (sscanf(p, " + x ^%d %n", &expo[i], &len) == 1) {
coef[i] = 1;
} else if (sscanf(p, " - x ^%d %n", &expo[i], &len) == 1) {
coef[i] = -1;
} else if (sscanf(p, " +%d x %n", &coeff[i], &len) == 1) {
expo[i] = 1;
} else if (sccanf(p, " -%d x %n", &coeff[i], &len) == 1) {
coef[i] = -coef[i];
expo[i] = 1;
} else if (i == 0 && sccanf(p, "%d x %n", &coeff[i], &len) == 1) {
expo[i] = 1;
} else if (sscanf(p, " +%d %n", &coeff[i], &len) == 1) {
expo[i] = 0;
} else if (sccanf(p, " -%d %n", &coeff[i], &len) == 1) {
coef[i] = -coef[i];
expo[i] = 0;
} else if (i == 0 && sccanf(p, "%d %n", &coeff[i], &len) == 1) {
expo[i] = 0;
} else {
fprintf(stderr, "this doesn't look like a polynomial: %s\n", p);
break;
}
p += len;
++i;
}
printf("got polynomial: ");
for (int j = 0; j < i; ++j)
printf("%+dx^%d", coef[j], expo[j]);
printf("\n");
}
Note that this can get pretty complex fast, with lots of different corner cases to check, but for simpler things may be easier than using a full parser.

String Pattern Matching in C

I was trying this pattern matching method in C but whenever I give all the input, the vscode terminal waits for a while and just stops the program without any warnings/message. Can anyone point to what is wrong here?
#include <stdio.h>
#include <string.h>
int main()
{
char STR[100], PAT[100], REP[100], ANS[100];
int i, m, j, k, flag, slP, slR, len;
i = m = k = j = flag = len = 0;
printf("\nMain String: ");
gets(STR);
printf("\nPattern String: ");
gets(PAT);
slP = strlen(PAT);
printf("\nReplace String: ");
gets(REP);
slR = strlen(REP);
while (STR[i] != '\0')
{
if (STR[i] = PAT[j])
{
len = 0;
for (k = 0; k < slP; k++)
{
if (STR[k] = PAT[k])
len++;
}
if (len == slP)
{
flag = 1;
for (k = 0; k < slR; k++, m++)
ANS[m] = REP[k];
}
}
else
{
ANS[m] = STR[i];
m++;
i++;
}
}
if (flag == 0)
{
printf("\nPattern not found!");
}
else
{
ANS[m] = '\0';
printf("\nResultant String: %s\n", ANS);
}
return 0;
}
There are multiple problems in the code:
using gets() is risky, this function was removed from the C Standard because it cannot be used safely.
if (STR[i] = PAT[j]) copied the pattern to the string. You should use:
if (STR[i] == PAT[j])
similarly, if (STR[k] = PAT[k]) is incorrect. You should compare PAT[k] and STR[i + k]:
if (STR[i + k] == PAT[k])
you should test for buffer overflow for the output string as replacing a short string by a larger one may produce a string that will not fit in ANS
you do not increment i properly.
Here is a modified version:
#include <stdio.h>
int getstr(const char *prompt, char *dest, int size) {
int c, len = 0;
printf("%s", prompt);
while ((c = getchar()) != EOF && c != '\n') {
if (len + 1 < size)
dest[len++] = c;
}
if (size > 0)
dest[len] = '\0';
printf("\n");
if (c == EOF && len == 0)
return -1;
else
return len;
}
int main() {
char STR[100], PAT[100], REP[100], ANS[100];
int i, m, k, flag;
if (getstr("Main String: ", STR, sizeof STR) < 0)
return 1;
if (getstr("Pattern String: ", PAT, sizeof PAT) < 0)
return 1;
if (getstr("Replace String: ", REP, sizeof REP) < 0)
return 1;
i = m = flag = 0;
while (STR[i] != '\0') {
if (STR[i] == PAT[0]) { // initial match
// compare the rest of the pattern
for (k = 1; PAT[k] != '\0' && PAT[k] == STR[i + k]; k++)
continue;
if (PAT[k] == '\0') { // complete match
flag = 1;
// copy the replacement string
for (k = 0; REP[k] != '\0'; k++) {
if (m + 1 < sizeof ANS)
ANS[m++] = REP[k];
}
i += k; // skip the matching characters
continue;
}
}
// otherwise copy a single character
if (m + 1 < sizeof ANS)
ANS[m++] = STR[i];
i++;
}
ANS[m] = '\0';
if (flag == 0) {
printf("Pattern not found!\n");
} else {
printf("Resultant String: %s\n", ANS);
}
return 0;
}

Compare code in reverse each word in sentence

I have school task. To reverse each word in sentence, so example :
Input: Fried chicken, fried duck.
Output: deirF nekcihc, deirf kcud.
So except dot and comma it's not reversed.
The first code
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main() {
int i, n, titik = 0, coma = 0;
char s[5001];
char c[5001];
char *tok;
scanf("%[^\n]s", s);
if (s[0] == ' ')
printf(" ");
tok = strtok(s, " ");
while (tok != NULL) {
strcpy(c, tok);
n = strlen(c);
for (i = n; i >= 0; i--) {
if (c[i] == ',') {
coma = 1;
} else
if (c[i] == '.') {
titik = 1;
} else
printf("%c", c[i]);
}
if (coma) {
printf(",");
coma = 0;
} else
if (titik){
printf(".");
titik = 0;
}
tok = strtok(NULL," ");
if (tok == NULL)
printf("\n");
else
printf(" ");
}
}
Second code is
#include <stdio.h>
#include <ctype.h>
#include <string.h>
int main() {
int i, j, n, prana = 0, titik = 0, coma = 0, end = 0;
char s[5001];
scanf("%[^\n]s", s);
n = strlen(s);
for (i = 0; i <= n; i++) {
if (isspace(s[i]) || iscntrl(s[i])) {
if (iscntrl(s[i]))
end = 1;
for (j = i - 1; j >= prana; j--) {
if (s[j] == '.') {
titik = 1;
} else
if (s[j] == ',') {
coma = 1;
} else
printf("%c", s[j]);
}
prana = i + 1;
if (titik) {
titik = 0;
if (end)
printf(".");
else
printf(". ");
} else
if (coma) {
coma = 0;
if (end)
printf(",");
else
printf(", ");
} else {
if (end)
printf("");
else
printf(" ");
}
}
}
printf("\n");
return 0;
}
Why the second code is accepted in test case?, but first code is not.
I tested the result it's same. Really identical in md5 hash.
The output of the two codes id different, because you print the terminating null character for each token in the first code. This loop:
for (i = n; i >=0 ; i--) ...
will have i == n in its first iteration. For a C string of length n, s[n] is the terminating null. This character may not show in the console, but it is part of the output.
To fix the loop, you could start with i = n - 1, but C uses inclusive lower bounds and exclusive upper bounds, and a more idomatic loop syntax is:
i = n;
while (i-- > 0) ...
Not related to your question at hand, but your codes are rather complicated, because they rely on many assumptions: words separated by spaces; only punctuation is comma or stop; repeated punctuation marks are ignored, special case for last word.
Here's a solution that treats all chunks of alphabetic characters plus the apostrophe as words and reverses them in place:
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
void reverse(char *str, int i, int j)
{
while (i < j) {
int c = str[--j];
str[j] = str[i];
str[i++] = c;
}
}
int main()
{
char str[512];
int begin = -1;
int i;
if (fgets(str, sizeof(str), stdin) == NULL) return -1;
for (i = 0; str[i]; i++) {
if (isalpha((unsigned char) str[i]) || str[i] == '\'') {
if (begin == -1) begin = i;
} else {
if (begin != -1) {
reverse(str, begin, i);
begin = -1;
}
}
}
printf("%s", str);
return 0;
}

Iterate through string and store numbers in array

I like to iterate through the string 1.3.6.1.2.1.2.2.1.10.1 and store all numbers in a array. My code works for numbers between 0-9 but not for greater than 9 because I iterate just one step and scan the number. How can I store all numbers, not like in my current output : 1 3 6 1 2 1 2 2 1 10 0 1 (without linebreak)?
int main(int argc, char *argv[])
{
//char * string = "1.3.6.1.2.1.2.2.1.9.1"; /* OK */
char * string = "1.3.6.1.2.1.2.2.1.10.1"; /* NOK */
static int oid_val_arr[256];
char *oid_tmp = string;
int idx = 0;
while (*oid_tmp)
{
int number;
if (sscanf(oid_tmp, "%d", &number) == 1)
{
oid_val_arr[idx] = number;
idx++;
}
oid_tmp++; /* PROBLEM */
}
for(int i = 0; i < 12; i++)
printf("%d\n", oid_val_arr[i]);
}
Should I use strtok()?
In your code, change this:
if(sscanf(oid_tmp, "%d", &number) == 1)
to this:
if(sscanf(oid_tmp, "%d%n", &number, &len) == 1)
in order to get the length too. Then of course you would need to change your while loop like this:
while (*oid_tmp)
{
int number;
int len;
if(sscanf(oid_tmp, "%d%n", &number, &len) == 1)
{
oid_val_arr[idx++] = number;
oid_tmp += len;
}
else
{
++oid_tmp;
}
}
as BLUEPIXY said.
Another approach would be to use strtok() and atoi(), like this:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define SIZE 11
int main ()
{
int arr[SIZE], i = 0;
char str[] ="1.3.6.1.2.1.2.2.1.10.1";
char * pch;
printf ("Splitting string \"%s\" into tokens:\n",str);
pch = strtok (str,".");
while (pch != NULL)
{
//printf ("%s\n",pch);
arr[i++] = atoi(pch);
pch = strtok (NULL, ".");
}
for(i = 0; i < SIZE; ++i)
printf("%d ", arr[i]);
printf("\n");
return 0;
}
Output:
Splitting string "1.3.6.1.2.1.2.2.1.10.1" into tokens:
1 3 6 1 2 1 2 2 1 10 1
or instead of strtok
Function ignores more than one separator between the numbers.
int stringToIntArray(const char *string, char *separators, int *table, size_t tablesize, int ignoreinvalid)
{
int result = (string == NULL || separators == NULL || table == NULL || !tablesize) * -1;
char tmpbuff[50];
char *tmpptr;
int invalid = 0;
if (!result)
{
while (*string)
{
invalid = 0;
tmpptr = tmpbuff;
while (*string && strchr(separators, *string) != NULL) string++;
while (*string && strchr(separators, *string) == NULL)
{
if (isdigit(*string)) *tmpptr++ = *string;
else
{
if (ignoreinvalid == 1)
{
invalid = 1;
break;
}
if (ignoreinvalid == 2)
{
result = -1;
break;
}
}
*string++;
}
if (result != -1)
{
if (invalid)
{
while (*string && strchr(separators, *string) == NULL) string++;
}
else
{
*tmpptr = '\0';
if (!strlen(tmpbuff)) break;
table[result++] = atoi(tmpbuff);
if (result == tablesize) break;
}
}
else break;
}
}
return result;
}
usage:
int ar[11];
int cnt = stringToIntArray("123,:0dddd3:0:;456", ",:;", &ar, 11, 0);
last parameter - 0 just ignores invalid symbols, 1 ignores the number, 2 breaks scanning with error. Return nomber of numbers found or -1 on error

program adding numbers doesn't show any output

I have a problem with an "add calculator".
Valgrind reports no memory errors, no errors from compiler but the program doesn't show any output despite the printf - "Base is ".
All pointers, and variables are (n my opinion) correctly initialized.
getnum function gets a number, returns a pointer to char - char *,
add function processes two numbers as strings, returns result which is a pointer to char (char *) as well.
I don't know whether the problem is memory allocation or procedures connected to processing arrays...
Here's the code:
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#define MAX(A,B) ((A)>(B) ? (A) : (B))
char *getnum(FILE *infile, int base)
{
int len = 10;
int c;
int pos = 0;
char *num = NULL;
char *tmpnum = NULL;
num = malloc(sizeof(char)*len);
while (((c = fgetc(infile)) != EOF) && (isalnum(c))) {
if (isdigit(c)) {
/* irrelevant*/
}
else if (isalpha(c)) {
fprintf(stderr, "Wrong base, expected 16\n");
free(num);
return NULL;
}
if (pos >= len) {
/*realloc*/
}
}
return num;
}
int main(int argc, char **argv)
{
FILE *infile = NULL;
char *number1 = NULL;
char *number2 = NULL;
char *result = NULL;
int base, i, j = 0, length, count = 0;
infile = fopen(argv[1], "r");
base = atoi(argv[2]);
while (!feof(infile)) {
number1 = getnum(infile, base);
number2 = getnum(infile, base);
break;
}
printf("Base is %d\n", base);
result = add(number1, number2, base);
length = strlen(result);
for (i = 0; i <= length - 1; i++) {
if (result[i] == '0') {
count++;
}
}
for (j = i; j == (length - 1); j++) {
printf("Result is: %s\n", &result[j]);
break;
}
free(result);
result = NULL;
fclose(infile);
return 0;
}
Trying to work it out for the past 4 hours and can't find a mistake.
Thanks in advance!
There is one severe typo near the end of main().
for (j = i; j == (length - 1); j++) {
/* ^^ SHOULD BE <= */
printf("Result is: %s\n", &result[j]);
break;
}
Looking at this code:
for (i = 0; i <= length - 1; i++) {
if (result[i] == '0') {
count++;
}
}
if (count == length) {
printf("Result is 0\n");
free(result);
result = NULL; /* arguable */
fclose(infile);
return 0;
}
for (i = 0; i <= length - 1; i++) {
if (result[i] != '0') {
break;
}
}
for (j = i; j == (length - 1); j++) {
printf("Result is: %s\n", &result[j]);
break;
}
Instead of counting the total number of zeroes in the output number, and then counting the number of leading zeroes again, why not combine the two?
What is the last loop about? It's not even really a loop - it will execute once if i is length - 1, or not at all if not (presumably you're hitting the latter case in your test input).
e.g.
for (count = 0; count < length; count++) {
if (result[count] != '0')
break;
}
if (count == length) {
printf("Result is 0\n");
free(result);
result = NULL; /* arguable */
fclose(infile);
return 0;
}
printf("Result is: %s\n", &result[count]);

Resources