Categories


Archives


Recent Posts


Categories


Just Enough C for PHP: Using C Variables

astorm

Frustrated by Magento? Then you’ll love Commerce Bug, the must have debugging extension for anyone using Magento. Whether you’re just starting out or you’re a seasoned pro, Commerce Bug will save you and your team hours everyday. Grab a copy and start working with Magento instead of against it.

No Frills Magento Layout is the only Magento front end book you'll ever need. Get your copy today!

Last time we ambushed you with a bunch of information about how C manages memory when you declare variables in your programs. Today we’re going to stick to int, float, and char variables, but get into the nitty gritty of actually using them.

To start, let’s consider our original hello world program.

#include<stdio.h>

int main()
{
    printf("Hello World\n");
    return 0;
}

This program uses a function named printf. The f in printf stands for format. While you can use printf to print a string (as we have above), the real power of printf is in its ability to print strings and format them using values provided by variables.

This might make more sense using code. Consider the following program

#include<stdio.h>

int main()
{
    printf("Our variable contains the value %i\n", 42);
    return 0;
}

If you compile and run this program, you’ll see output that looks like the following

Our variable contains the value 42

You’ll notice we passed printf two arguments. The first was the string we wanted to print. The second was a variable. You’ll also notice our string included a funny looking %i character sequence. In the final printed string, this %i was swapped out for the value of the variable we passed in. This is what formatting means — it’s a very basic templating system for replacing variables in strings.

If you wanted to use two variables, you’d just include another %i and pass a third argument to the function.

#include<stdio.h>

int main()
{
    printf("Our variables contains the values %i and %i\n", 42, 65);
    return 0;
}

The printf function will run through the string left to right, replacing the first % sequence with the second argument, the second % sequence with the third, and so on.

Understanding Formatting Templates

Here’s another formatting string to try

#include<stdio.h>

int main()
{
    printf("This isn't going to work %i", 4.321);
    return 0;
}

If you try compiling the above program, you’ll get an error that looks something like this

main.c:5:47: warning: format specifies type 'int' but the argument has type 'double' [-Wformat]
        printf("This isn't going to work %i", 4.321);
                                         ~~   ^~~~~
                                         %f
1 warning generated.

Why didn’t this work? Because %i only works with int variables. If you want to use a decimal number (i.e. a float) you’ll need to use the %f format string

#include<stdio.h>

int main()
{
    printf("This is going to work %f\n", 4.321);
    return 0;
}

Once again, C’s strict typing system rears its head. Rather than turn your 4.321 into an int, or rather than have some generic template replacement, C forces you to specify exactly what type you’ll be using. C does this because casting a variable has performance implications, and C is biased towards not making these sorts of decisions for you.

Mixing Types

One of the challenges you’ll face as a C programmer is understanding the consequences of using two different types in the same sort of operation. For example — consider the following program.

#include <stdio.h>
int main() {
    int x = 5;
    int y = 2;
    float answer = x / y;
    printf("Answer: %f\n", answer);
    return 0;
}

Here we declare two integers (x, y) and we divide the first by the second. Also, since 5 divided by 2 is 2.5, we declare a float variable named answer to hold the results. However, if you run the above program, you’ll get the following output.

Answer: 2.000000

What gives? Why does C think 5 divided by 2 is 2.0?

The problem is, we divided an integer by an integer. Since both parts of the division operation were integers, C used integer division to derive a result. Again, C errors on the side of doing the most efficient thing, even if it’s not the most obvious thing. We may have been smart enough to declare a float to hold our value, but we weren’t smart enough to remember that C can be weird when types mix. The solution is to ensure either the numerator or the divisor in our example is also a float.

One way to do this would be declaring x as a float.

#include <stdio.h>
int main() {
    float x = 5;
    int y = 2;
    float answer = x / y;
    printf("Answer: %f\n", answer);
    return 0;
}

While this works for our simple example, in a real program changing the type of a variable that’s used elsewhere may have unforeseen consequences. Fortunately C (like most programming languages) has a mechanism that will allow us to temporarily convert a variable of one type into other. This mechanism is known as casting. To cast the integer x as a float, we’d do this

#include <stdio.h>
int main() {
    int x = 5;
    int y = 2;
    float answer = ((float) x) / y;
    printf("Answer: %f\n", answer);
    return 0;
}

This program is identical to our first example, with the exception of this

((float) x) / y;

Before we use x in our division operation, we put the (float) cast in front of it. This will treat x for this operation only as a floating point number.

Lost Information

Casting from an int to a float is a relatively safe operation. However, what about casting a floating point number like 2.5 to an integer. What integer would that be? Two? Or three? This is the danger of casting — you often introduce ambiguities into your program. If we give this a try

#include <stdio.h>
int main() {
    int x = 0;
    float y = 2.5;

    x = (int) y;
    printf("Two or Three?: %i\n", x);
    return 0;
}

You’ll see that C will just drop the decimal.

Two or Three?: 2

Here’s another tricky example of lost information — what do you think this program will print?

#include <stdio.h>
int main() {
    char x = ' ';
    int y = 57;

    x = (char) y;
    printf("Two or Three?: %c\n", x);
    return 0;
}         

When an integer 57 gets cast as a char, the result is —

What is 57 as a char?: 9

Nine? How does that make any sense?! Well — it doesn’t until we consider the ASCII Text Encoding table. The character 9 is the 57th entry in this table. At some point a c systems developer decided that casting an int as a char would turn it into its corresponding text character.

This isn’t the only example of chars being somewhat type fluid. Consider the following example

#include <stdio.h>
int main() {
    int x = 81;
    char y = 'X';

    printf("%c\n",x);
    printf("%i\n",y);
    return 0;
}

Here we’ve printed an int as a char (with %c) and a char as an int (%i). The normally strict C didn’t miss a beat, and automatically rendered one as the other.

Q
88

You’ll see this sort of number/char substitution all over C programs — but be careful. Consider this program.

#include <stdio.h>
int main() {
    int x = 325;

    printf("%c\n",x);
    return 0;
}

Here we’re trying to use an int as a char — but with a number that’s outside the normal range of the ASCII tables. This program produces the following output

E

Why E and 325 are the same is a bit outside what we’re going to cover today — the main point is be careful when you’re using different variable types in a char context — they may not do what you think.

Character Addition

There’s one last example to consider before we wrap up for the day.

#include <stdio.h>
int main() {
    int x = 20;
    char y = 'a';
    int answerInt = x + y;
    char answerChar = x + y;
    printf("Answer Int: %i\n", answerInt);
    printf("Answer Char: %c\n", answerChar);
    return 0;
}

Here we’re performing a mixed type addition with ints and chars. If we look at the output.

Answer Int: 117
Answer Char: u

we see that C treated our char as a number again. If you’re coming from a language like javascript, you might expect the + to do some sort of concatenation. That’s not going to work in C.

Wrap Up

Closing with javascript concatenation does (once again) raise the specter of strings. So far we’ve been focused on numbers and individual characters — but we’ve avoided how C deals with silly human things like words and text.

Next time we’ll start our trek towards strings in C, but before we can reach that summit we’ll need to stop at basecamp, and cover an even more important C concept: Arrays.

Copyright © Alan Storm 1975 – 2018 All Rights Reserved

Originally Posted: 8th January 2018