0

I'm trying to make a calculator that takes a void pointer called yourVal, look at the first byte and decide if it's a '*' or '/'. Based on the sign, i multiply bytes 3+4, 5+6, and 7+8. say i have *1234567. I multiply 23 * 45 * 67. With the division, I divide byte 5(45) by byte 3(23). I'm a novice with pointers in C, and I really have no idea how to even set a value to a void pointer. When I do the following in main

void *yourVal;
*yourVal = "*1234567";
printf("%s\n", yourVal);

I'm not able to dereference a void pointer. But I tried with a char pointer, and I have the same issue. This is my code for the calculator function. Based on whether I use printf or not, I get different results.

int calculator(void *yourVal){
  char *byteOne;
  short int *byteThree, *byteFive, *byteSeven;
  int value;

  byteOne = (char *)yourVal;
  byteThree = (short int *)yourVal+2;
  byteFive = (short int *)yourVal+4;
  byteSeven= (short int *)yourVal+6;

  if(*byteOne == '*') {
    value = *byteThree * *byteFive * *byteSeven;
    printf("You multiplied\n");
  }
  else if(*byteOne == '/') {
    if (*byteThree == 0) {
        value = 0xBAD;
        printf("Your input is invalid\n");
    }
    else {
        value = *byteFive / *byteThree;
        printf("You divided\n");
    }
  }
  else {
    value = 0xBAD;
    printf("Your input is invalid\n");
  }
}

The division isn't working at all, and the multiplication only grabs one digit. Any tips would be appreciated. I looked at various sources but I'm not seeing how to work with void pointers efficiently. Also, I can't use any library functions other than printf, and this is a school assignment, so try not to give too many spoilers or do it for me. We were given one hint, which is to cast yourVal to a structure. But I'm lost on that. Thanks

Avallauch
  • 65
  • 2
  • 11
  • 2
    If `yourVal` is the string `"1+2+3"`, when you assign `byteThree = (short int*)yourVal + 2` it absolutely does not do what you think it does. If you want to convert the character `2` to the integer value 2, you can't just cast. (The character `2` is very likely the integer 50, although that depends on the character set being used.) – William Pursell Sep 22 '17 at 06:21
  • 3
    Why do you use a void pointer in the first place? It seems obvious that you are working with `char`s. – M Oehm Sep 22 '17 at 06:21
  • That's the parameter we are given to write the function. They probably have some test cases that need to use void pointers, i dont know. – Avallauch Sep 22 '17 at 06:26
  • You should consider using `sscanf(input, "%d%n", &number, &bytes_read)` for extracting numbers out of your input. – Ajay Brahmakshatriya Sep 22 '17 at 06:27
  • we can only use printf for this assignment. – Avallauch Sep 22 '17 at 06:28
  • 1
    It then is not a `void*` but a `char*` (or you should cast to one) since you are looking at the first *character* ; for example, looking at the first character of some address of a `double` is useless (and implementation specific) – Basile Starynkevitch Sep 22 '17 at 06:33
  • 1
    Compile with all warnings and debug info `gcc -Wall -Wextra -g` with [GCC](http://gcc.gnu.org/) and **use the debugger** `gdb` – Basile Starynkevitch Sep 22 '17 at 06:34
  • 1
    [sample code](https://ideone.com/7miKwe) – BLUEPIXY Sep 22 '17 at 06:34
  • Thank you all, GDB works for me but im on windows, and not having src or asm layouts on my current debugger kind of hinders things with my current knowledge. I thought I was trying to cast to a char*, at least with the first value? – Avallauch Sep 22 '17 at 06:40

2 Answers2

1
byteOne = (char *)payload;
byteThree = (short int *)yourVal+2;
byteFive = (short int *)yourVal+4;
byteSeven= (short int *)yourVal+6;

This doesn't do what you think it does. If you want to read the numbers at these positions, you need to do something like.

char* Value = yourValue;
unsigned byteOne, byteThree, byteFive, byteSeven;
byteOne = Value[0] - '0';
byteThree = Value[2] - '0';
byteFive = Value[4] - '0';
byteSeven = Value[6] - '0';

What I have done here is read the byte at that position and subtract the ASCII value of '0' to get the numerical value of that character. But again this will work only for a single character.

If you need to read more characters you will have to use library functions like sscanf or atoi.

Ajay Brahmakshatriya
  • 8,993
  • 3
  • 26
  • 49
  • We are supposed to grab a short int at each byte, which I'm supposing means 16 bits or two chars. But we are also told not to use any library functions. I'm not sure how I would grab two bytes and put them into an int out of a void pointer. The subtraction of '0' does help, though, I will be using that at some point I am sure. – Avallauch Sep 22 '17 at 06:37
  • @Avallauch I think you are getting confused between decimal characters and byte representation. Yes, unsigned short does mean 16 bits (or 2 bytes) but its maximum can go upto 65536. If you just read 2 characters from the input, the maximum can be 99. Because it is represented as decimal. If you want to actually read a short from a string input(which can be upto 5 digits), you need to use `atoi`. – Ajay Brahmakshatriya Sep 22 '17 at 06:40
  • 1
    @Avallauch also you called your variable `payload`. Is this data coming over network? In that case it might not be decimal encoded but in raw binary. The parsing strategy will be completely different in that case. – Ajay Brahmakshatriya Sep 22 '17 at 06:41
  • So, essentially they are asking for multiplication of any value stored in that memory? It says "return the product of 3 short ints starting at the bytes 3, 5, and 7. – Avallauch Sep 22 '17 at 06:44
  • @Avallauch I am a bit confused what you actually want now. Can you post the entire question? – Ajay Brahmakshatriya Sep 22 '17 at 06:46
  • No, this isn't over a network. They just run a test main on it. – Avallauch Sep 22 '17 at 06:47
  • if the first byte in yourval is character '*', return product of 3 short ints starting at bytes 3,5, and 7. If the first byte is a character '/', return the quotient when you divide int (not short int) at byte 5 by short int at byte 3. if short int at byte 3 is 0, return 0xbad.You can cast yourval to appropriate struct. byte 1 is at &yourval, and so on. – Avallauch Sep 22 '17 at 06:48
  • 1
    @Avallauch I have a feeling that the input in __not__ decimal encoded in the question. The input has the raw bytes of a `unsigned short`. You need to confirm this with your instructor. Better ask them for a sample input. – Ajay Brahmakshatriya Sep 22 '17 at 06:51
  • Yes, the question seems to be asking something closer to... unsigned char *yourVal_m = {'*',0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08}; // Multiply 0x0304 * 0x0506 * 0x0708 unsigned char *yourVal_d = {'/',0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08}; // Divide 0x05060708 / 0x0304 – B. Wolf Sep 22 '17 at 07:05
  • That looks more like it. Thanks for the visualization. – Avallauch Sep 22 '17 at 19:57
0
  • The void pointer adds no functionality you need to solve this problem, it just complicates things. Use a char pointer instead.
  • "*1234567" is a string, not an array of integers. You cannot treat it as an array of integers. Each character would have to be converted to an integer before you do arithmetic. The easiest way to do that is to subtract by the ASCII character '0'.
  • "...i multiply bytes 3+4..." When counting bytes, you always start at 0. In the string "*1234567", the 2 is the byte with index 2 not 3.
  • "Based on the sign, i multiply bytes 3+4, 5+6, and 7+8. say i have *1234567. I multiply 23 * 45 * 67. With the division, I divide byte 5(45) by byte 3(23)"
    I fail to see how this algorithm makes any sense. What is the 1 there for? Why aren't you using some conventional formatting such as prefix, postfix or just plainly typed-out equations?

Example:

int calculator (const char* yourVal)
...

int byte2 = yourVal[2] - '0';
Lundin
  • 195,001
  • 40
  • 254
  • 396