简体   繁体   中英

Atoi() and strtol() not working correctly in C

Basically I want to check if the time that I wrote is valid or not I typed this string: 20:40:30 and I get as a result: No

When I debugged the problem it turned out that the atoi is not working correctly.

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

int main() {
    char Input[20] = { '\0' };
    scanf("%s", &Input);

    char sub1[2] = { '\0' };
    char sub2[2] = { '\0' };
    char sub3[2] = { '\0' };

    strncpy(sub1, Input, 2);
    strncpy(sub2, Input + 3, 2);
    strncpy(sub3, Input + 6, 2);

    int H = atoi(sub1);
    int M = atoi(sub2);
    int S = atoi(sub3);

    int count = 0;
    if (H >= 0 && H < 24) count++;
    if (M >= 0 && M < 60) count++;
    if (S >= 0 && S < 60) count++;

    if (count == 3)
        printf("Yes);
    else
        printf("No");

    return 0;
}

I tried strtol too and still the same problem.

There are multiple problems in your code:

  • the arrays into which you copy the string fragments are not long enough to hold 2 characters plus a null terminator.
  • strncpy() does not set a nul terminator in the destination if the source string has at least as many characters as the size argument specifies. Making the destination arrays longer and initializing the to 0 would suffice to solve the problem here, but the semantics strncpy() are confusing and error prone so it would be best to avoid using the function.
  • you do not verify the actual contents of the string: "1x+ 2=3b" would be considered correct as well as "abcdefgh" because you only check that the numbers if any starting at offsets 0, 3 and 6 are in the proper range.

Here is a more effective verification:

#include <stdio.h>
#include <stdlib.h>

int main() {
    char Input[20], sub1[3], sub2[3], sub3[3];
    int pos;
    char c;

    /* read a string of at most 19 characters */
    if (scanf("%19s", Input) != 1) {
        printf("No: input error\n");
        return 1;
    }
    /* extract 3 fields of at most 2 digits separated by ':'
     * verify that all characters have been consumed
     * verify that 8 characters have been consumed 
     */
    if (sscanf(Input, "%2[0-9]:%2[0-9]:%2[0-9]%n%c", sub1, sub2, sub3, &pos, &c) != 3 || pos != 8) {
        printf("No: format error\n");
        return 1;
    }
    int H = atoi(sub1);
    int M = atoi(sub2);
    int S = atoi(sub3);

    /* no need to test for negative values since we already verified
     *  that the fields have 2 digits
     */
    if (H < 24 && M < 60 && S < 60)
        printf("Yes\n");
    else
        printf("No: values out of range\n");

    return 0;
}

strncpy() does not place the final '\0' when the max number of characters is reached.
You have to place it manually, and ensure there is enough storage for it.
(of course, if the resulting buffer is already filled with zeros you don't have to place it explicitly, but in the general case you have to ensure that)

In your attempt, atoi() will find anything after the two characters you copied; this is a buffer overrun and this sequence of character will probably not look like an integer.

/**
  gcc -std=c99 -o prog_c prog_c.c \
      -pedantic -Wall -Wextra -Wconversion \
      -Wc++-compat -Wwrite-strings -Wold-style-definition -Wvla \
      -g -O0 -UNDEBUG -fsanitize=address,undefined
**/

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

int main(void)
{
     char Input[20]={'\0'};
     scanf("%s",Input);


     char sub1[3]={'\0'}; // 2 --> 3 for the final '\0'
     char sub2[3]={'\0'}; // note that since these arrays are partially
     char sub3[3]={'\0'}; // initialised, they contain some zeros in the
                          // remaining locations.


     strncpy(sub1,Input,2);
     sub1[2]='\0'; // useless here since sub1 is filled with zeros
     strncpy(sub2,Input+3,2);
     sub2[2]='\0'; // useless here since sub2 is filled with zeros
     strncpy(sub3,Input+6,2);
     sub3[2]='\0'; // useless here since sub3 is filled with zeros


     int H=atoi(sub1);
     int M=atoi(sub2);
     int S=atoi(sub3);

     int count=0;
     if (H>=0 && H<24)count++;
     if (M>=0 && M<60)count++;
     if (S>=0 && S<60)count++;

    if (count==3)printf("Yes\n");
    else printf("No\n");


return 0;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM