1

I'm currently working on a homework and can't get the result I want from the code below.

#include <stdio.h>

int main() {
    int base, num, x, y, z, t, choice;
    char hexa = 0, a, b, c, d, k, l, m, n, h, g, f, v;

    switch (hexa) {
    case 'A':
        num = 10;
        break;
    case 'B':
        num = 11;
        break;
    case 'C':
        num = 12;
        break;
    case 'D':
        num = 13;
        break;
    case 'E':
        num = 14;
        break;
    case 'F':
        num = 15;
        break;
    }

    printf("Please enter the base:\n");
    scanf("%d", &base);

    if (base == 10) {
        printf("Please enter your ip address:\n");
        scanf("%c.%c.%c.%c", &a, &b, &c, &d);

        //if((a<0 || a>255) && (b<0 || b>255) && (c<0 || c>255) && (d<0 || d>255)){ //FIX THIS
        //  printf("Sorry, that is not a valid address!");}
        printf("Please enter the sub-net mask\n"); //Skips this line
        scanf("%d.%d.%d.%d", &x, &y, &z, &t);
    }
    else if (base == 16) {
        printf("Enter your ip address\n");
        scanf("%c.%c.%c.%c", &k, &l, &m, &n);
        printf("Enter the subnet mask\n");
        scanf("%c.%c.%c.%c", &h, &g, &f, &v);
    }

    scanf("%d", &choice);

    if (choice == 1) { //there is a part that asks which 
        printf("%c.%c.%c.%c", a, b, c, d); //prints only dots
    }
    else if (choice == 2) {}
    else if (choice == 3) {}
    else if (choice == 4) {}
    else if (choice == 5) {}
    else if (choice == 6) {}

    return 0;
}

So basically I'm trying to get an IP and subnet and convert it to binary but as instructed I can't use bitwise shift and %x to get the IP address as base 16. The problem is when I try to print the IP address given printf only prints dots and nothing else. And also one of the skips the subnet mask scanf. I would be really glad if I can get some help from you guys as I don't have many friends to ask questions. Thanks.

EDIT: I don't know if anyone is going to face this problem but my solution was rather silly but it works. You basically take the input as scanf("%c%c.%c%c.%c%c.%c%c%c"), the last %c is for the enter as char takes enter as input.

chqrlie
  • 131,814
  • 10
  • 121
  • 189
Kaya
  • 21
  • 6
  • 1
    `char hexa = 0` does not match any `switch` `case` and so `int num` remains *uninitialised*. Edit: `num` isn't used, what is that `switch` business for? – Weather Vane Mar 12 '19 at 20:00
  • 1
    How are the three digits `192` of an address like `192.168.0.1` supposed to fit into a `char`? – Kaz Mar 12 '19 at 20:01
  • @kaya - A char can hold a value between 0 an 256 (slightly different in unsigned but the range is the same – Ed Heal Mar 12 '19 at 20:17
  • 1
    `int main(void)` – William Pursell Mar 12 '19 at 20:21
  • @WilliamPursell - Why the `void` - not required – Ed Heal Mar 12 '19 at 20:24
  • 2
    @EdHeal [about void](https://stackoverflow.com/questions/41803937/func-vs-funcvoid-in-c99) – Michail Mar 12 '19 at 20:45
  • You might try to explain the code to your pet or [Rubber duck](https://rubberduckdebugging.com/) – Gerhardh Mar 12 '19 at 20:51
  • What is your exact input and output? You do not check return value of `scanf`. I would assume that the value is less than it should be. This would indicate a bunch of uninitialized variables for your `printf` – Gerhardh Mar 12 '19 at 20:51
  • 2
    Switch statement not required. Perahps an `if` statement and `num = heax - 'A' + 10` would be simplier – Ed Heal Mar 12 '19 at 20:57
  • @WeatherVane Well, I should written it but because i cant use %x to get hexadecimal input I thought it is necessary to use switch statements. – Kaya Mar 12 '19 at 21:47
  • @Gerhardh I'm sorry english is not my main language but I will try to give a reasonable answer because I couldn't fully understand you. The input is let's say 192.168.1.1 as scanf("%c.%c.%c.%c", &a, &b, &c, &d) so when i try to output this as printf("%c.%c.%c.%c", a, b, c, d) I get "...". – Kaya Mar 12 '19 at 21:51
  • %c does not fit for "192". Check return value of scanf. – Gerhardh Mar 12 '19 at 21:53
  • The first `%c` will read the first digit which is the `1` of `192`. – Weather Vane Mar 12 '19 at 21:57
  • @Gerhardh Actually anything more than 9.9.9.9 outputs (55.55.55.55) outputs something like 5. . .8 as you said 192 is not fit for char so what can i use? I am specially trying to use chars to check them later on if the user inputs anything in base 16. By the way I'm really sorry if I say silly things but I'm completely new to these stuff and honestly this assignment is a bit too hard i think. – Kaya Mar 12 '19 at 22:07
  • 1
    Use `%d.%d.%d.%d` and pass the addresses of 4 `int` variables. Worry about why you (think you) need `char` later. Or, input one string with `%s` and analyse it at your leisure. – Weather Vane Mar 12 '19 at 22:11
  • @WeatherVane It makes sense to use int variables for base 10. However if the user inputs FF printf("%c.%c.%c.%c", a, b, c, d) prints out F . . .8 I can't see any solutions for :(. By the way it is forbidden to use strings either. – Kaya Mar 12 '19 at 22:20
  • 1
    `%c` does not read either decimal or hexadecimal. It reads a single character. One `%c` - one character. As above: input one string with `%s` and analyse it at your leisure. Incidentally I am curious as to how you would decide whether, say, `12` is decimal or hexadecimal. – Weather Vane Mar 12 '19 at 22:45
  • @WeatherVane the base is selected before entering the IP address. – Gerhardh Mar 13 '19 at 04:48
  • @Gerhardh Well as I said the problem is I cant use %x, it is prohibited – Kaya Mar 13 '19 at 15:07
  • Sorry. missed that. – Gerhardh Mar 13 '19 at 15:07
  • If you cannot use %x in scanf then you'll have to read and parse the stream yourself. Get one character, if it is between '0' and '9' subtract '0' from it otherwise use your switch block. Set your integer to it. Get the next character. Multiply value by your base, add the integer value of your character. When you hit a dot move to the next variable. – Zan Lynx Mar 17 '19 at 02:12

2 Answers2

0

Hi and welcome to stackoverflow !

My answer will only help you about the base 16 part because you can easily do the base 10 based on what you already achieved and some hints i'm giving to you.

Parsing using base 16

Like you mentioned, you can't use %x to retrieve the IP address so another possibility is to use strings. An IP address is digits from 0 to 255 so you can expect hex characters from 0x00 to 0xFF.

To me, the best way to achieve that is to use a scanset with the scanf function:

scanf("%2[0-9A-F]", str);

Pattern %2[0-9A-F] means scanf is expecting at most two characters that must be any digits or any capital letters between A and F (so any hex character). Note, str length must be 3 to store 2 characters + the null terminator \0.

Then, str buffer will be filled with ASCII characters being a hex representation of the IP address. You can use the strtol function to convert a hex-representation-string to an integer.

The full code is below:

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

#define DIGIT_SIZE 3 // 2 hex digit + null character

int main(void) {

    char d1[DIGIT_SIZE];
    char d2[DIGIT_SIZE];
    char d3[DIGIT_SIZE];
    char d4[DIGIT_SIZE];

    scanf("%2[0-9A-F].%2[0-9A-F].%2[0-9A-F].%2[0-9A-F]", d1, d2, d3, d4);

    printf("hex ip:[%s.%s.%s.%s]\n", d1, d2, d3, d4);

    int i1 = (int)strtol(d1, NULL, 16);
    int i2 = (int)strtol(d2, NULL, 16);
    int i3 = (int)strtol(d3, NULL, 16);
    int i4 = (int)strtol(d4, NULL, 16);

    printf("dec ip:[%d.%d.%d.%d]\n", i1, i2, i3, i4);

    return 0;
}

Few tries on my side:

$ 8.8.8.8  
$ hex ip:[8.8.8.8]
$ dec ip:[8.8.8.8]

$ A.B.C.D
$ hex ip:[A.B.C.D]
$ dec ip:[10.11.12.13]

$ FF.FF.FF.FF
$ hex ip:[FF.FF.FF.FF]
$ dec ip:[255.255.255.255]

$ 0.0.0.0
$ hex ip:[0.0.0.0]
$ dec ip:[0.0.0.0]
Martin
  • 877
  • 8
  • 20
  • Hey Martin, I thank you for your answer and apologize if I didn't mention this before but I can't use strings as well as define. I kinda think this hw is unnecessary but the instructor insists on these terms saying they will be helpful later on. Today when I was trying to remember the things she told us, I remembered she talked about buffer. But still can't predict how to get base 16 input without using any of these. – Kaya Mar 14 '19 at 00:00
  • As you may know, in C a string is a buffer of character. Let's wait some more information from your teacher then – Martin Mar 14 '19 at 19:07
0

There are multiple problems in your code:

  • The switch statement is useless as hexa has a constant value and num is not used anyway.

  • You should parse decimal numbers with %d, %u or %i and hexadecimal numbers with %x.

  • If you insist on storing le IP selectors as bytes, you should use unsigned char instead of plain char and use %hhu and %hhx respectively.

  • The test for number validity is incorrect, it is an error to have any number outside the range 0..255, so || is required between all tests.

  • you should print the IP components with %d, not %c: %c output characters, not numbers. These characters probably are not printable, so only the dots appear.

Here is a modified version:

#include <stdio.h>

int main() {
    int base, a, b, c, d, x, y, z, t, n, choice;

    printf("Please enter the base: ");
    if (scanf("%d", &base) != 1)
        return 1;

    if (base != 10 && base != 16) {
        printf("invalid base\n");
        return 1;
    }

    printf("Please enter your IP address: ");
    if (base == 10) {
        n = scanf("%d.%d.%d.%d", &a, &b, &c, &d);
    } else {
        n = scanf("%x.%x.%x.%x", &a, &b, &c, &d);
    }
    if (n != 4) {
        printf("invalid input\n");
        return 1;
    }
    if (a < 0 || a > 255 || b < 0 || b > 255 || c < 0 || c > 255 || d < 0 || d > 255) {
        printf("invalid IP address\n");
        return 1;
    }
    printf("Please enter the sub-net mask: ");
    if (base == 10) {
        n = scanf("%d.%d.%d.%d", &x, &y, &z, &t);
    } else {
        n = scanf("%x.%x.%x.%x", &x, &y, &z, &t);
    }
    if (n != 4) {
        printf("invalid input\n");
        return 1;
    }
    if (x < 0 || x > 255 || y < 0 || y > 255 || z < 0 || z > 255 || t < 0 || t > 255) {
        printf("invalid sub-net mask\n");
        return 1;
    }

    if (scanf("%d", &choice) != 1) {
        printf("invalid input\n");
        return 1;
    }
    switch (choice) {
      case 1:
        printf("%d.%d.%d.%d\n", a, b, c, d);
        break;
      case 2:
      case 3:
      case 4:
      case 5:
      case 6:
        break;
    }
    return 0;
}

Note that there is a way to compact the validity test:

    if (((a | b | c | d) & ~255U) {
        printf("invalid IP address\n");
        return 1;
    }
chqrlie
  • 131,814
  • 10
  • 121
  • 189