I want to check if a string is a number with this code. I must check that all the chars in the string are integer, but the while returns always isDigit = 1. I don't know why that if doesn't work.
char tmp[16];
scanf("%s", tmp);
int isDigit = 0;
int j=0;
while(j<strlen(tmp) && isDigit == 0){
if(tmp[j] > 57 && tmp[j] < 48)
isDigit = 0;
else
isDigit = 1;
j++;
}
Forget about ASCII code checks, use isdigit or isnumber (see man isnumber). The first function checks whether the character is 0–9, the second one also accepts various other number characters depending on the current locale.
There may even be better functions to do the check – the important lesson is that this is a bit more complex than it looks, because the precise definition of a “number string” depends on the particular locale and the string encoding.
if(tmp[j] >= '0' && tmp[j] <= '9') // should do the trick
More obvious and simple, thread safe example:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char **argv)
{
if (argc < 2){
printf ("Dont' forget to pass arguments!\n");
return(-1);
}
printf ("You have executed the program : %s\n", argv[0]);
for(int i = 1; i < argc; i++){
if(strcmp(argv[i],"--some_definite_parameter") == 0){
printf("You have passed some definite parameter as an argument. And it is \"%s\".\n",argv[i]);
}
else if(strspn(argv[i], "0123456789") == strlen(argv[i])) {
size_t big_digit = 0;
sscanf(argv[i], "%zu%*c",&big_digit);
printf("Your %d'nd argument contains only digits, and it is a number \"%zu\".\n",i,big_digit);
}
else if(strspn(argv[i], "0123456789abcdefghijklmnopqrstuvwxyz./") == strlen(argv[i]))
{
printf("%s - this string might contain digits, small letters and path symbols. It could be used for passing a file name or a path, for example.\n",argv[i]);
}
else if(strspn(argv[i], "ABCDEFGHIJKLMNOPQRSTUVWXYZ") == strlen(argv[i]))
{
printf("The string \"%s\" contains only capital letters.\n",argv[i]);
}
}
}
if ( strlen(str) == strlen( itoa(atoi(str)) ) ) {
//its an integer
}
As atoi converts string to number skipping letters other than digits, if there was no other than digits its string length has to be the same as the original.
This solution is better than innumber() if the check is for integer.
#include <stdio.h>
#include <string.h>
char isNumber(char *text)
{
int j;
j = strlen(text);
while(j--)
{
if(text[j] > 47 && text[j] < 58)
continue;
return 0;
}
return 1;
}
int main(){
char tmp[16];
scanf("%s", tmp);
if(isNumber(tmp))
return printf("is a number\n");
return printf("is not a number\n");
}
You can also check its stringfied value, which could also work with non Ascii
char isNumber(char *text)
{
int j;
j = strlen(text);
while(j--)
{
if(text[j] >= '0' && text[j] <= '9')
continue;
return 0;
}
return 1;
}
In this part of your code:
if(tmp[j] > 57 && tmp[j] < 48)
isDigit = 0;
else
isDigit = 1;
Your if condition will always be false, resulting in isDigit always being set to 1. You are probably wanting:
if(tmp[j] > '9' || tmp[j] < '0')
isDigit = 0;
else
isDigit = 1;
But. this can be simplified to:
isDigit = isdigit(tmp[j]);
However, the logic of your loop seems kind of misguided:
int isDigit = 0;
int j=0;
while(j<strlen(tmp) && isDigit == 0){
isDigit = isdigit(tmp[j]);
j++;
}
As tmp is not a constant, it is uncertain whether the compiler will optimize the length calculation out of each iteration.
As #andlrc suggests in a comment, you can instead just check for digits, since the terminating NUL will fail the check anyway.
while (isdigit(tmp[j])) ++j;
I need to do the same thing for a project I am currently working on. Here is how I solved things:
/* Prompt user for input */
printf("Enter a number: ");
/* Read user input */
char input[255]; //Of course, you can choose a different input size
fgets(input, sizeof(input), stdin);
/* Strip trailing newline */
size_t ln = strlen(input) - 1;
if( input[ln] == '\n' ) input[ln] = '\0';
/* Ensure that input is a number */
for( size_t i = 0; i < ln; i++){
if( !isdigit(input[i]) ){
fprintf(stderr, "%c is not a number. Try again.\n", input[i]);
getInput(); //Assuming this is the name of the function you are using
return;
}
}
None of these deal appropriately with negative numbers or floating point numbers.
How about:
bool
is_realnumber(char *instring) {
if (*instring != '-' && *instring != '.' && !isdigit(*instring)) return false;
if (strspn(instring+1, "0123456789.") < strlen(instring+1)) return false;
int c = 0;
while (*instring) if (*instring++ == '.') if (++c > 1) return false;
return true;
}
I can extend Marcelo's answer supporting floating numbers also as following:
char isnumber(const char *str)
{
int decpos = -1, pmpos = -1, engpos = strlen(str) - 1, epmpos = strlen(str) - 1;
for (int i = 0; i < strlen(str); i++)
/* check if it is integer */
if (str[i] > 47 && str[i] < 58)
continue;
/* check if it is decimal seperator and used once*/
else if (str[i] == 46 && decpos == -1)
{
decpos = i;
continue;
}
/* check if it is +/-, at the begining*/
else if ((str[i] == 43 || str[i] == 45) && i == 0)
{
pmpos = 1;
continue;
}
/* check if it is engineering format e/E, used once, after decimal and before +/-*/
else if ((str[i] == 69 || str[i] == 101) && engpos == strlen(str) - 1 && i > 0 && i > decpos && i < epmpos)
{
engpos = 1;
continue;
}
/* check if it is engineering format +/-, used once, after decimal and after engineering e/E*/
else if ((str[i] == 43 || str[i] == 45) && epmpos == strlen(str) - 1 && i > 0 && i > decpos && i > engpos)
{
epmpos = 1;
continue;
}
else
return 0;
return 1;
}
You can implement the function as following:
bool isNumeric(const char* s){
while(*s){
if(*s < '0' || *s > '9')
return false;
++s;
}
return true;
}
If you intend to use that number in integer/long form in the future, you will be calling atoi or atol anyway, in which case you might want to just check the return value.
char tmp[16];
scanf("%s", tmp); // unsafe!!!
long tmp_long = atol(&tmp);
if (tmp_long == 0){
printf("%s: is not a number.\n", &tmp);
}
tutorialspoint on atol
Your condition says if X is greater than 57 AND smaller than 48. X cannot be both greater than 57 and smaller than 48 at the same time.
if(tmp[j] > 57 && tmp[j] < 48)
It should be if X is greater than 57 OR smaller than 48:
if(tmp[j] > 57 || tmp[j] < 48)
rewrite the whole function as below:
bool IsValidNumber(char * string)
{
for(int i = 0; i < strlen( string ); i ++)
{
//ASCII value of 0 = 48, 9 = 57. So if value is outside of numeric range then fail
//Checking for negative sign "-" could be added: ASCII value 45.
if (string[i] < 48 || string[i] > 57)
return FALSE;
}
return TRUE;
}
The problem is that the result of your code "isDigit" is reflecting only the last digit test. As far as I understand your qustion, you want to return isDigit = 0 whenever you have any character that is not a number in your string. Following your logic, you should code it like this:
char tmp[16];
scanf("%s", tmp);
int isDigit = 0;
int j=0;
isDigit = 1; /* Initialised it here */
while(j<strlen(tmp) && isDigit == 0){
if(tmp[j] > 57 || tmp[j] < 48) /* changed it to OR || */
isDigit = 0;
j++;
}
To get a more understandable code, I'd also change the test:
if(tmp[j] > 57 || tmp[j] < 48)
to the following:
if(tmp[j] > '9' || tmp[j] < '0')
Can check every char by isdigit().
#include <string.h>
#include <ctype.h>
int is_digit_str(char* str){
int digit_count = 0;
for (int i = 0; i < strlen(str); i++) {
if(isdigit(str[i]))
digit_count++;
else
break;
}
return digit_count == strlen(str);
}
int being_number(char string[]){
int l=strlen(string);
for (int i = 0; i < l; i++)
{
if(string[i] >= '0' && string[i] <= '9'){
i=i;
}
else{
return(0);
}
}
return(1);
}
Related
I need to check if a given string is a Palindrome or mini-Palindrome.
Palindrome length will be 2 or more, the function need to ignore spaces and ignore the differences of upper and lower alphabet.
if the string is Palindrome the function will transfer the indexes of the start and the end of him and will return 1 else return 0.
example1: "My gym" the function will transfer low=0 high=5 and 1
example2: "I Love ANNA" the function will transfer low=7 high=10 and 1
example3: "I love Pasta" return 0.
Also i can’t use functions from librarys other then string.h stdlib.h stdio.h.
I tried to write like this:
int i;
int size = strlen(str);
i = 0;
while (str[i] != '\0')
{
if (str[i] == ' ')
{
i++;
continue;
}
//-------------------
if (str[i] >= ‘a’ && str[i] <= ‘z’)
str[i] = str[i] - 32;
if (str[size-1] >= ‘a’ && str[size-1] <= ‘z’)
str[size-1] = str[size-1] - 32;
//-------------------
if (str[i] == str[size-1])
{
*low = i;
*high = size-1;
return 1;
}
else
{
size--;
i++;
}
}
return 0;
But it isnt working well, i cant figure how to do it with the example 2
Here goes. Will this help you
#define LOWER(a) (((a) >=' A' && (a) <= 'Z') ? ((a) - 'A' +'a') : (a))
#define MYCMP(a,b) (LOWER(a) == LOWER(b))
int is_palidrome(char *s) {
int start = 0;
int end = strlen(s) - 1;
for (; s[start] // Not end of line
&& end >=0 // Not run over the from of the line
&& start < end // Still not got to the middle
&& MYCMP(s[start], s[end]) == 1; // They are still equal
start++, end--) { //Nowt }
};
return (start >= end);
}
I made a program. It works only if the string contains letters and spaces. You can modify it to work for other characters.
#include <stdio.h>
#include <string.h>
#define SIZE 100
int isPalindrome( char *s, size_t l );
int main() {
char str[SIZE];
size_t i, j, len, pldrm = 0;
fgets(str, SIZE, stdin);
len = strlen(str);
for(i = 0; i < len; i++) if( str[i] != ' ' && !((str[i] >= 'a' && str[i] <= 'z') || (str[i] >= 'A' && str[i] <= 'Z')) ) goto the_end;
for(i = 0; i < len-1; i++) {
if( str[i] != ' ' ) {
for(j = i+1; j < len; j++) {
if( (pldrm = isPalindrome(&str[i], j-i+1)) ) {
str[j+1] = '\0';
goto the_end;
}
}
}
}
the_end:
pldrm ? printf("A palindrome has been found from the position %zu till the position %zu.\n\nThe palindrome is: %s\n", i, j, &str[i]) : puts("No palindromes");
return 0;
}
int isPalindrome( char *s, size_t l )
{
static const char az[26] = "abcdefghijklmnopqrstuvwxyz", AZ[26] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
int isPldrm = 1, spc = 0; // used to skip spaces within the palindrome
for(size_t i = 0; i < l/2; i++) {
for(size_t j = 0; j < 26; j++) {
if( s[i] == az[j] || s[i] == AZ[j] ) {
while( s[l-1-i-spc] == ' ' ) ++spc;
if( s[l-1-i-spc] != az[j] && s[l-1-i-spc] != AZ[j] ) {
isPldrm = 0;
goto thats_it;
}
break;
}
}
}
thats_it:
return isPldrm;
}
Also, it finds only the first palindrome in the input. Doesn't check for further palindromes.
As stated above, I would like to make a function that checks if all the characters in a string contains any prohibited input. The condition is that I only want to accept alphabets, hyphens and apostrophes. Below is my code which does not work the way I intended it to. If it is not an alphabet AND not an apostrophe or a hyphen, I want to change result to 0. However, when I enter a valid input like 'a-a; which is either an alphabet or hyphen, the if function still gets executed which prints "IT IS NOT ACCEPTED".
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
int validateInput(char word[]);
int main(void) {
char word[33] = "a-a";
printf("%d",validateInput(word));
}
int validateInput(char word[]) {
int result = 1;
int i;
int length = strlen(word);
for (i = 0; i <length; i++) {
if ((isalpha(word[i]) == 0) && ((word[i] != '-') || (word[i] != '\''))) {
printf("IT IS NOT ACCEPTED\n");
result = 0;
}
else {
printf("ACCEPTED\n");
}
}
return result;
}
There are multiple problems in your code:
you issue the diagnostic at each iteration instead of at the end of the loop
the test (word[i] != '-') || (word[i] != '\'') is always true.
isalpha() should not be passed a char value that could be negative. You should cast the argument as (unsigned char) to avoid potential undefined behavior.
Here is a modified version:
#include <ctype.h>
int validateInput(const char *word) {
int result = 1;
for (size_t i = 0; word[i] != '\0'; i++) {
if (!isalpha((unsigned char)word[i]) && word[i] != '-' && word[i] != '\'') {
result = 0;
break;
}
}
if (result) {
printf("ACCEPTED\n");
} else {
printf("IT IS NOT ACCEPTED\n");
}
return result;
}
Note however that the above function will accept an empty string, which might not be the intended behavior.
Here is a simpler version using sscanf() that works for ASCII:
#include <stdio.h>
int validateInput(const char *word) {
int pos = 0;
sscanf(word, "%*[-a-zA-Z']%n", &pos);
if (pos > 0 && word[pos] == '\0') {
printf("ACCEPTED\n");
return 1;
} else {
printf("IT IS NOT ACCEPTED\n");
return 0;
}
}
And this is a more verbose version using strspn() that works for all encodings:
#include <string.h>
int validateInput(const char *word) {
size_t len = strspn(word, "'-ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz");
if (len > 0 && word[len] == '\0') {
printf("ACCEPTED\n");
return 1;
} else {
printf("IT IS NOT ACCEPTED\n");
return 0;
}
}
Try:
if( !( (isalpha((unsigned char)word[i])) || (word[i] == '-') || (word[i] == '\'')) )
Hi I am confined to stdio.h, stdlib.h and string.h and I need to ask a user for input - the input can be any number of characters between 1 and 6, however the first two characters MUST be an uppercase alphabetical letter, and the remaining four characters MUST be a number between 0 and 9.
Examples of valid input:
AB1
AB1234
AB
A
Examples of Invalid Input:
AB12345 (too many characters)
123 (first two characters are not uppercase letters)
ABA (a character after the second one is not a numeric value)
Here is my attempt so far (just bear in mind I have almost no experience with C, the likelihood that this solution is "idiomatic" is next to none, and the reason I am asking this is so that I can learn):
Flightcode is a char array defined as flightcode[7] it lives inside another struct called flight. I am fgetsing it into a temp_array[7] first and then strcpying it into the flight->flightcode such that the null terminator is appended and I don't know a better way of doing that.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_FLIGHTCODE_LEN 6
#define MAX_CITYCODE_LEN 3
#define MAX_NUM_FLIGHTS 50
#define DB_NAME "database"
typedef struct {
int month;
int day;
int hour;
int minute;
} date_time_t;
typedef struct {
char flightcode[MAX_FLIGHTCODE_LEN + 1];
date_time_t departure_dt;
char arrival_city[MAX_CITYCODE_LEN + 1];
date_time_t arrival_dt;
} flight_t;
date_time_t departure_dt;
date_time_t arrival_dt;
char * scanline(char *dest, int dest_len);
int main(){
char temp_string[100];
flight_t flight[MAX_NUM_FLIGHTS + 1];
int correct_code = 0;
printf("Enter flight code>\n");
scanline(temp_string, sizeof(flight->flightcode));
strcpy(flight->flightcode, temp_string);
while(correct_code == 0)
{
for(int i = 0; flight->flightcode[i] != '\0' && correct_code == 0; i++)
{
while((i < 2 && (flight->flightcode[i] <= 64 || flight->flightcode[i] >= 91)) || (i > 1 && (flight->flightcode[i] < 48 || flight->flightcode[i] >= 58)))
{
printf("Invalid input.\n");
scanline(temp_string, sizeof(flight->flightcode));
strcpy(flight->flightcode, temp_string);
}
if((i < 2 && (flight->flightcode[i] > 64 || flight->flightcode[i] < 91)) || (i > 1 && (flight->flightcode[i] >= 48 || flight->flightcode[i] < 58)))
{
correct_code = 1;
}
}
}
}
char * scanline(char *dest, int dest_len){
int i, ch;
i = 0;
for (ch = getchar();
ch != '\n' && ch != EOF && i < dest_len -1; ch = getchar())
dest[i++] = ch;
dest[i] = '\0';
while (ch != '\n' && ch != EOF)
ch = getchar();
return (dest);
}
Scansets and the %n specifier could be used to parse the input.
The format string "%n%2[A-Z]%n%4[0-9]%n" uses the %n specifier in three places to capture the number of characters processed. The scanset %2[A-Z] will scan up to two characters if the characters are in the set of upper case letters. %4[0-9] will scan up to four characters if the characters are digits.
If two values are scanned by sscanf, the number of characters processed are subtracted to make sure there are two leading upper case characters and six or fewer total character and the trailing character is the terminating zero.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_FLIGHTCODE_LEN 6
#define MAX_CITYCODE_LEN 3
#define MAX_NUM_FLIGHTS 50
#define DB_NAME "database"
typedef struct {
int month;
int day;
int hour;
int minute;
} date_time_t;
typedef struct {
char flightcode[MAX_FLIGHTCODE_LEN + 1];
date_time_t departure_dt;
char arrival_city[MAX_CITYCODE_LEN + 1];
date_time_t arrival_dt;
} flight_t;
date_time_t departure_dt;
date_time_t arrival_dt;
char * scanline(char *dest, int dest_len);
int main(){
int head = 0, leading = 0, tail = 0;
int correct_code = 0;
int result = 0;
char temp_string[100];
char upper[3] = "";
char digits[5] = "";
flight_t flight[MAX_NUM_FLIGHTS + 1];
do {
printf("Enter flight code>\n");
scanline(temp_string, sizeof(temp_string));
if ( 0 < ( result = sscanf ( temp_string, "%n%2[A-Z]%n%4[0-9]%n", &head, upper, &leading, digits, &tail))) {
if ( 1 == result && 0 == temp_string[leading]) {
correct_code = 1;
break;
}
if ( 2 == result && 2 == leading - head && 7 > tail - head && 0 == temp_string[tail]) {
correct_code = 1;
}
else {
printf ( "invalid input\n");
}
}
else {
printf ( "invalid input\n");
}
} while(correct_code == 0);
printf ( "Input is: %s\n", temp_string);
strcpy(flight->flightcode, temp_string);
return 0;
}
char * scanline(char *dest, int dest_len){
int i, ch;
i = 0;
for (ch = getchar(); ch != '\n' && ch != EOF && i < dest_len -1; ch = getchar()) {
dest[i++] = ch;
}
dest[i] = '\0';
while (ch != '\n' && ch != EOF) {
ch = getchar();
}
return dest;
}
Your function scanline does not do much more than the standard function fgets. I propose to use the standard function instead. Removing the trailing newline '\n' is easy.
I have split the checks into 3 parts:
Check the length to be more than 0 and not more than MAX_FLIGHTCODE_LEN.
Check the first 2 characters to be uppercase letters A..Z
Check the remaining characters to be digits 0..9
Proposed code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_FLIGHTCODE_LEN 6
#define MAX_CITYCODE_LEN 3
#define MAX_NUM_FLIGHTS 50
#define DB_NAME "database"
typedef struct {
int month;
int day;
int hour;
int minute;
} date_time_t;
typedef struct {
char flightcode[MAX_FLIGHTCODE_LEN + 1];
date_time_t departure_dt;
char arrival_city[MAX_CITYCODE_LEN + 1];
date_time_t arrival_dt;
} flight_t;
date_time_t departure_dt;
date_time_t arrival_dt;
int main(void){
char temp_string[100];
flight_t flight[MAX_NUM_FLIGHTS + 1];
int correct_code;
size_t len;
int i;
do
{
/* we first assume the code is correct and set this to 0 on any error */
correct_code = 1;
printf("Enter flight code>\n");
if(fgets(temp_string, sizeof(temp_string), stdin) == NULL)
{
if(feof(stdin)) fprintf(stderr, "no input (EOF)\n");
else perror("fgets");
correct_code = 0;
temp_string[0] = '\0';
}
if(correct_code)
{
len = strlen(temp_string);
/* cut off newline
* Use a loop to handle CR and LF just in case Windows might leave more than one character */
while((len > 0) &&
((temp_string[len - 1] == '\n') ||
(temp_string[len - 1] == '\r')))
{
len--;
temp_string[len] == '\0';
}
if(len > MAX_FLIGHTCODE_LEN)
{
correct_code = 0;
fprintf(stderr, "Input must not be longer than %d characters.\n", MAX_FLIGHTCODE_LEN);
}
if(len == 0)
{
correct_code = 0;
fprintf(stderr, "Empty input.\n");
}
}
/* check first two letters */
for(i = 0; (i < 2) && (i < len) && correct_code; i++)
{
/* you could use function isupper when you make sure the locale is set to "C" */
if((temp_string[i] < 'A') || (temp_string[i] > 'Z'))
{
correct_code = 0;
fprintf(stderr, "first two characters must be uppercase letters. Found '%c' at position %d\n", temp_string[i], i);
}
}
/* check digits starting from 3rd character */
for(i = 2; (i < MAX_FLIGHTCODE_LEN) && (i < len) && correct_code; i++)
{
/* you could use function isdigit here */
if((temp_string[i] < '0') || (temp_string[i] > '9'))
{
correct_code = 0;
fprintf(stderr, "Third to last characters must be digits. Found '%c' at position %d\n", temp_string[i], i);
}
}
if(correct_code)
{
/* we already checked that length is not more than MAX_FLIGHTCODE_LEN, so we don't need strncpy to avoid buffer overflow */
strcpy(flight->flightcode, temp_string);
printf("Valid code: %s\n", flight->flightcode);
}
else
{
fprintf(stderr, "Invalid code.\n");
}
} while(!correct_code);
return 0;
}
You have a requirement that does not fit well with what scanf can easily do, so I would stay away from it, and use fgets as a primary read utility.
But as the number of acceptable uppercase and digit characters is not fixed by only limited I would use a custom parser based on a state machine. It is probably not the most elegant nor efficient way but it is simple, robust and easy to maintain.
Just to demonstrate it, I have allowed blank characters before the first uppercase one and spaces after the last digit. So the following code accept an arbitrary long line following this regex pattern [ \t]*[A-Z]{1,maxupper}[0-9]{0,maxdigit}\s* provided it receives a buffer of size at least maxupper+maxupper+1. It returns a pointer to the buffer is successful or NULL if not.
As you have said that you could not use the ctype macros, I have defined ASCII (or any charset derived from ASCII) equivalent for the ones I have used.
#define TRUE 1
#define FALSE 0
inline int isupper(int c) {
return c >= 'A' && c <= 'Z'; // only for ASCII and derived
}
inline int isdigit(char c) {
return c >= '0' && c <= '9'; // guarantee per standard
}
inline int isblank(int c) {
return c == ' ' || c == '\t';
}
inline int isspace(int c) {
static const char spaces[] = " \t\r\n\v";
for(const char *s=spaces; *s != '\0'; s++) {
if (c == *s) return TRUE;
}
return FALSE;
}
char *get_string(char *buffer, int maxupper, int maxdigit, FILE *fd) {
char buf[16]; // any size >=2 will fit
char *cur = buffer;
int state = 0, uppersize=0, digitsize=0;
for (;;) { // allow lines longer than buf
if (NULL == fgets(buf, sizeof(buf), fd)) {
*cur = '\0'; // EOF: do not forget the terminating NULL
return state >= 1 ? buffer : NULL; // must have at least 1 char
}
for (char *b=buf; *b!='\0'; b++) {
switch(state) {
case 0: // spaces before first uppercase
if (isblank(*b)) break;
state++;
case 1: // first uppercase
if (! isupper(*b)) {
state = 5; // must read up to \n
break;
}
state++;
case 2: // process uppercase chars
if (! isupper(*b)) {
if (uppersize > 0) state++;
else {
state = 5; // must read up to \n
break;
}
}
else {
if (uppersize >= maxupper) {
state = 5; // must read up to \n
break;
}
*cur++ = *b;
uppersize++;
break;
}
case 3: // process digit chars
if (! isdigit(*b)) {
state++;
}
else {
if (digitsize >= maxdigit) {
state = 5; // must read up to \n
break;
}
*cur++ = *b;
digitsize++;
break;
}
case 4: // allow spaces after last digit
if ('\n' == *b) {
*cur = '\0';
return buffer;
}
if (! isspace(*b)) state++
break;
case 5: // on error clean end of line
if ('\n' == *b) return NULL;
}
}
}
}
Then in your code, you simply calls it that way:
...
printf("Enter flight code>\n");
if (NULL == get_string(flight->flightcode, 2, 4, stdin)) {
// process the error
...
}
...
First thing, realize that your question text is missing a question. Moreover, your question title makes no sense.
Anyway, here it is a possible, purposely very ugly, solution. Approach: you want to do X, so you write the code to do X. Let's start with scanline():
int scanline(char *dest, int dest_len)
{
int i = 0;
int ch;
while (1) {
// Read
ch = fgetc(stdin);
// Check
if (ch == EOF)
break;
if (ch == '\n')
break;
if (i >= dest_len - 1)
break;
// Use
dest[i] = ch;
++i;
}
dest[i] = 0;
// Is the string finished? Ok!
if (ch == '\n' || ch == EOF)
return 1;
// Otherwise discard the rest of the line. Not ok!
while (ch != '\n' && ch != EOF)
ch = fgetc(stdin);
return 0;
}
I know this is ugly, but I believe that it is helpful to clarify the three steps involved in file input: read, check, use. Note that it returns true if the line was up to the required number of characters (one less than the buffer size to accomodate for the terminator.
Then you want to check if:
scanline() is successful
there is at least one character.
character 0 is between 'A' and 'Z'
character 1 is between 'A' and 'Z'
character 2 is between '0' and '1'
character 3 is between '0' and '1'
character 4 is between '0' and '1'
character 5 is between '0' and '1'
Lets write the code for that:
int main(void)
{
flight_t flight;
while (1) {
printf("Enter flight code>\n");
if (!scanline(flight.flightcode, sizeof(flight.flightcode))) {
printf("Too many characters.\n");
continue;
}
int i = 0;
if (flight.flightcode[i] == 0) {
printf("Empty input.\n");
continue;
}
if (flight.flightcode[i] < 'A' || flight.flightcode[i] > 'Z') {
printf("Character %d is not upper case.\n", i);
continue;
}
i++;
if (flight.flightcode[i] == 0)
break;
if (flight.flightcode[i] < 'A' || flight.flightcode[i] > 'Z') {
printf("Character %d is not upper case.\n", i);
continue;
}
i++;
if (flight.flightcode[i] == 0)
break;
if (flight.flightcode[i] < '0' || flight.flightcode[i] > '9') {
printf("Character %d is not a digit.\n", i);
continue;
}
i++;
if (flight.flightcode[i] == 0)
break;
if (flight.flightcode[i] < '0' || flight.flightcode[i] > '9') {
printf("Character %d is not a digit.\n", i);
continue;
}
i++;
if (flight.flightcode[i] == 0)
break;
if (flight.flightcode[i] < '0' || flight.flightcode[i] > '9') {
printf("Character %d is not a digit.\n", i);
continue;
}
i++;
if (flight.flightcode[i] == 0)
break;
if (flight.flightcode[i] < '0' || flight.flightcode[i] > '9') {
printf("Character %d is not a digit.\n", i);
continue;
}
i++;
if (flight.flightcode[i] == 0)
break;
}
}
Some remarks:
in your code you set correct_code to 1 as soon as the first character was ok. If you want to loop through the characters you must check if there is an error and exit the loop.
don't use ASCII codes when you have the specific character literals available.
I suggest that you take my solution and, as an exercise fix it to be able to work with arbitrary MAX_FLIGHTCODE_LEN, and possibly with arbitrary number of letters and numbers. Of course MAX_FLIGHTCODE_LEN shall be equal to their sum!
Drop the useless requirement for not using <ctype.h>, and use also <stdbool.h>, which makes the programmer intention clearer.
I am trying to convert a string of numerical characters to their corresponding integral form. Please suggest what is wrong with the code. I would like to stick with pointers. I understand that the pointer str points to the first character in my string. So, each time I call my function in the loop, I want the pointer to increment by 1, and add the value of the character to one node in my array. For some reason, though I am unable to do so. Here is the code.
#include <stdio.h>
#include <string.h>
#include <malloc.h>
#include <stdlib.h>
int ctoi(char *c);
int main (void)
{
char *str;
int A[20];
int i = 0;
str = (char*) malloc(20 * sizeof(char));
printf("Input the string. ");
scanf("%s", str);
while(str != '\0')
{
A[i] = ctoi(str);
i++;
str++;
}
for(i = 0; i < strlen(str); i++)
printf("%d", A[i]);
getchar();
getchar();
return 0;
}
int ctoi(char *c)
{
int a;
a= *c - '0';
return a;
}
for (i=0;i<strlen(str);i++)
printf("%d", A[i]);
Here strlen will return 0 because you updated str in your previous loop .Replace it with :
for(i=0;i<len;i++)
where len is the length of your input string .Find it before using str in while loop
while(str!='\0') should be `while(*str!='\0')`
. You will get it . But for writing your own atoi function you dont need to store the number in an array
Please try this it works, the myatoi() function was lifted perhaps 20 years ago from the classic "THE C PROGRAMMING LANGUAGE" , get the book.
#include <stdio.h>
main()
{
char temp[99];
strcpy(temp , "34");
printf( "\n %d " , myatoi(temp));
strcpy( temp , "8642");
printf( "\n %d " , myatoi(temp));
}
int myatoi( char s[])
{
int i,n,sign;
// skip white space
for( i=0 ; s[i]==' ' || s[i]=='\n' ||s[i]=='\t';i++) ;
sign=1;
if( s[i]=='+' || s[i]=='-')
sign=( s[i++]=='+' ? 1 : -1 );
for( n=0; s[i]>='0' && s[i]<='9' ; i++)
n=10*n+s[i]-'0' ;
return(sign*n);
}
OP's code needs a few (at least 2) fixes to mostly work. See ***
int main (void)
{
char *str;
int A[20];
int i = 0;
// *** Cast not needed, '* sizeof(char)' not needed
str = malloc(20);
printf("Input the string. ");
scanf("%s", str);
// ***
char *str_original = str;
while(*str != '\0')
{
A[i] = ctoi(str);
i++;
str++;
}
// ***
str = str_original;
for(i = 0; i < strlen(str); i++)
printf("%d", A[i]);
// ***
free(str); // Good to return memory
str = NULL;
getchar();
getchar();
return 0;
}
A simple way to convert a string to an int
int strtoi(const char *s) {
int sum = 0;
char ch;
char sign = *s;
if (*s == '-' || *s == '+') s++;
while ((ch = *s++) >= '0' && ch <= '9') {
sum = sum * 10 - (ch - '0');
}
if (sign != '-') {
sum = -sum;
}
return sum;
}
Notes: This code accumulates the sum on the negative side of 0 to avoid UB when trying to parse the string for INT_MIN. Modified code could skip leading white-space, add text error detection, overflow detection, etc.
Here is my custom atoi funtion, who handle unsigned int with debug gestion:
int my_getnbr(char *str)
{
int nb;
int sign;
int i;
nb = 0;
sign = 0;
i = -1;
if (!str)
return (0);
while (str[++i])
if (str[i] < '0' && str[i] > '9' && str[i] != '-' && str[i] != '+')
return (0);
i = 0;
while (str[i] != '\0' && (str[i] == '-' || str[i] == '+'))
if (str[i++] == '-')
++sign;
while (str[i] && (str[i] >= '0' && str[i] <= '9'))
{
nb = (nb * 10) + (str[i++] - '0');
if (str[i] == ' ')
i++;
}
return (((sign % 2) == 1) ? ((nb) * (-1)) : (nb));
}
tested with that main:
int main()
{
printf("%d\n", my_getnbr("-42"));
printf("%d\n", my_getnbr("-+-+--42"));
printf("%d\n", my_getnbr("-0"));
printf("%d\n", my_getnbr("590310"));
return (0);
}
No leaks, here is the result:
-42
42
0
590310
Firstly
while(str!='\0') should be
while(*str!='\0')
You should compare the content, not the address.
And while printing the returned data, you are doing
for(i=0;i<strlen(str);i++)
printf("%d", A[i]);
str already parsed till the last. So length would probably be 0.
Change your while loop to
while(*str!='\0')
{
A[i]=ctoi(*str);
i++;
str++;
}
And your function to
int ctoi(char c)
{
int a;
a= c-'0';
return a;
}
There are several approaches for a simple atoi replacement without the base conversion flexibility in strtol. The simplest is generally to find the length of the string to convert, and then work backward toward the front of the string preforming the conversion from string to integer as you go. A quick example would be:
/* a quick atoi replacement */
int atoi2 (char *s)
{
int nmax = (1ULL << 31) - 1; /* INT_MAX */
long long n = 0; /* the number to return */
size_t m = 1; /* multiplier for place */
size_t l = 0; /* length of string */
char *p = s;
while (*p++) l++; /* get string length */
p -= 2; /* position at last char */
while (l--) /* for each char in string */
{ /* verify a digit or '-' sign */
if ((*p >= '0' && *p <= '9') || *p == '-')
{
if (*p == '-') { /* if '-' is first char */
if (p == s) n = -n; /* negate value */
}
else { /* otherwise normal conversion */
n += (*p - '0') * m;
if (n > nmax) { /* prevent overflow */
fprintf (stderr, "atoi2() error: conversion > INT_MAX.\n");
exit (EXIT_FAILURE);
}
m *= 10;
}
}
p--;
}
return (int) n;
}
A simple driver program to test could be:
#include <stdio.h>
#include <stdlib.h>
int atoi2 (char *s);
int main (int argc, char **argv) {
if (argc < 1) return 1;
printf ("\n string : %s, conversion : %d\n\n",
argv[1], atoi2 (argv[1]));
return 0;
}
Example Use/Output
$ ./bin/atoi2 321
string : 321, conversion : 321
$ ./bin/atoi2 -321
string : -321, conversion : -321
$ ./bin/atoi2 2147483647
string : 2147483647, conversion : 2147483647
$ ./bin/atoi2 2147483648
atoi2() error: conversion > INT_MAX.
If you have any questions, please do not hesitate to ask.
Here is a custom atoi function that avoids using most of the standard library functions
/*** _atoi - finds the first set of integers in a given string
* #s: string entered
* Return: first number sequence
**/
int _atoi(char *s)
{
int length = 0, negativeCount = 0, count = 0, num = 0;
while (s[length] != '\0')
{
length++;
}
while (count < length)
{
if (s[count] == '-')
{
negativeCount++;
}
if (s[count] >= 48 && s[count] <= 57)
{
/* ascii values for numbers */
for (; s[count] >= 48 && s[count] <= 57; count++)
{
num = (10 * num - (s[count] - 48));
}
break;
}
count++;
}
if (negativeCount % 2 != 0)
{
return (num);
}
else
{
return (-num);
}
}
How do you remove spaces and special characters from a string?
I couldn't find a single answer while googling. There were a lot related to other languages, but not C. Most of them mentioned the use of regex, which isn't C standard (?).
Removing a simple space is easy:
char str[50] = "Remove The Spaces!!";
Then a simple loop with a if-statement:
if (str[i] != ' ');
Output would be:
RemoveTheSpaces!!
What do I add to the if-statement so it would recognize special characters and remove them?
My definition of special characters:
Characters not included in this list:
A-Z a-z 0-9
This is probably not the most efficient way of achieving this but it will get the job done fairly fast.
Note: this code does require you to include <string.h> and <ctype.h>
char str[50] = "Remove The Spaces!!";
char strStripped[50];
int i = 0, c = 0; /*I'm assuming you're not using C99+*/
for(; i < strlen(str); i++)
{
if (isalnum(str[i]))
{
strStripped[c] = str[i];
c++;
}
}
strStripped[c] = '\0';
There are millions of different ways this can be done. Here is just one example that is not using any additional storage and performs the removal of unneeded characters "in-place":
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
static void my_strip(char *data)
{
unsigned long i = 0; /* Scanning index */
unsigned long x = 0; /* Write back index */
char c;
/*
* Store every next character in `c` and make sure it is not '\0'
* because '\0' indicates the end of string, and we don't want
* to read past the end not to trigger undefined behavior.
* Then increment "scanning" index so that next time we read the
* next character.
*/
while ((c = data[i++]) != '\0') {
/* Check if character is either alphabetic or numeric. */
if (isalnum(c)) {
/*
* OK, this is what we need. Write it back.
* Note that `x` will always be either the same as `i`
* or less. After writing, increment `x` so that next
* time we do not overwrite the previous result.
*/
data[x++] = c;
}
/* else — this is something we don't need — so we don't increment the
`x` while `i` is incremented. */
}
/* After all is done, ensure we terminate the string with '\0'. */
data[x] = '\0';
}
int main()
{
/* This is array we will be operating on. */
char data[512];
/* Ask your customer for a string. */
printf("Please enter a string: ");
if (fgets(data, sizeof(data), stdin) == NULL) {
/* Something unexpected happened. */
return EXIT_FAILURE;
}
/* Show the customer what we read (just in case :-)) */
printf("You have entered: %s", data);
/*
* Call the magic function that removes everything and leaves
* only alphabetic and numberic characters.
*/
my_strip(data);
/*
* Print the end result. Note that newline (\n) is there
* when we read the string
*/
printf("Stripped string: %s\n", data);
/* Our job is done! */
return EXIT_SUCCESS;
}
I put a lot of comments in there so hopefully the code doesn't need explanation. Hope it helps. Good Luck!
This is just a silly suggestion.
char ordinary[CHAR_MAX] = {
['A']=1,['B']=1,['C']=1,['D']=1,['E']=1,['F']=1,['G']=1,['H']=1,['I']=1,
['J']=1,['K']=1,['L']=1,['M']=1,['N']=1,['O']=1,['P']=1,['Q']=1,['R']=1,
['S']=1,['T']=1,['U']=1,['V']=1,['W']=1,['X']=1,['Y']=1,['Z']=1,
['a']=1,['b']=1,['c']=1,['d']=1,['e']=1,['f']=1,['g']=1,['h']=1,['i']=1,
['j']=1,['k']=1,['l']=1,['m']=1,['n']=1,['o']=1,['p']=1,['q']=1,['r']=1,
['s']=1,['t']=1,['u']=1,['v']=1,['w']=1,['x']=1,['y']=1,['z']=1,
['0']=1,['1']=1,['2']=1,['3']=1,['4']=1,['5']=1,['6']=1,['7']=1,['8']=1,
['9']=1,
};
int is_special (int c) {
if (c < 0) return 1;
if (c >= CHAR_MAX) return 1;
return !ordinary[c];
}
void remove_spaces_and_specials_in_place (char *str) {
if (str) {
char *p = str;
for (; *str; ++str) {
if (!is_special(*str)) *p++ = *str;
}
*p = '\0';
}
}
Using your if statement:
if (str[i] != ' ');
With a little logic (the characters have to be in the range a-z or A-Z or 0-9:
If ( !('a' <= str[i] && 'z' >= str[i]) &&
!('A' <= str[i] && 'Z' >= str[i]) &&
!('0' <= str[i] && '9' >= str[i])) then ignore character.
This is Ascii Code Range
Char:Dec
0:48, 9:57
A:65, Z:90
a:97, z:122
try this:
char str[50] = "Remove The Spaces!!";
int i =0;
for(; i<strlen(str); i++)
{
if(str[i]>=48 && str[i]<=57 || str[i]>=65 && str[i]<=90 || str[i]>=97 && str[i]<=122)
//This is equivalent to
//if(str[i]>='0' && str[i]<='9' || str[i]>='A' && str[i]<='Z' || str[i]>='a' && str[i]<='z')
printf("alphaNumeric:%c\n", str[i]);
else
{
printf("special:%c\n", str[i]);
//remove that
}
}
#include <stdio.h>
#include <string.h>
main()
{
int i=0, j=0;
char c;
char buff[255] = "Remove The Spaces!!";
for(; c=buff[i]=buff[j]; j++){
if(c>='A' && c<='Z' || c>='a' && c<='z' || c>='0' && c<='9'){
i++;
}
}
printf("char buff[255] = \"%s\"\n", buff);
}
include < stdio.h >
int main()
{
char a[100];
int i;
printf("Enter the character : ");
gets(a);
for (i = 0; a[i] != '\0'; i++) {
if ((a[i] >= 'a' && a[i] <= 'z') || (a[i] >= 'A' && a[i] <= 'Z')
|| (a[i] - 48 >= 0 && a[i] - 48 <= 9)) {
printf("%c", a[i]);
} else {
continue;
}
}
return 0;
}