138
\$\begingroup\$

What general tips do you have for golfing in C? I'm looking for ideas that can be applied to code golf problems in general that are at least somewhat specific to C (e.g. "remove comments" is not an answer). Please post one tip per answer. Also, please include if your tip applies to C89 and/or C99 and if it only works on certain compilers.

\$\endgroup\$
  • 9
    \$\begingroup\$ I think the biggest single-sentence hint is: Read the winning codes submitted to IOCCC. \$\endgroup\$ – vsz May 12 '12 at 21:23

50 Answers 50

4
\$\begingroup\$

Missing includes and return values

As noted in the very first answer, some compilers (notably, GCC anc clang) let you get away with omitting #includes for standard library functions.

While that usually goes well, it might cause problems in some cases, since the implicit declarations of standard library functions inside the source code will cause the compiler to treat return values as ints. For example, the code

char*p=getenv("PATH");

wont work as expected on a 64-bit platform since getenv returns a 64-bit memory address which doesn't fit into an int.

In this case, there are at least three ways to use getenv without errors.

  • Include the header file as follows.

    #include<stdlib.h>
    char*p=getenv("PATH");
    

    This is the right way™, but not very golfy; it costs 19 bytes.

  • Declare getenv with the pointer as follows.

    char*getenv(),*p=getenv("PATH");
    

    This costs 10 bytes.

  • Finally, unless your code wouldn't work on 32-bit platforms, compile your code on one of those or with the -m32 flag (gcc). This costs 0 bytes.

\$\endgroup\$
4
\$\begingroup\$

Inverse flag update

Sometimes a challenge asks to determine a data set's specific boolean property. To avoid the unacceptably long return keyword, I often use a flag variable which gets updated in a loop and assign-returned at the end (I will refer to this tip for more detail on assign-returning).

When working with such boolean flags and boolean values, to update them I often use either f&=a|b or f*=a|b to align them with the result of a|b. This is equivalent to saying f = f && (a|b).

However, sometimes a flag needs to be inversely updated, meaning f = f && !(a|b). Naively, one would use f&=!(a|b) (9 bytes), or -- using fundamental logical equivalences -- one would golf it to f&=!a&!b (8 bytes).
For the case of an inverse flag update, though, one might be better off using the binary shift right operator >>, as the previous assignment is (when working with boolean values) equivalent to f>>=!(!a&!b), which simply golfs to f>>=a|b (7 bytes).

If the flag update in question does not involve parentheses due to negation (as in the previous example), inverse flag updating may still be shorter, as for example f&=!a|!b (8 bytes) is equivalent to f&=!(a&b) (9 bytes), which is equivalent to f>>=a&b (7 bytes).

Inverse flag updating may in certain cases also be used even though the values in question are not boolean (either 0 or 1).
If only one operand is boolean, bitwise and (&) can still be used, as the second operand's bits will all be cleared. When using bitwise or (|) or both operands are non-boolean, one should consider using logical and (&&) and logical or (||) to get a boolean result, even though they are one byte longer.

As a side node, these rules also apply when the expression is side-effect-dependent, meaning !f()&&!g() is equivalent to !(f()||g()) regarding the execution of g(), such that even in those cases inverse flag updating can be used.

For testing purposes, I wrote a simple truth table tester (TIO-link).

One recent real-world example of this technique in action would be for example my answer to Detect Rectangular Text.

\$\endgroup\$
3
\$\begingroup\$

instead of the printf loop

for(i=1;i<12;i++){if(!i%3)printf("\n");printf("%d",i);}

just use

for(i=1;i<12;i++) printf("%c%d",!(i%3)*10,i);

it helps me so much .


@SamHocevar 's answer (shoretr by 2bytes)

for(i=1;i<12;i++) printf("\n%d"+!!(i%3),i); 
\$\endgroup\$
  • 3
    \$\begingroup\$ The second line is incorrect; it will actually print the null characters. \$\endgroup\$ – sam hocevar May 4 '15 at 23:16
  • \$\begingroup\$ lol im not pinting them into char array , it is terminal console, and nul character doesnt mean space nor a newline:/ \$\endgroup\$ – Abr001am May 4 '15 at 23:39
  • 7
    \$\begingroup\$ You can use this: printf("\n%d"+!!(i%3),i); which is 2 characters shorter. \$\endgroup\$ – sam hocevar May 5 '15 at 0:47
3
\$\begingroup\$

Use bitwise and (&) when comparing boolean expressions to save one byte.

Example:

if(i^2&k/3) DoSomething;

Really, really useful when combined with the other tips

\$\endgroup\$
  • 1
    \$\begingroup\$ The example if(i^2&k/3) seems like it would be equivalent to if(i != 2 && k >= 3), but it's not because & has higher precedence than ^. Also, even if(i-2&k/3) wouldn't work, because a bitwise and of two nonzero values could result in zero. On the other hand, if(i!=2&k>2) would work. \$\endgroup\$ – user59468 Sep 19 '16 at 23:44
3
\$\begingroup\$

Use s[i] instead of i<strlen(s) in string-handling loops

For example:

for(i=0;i<strlen(s);i++)s[i]=s[i+1];

can be shortened to:

for(i=0;s[i];i++)s[i]=s[i+1];
\$\endgroup\$
  • 3
    \$\begingroup\$ Though in this case one would most likely not bother with indices and use pointer incrementation; for(;*s;)*s=*++s;. \$\endgroup\$ – Jonathan Frech Apr 30 '18 at 12:59
3
\$\begingroup\$

Use for rather than while

Any while can be changed into a for of the same length:

while(*p++)
for(;*p++;)

On its own, that's not golf. But we now have an opportunity to move an immediately-preceding statement into the parens, saving its terminating semicolon. We might also be able to hoist an expression statement from the end of the loop; if the loop contained two statements, we could also save the braces:

a=5;while(*p++){if(p[a])--a;++b;}

for(a=5;*p++;++b)if(p[a])--a;
\$\endgroup\$
  • 2
    \$\begingroup\$ Even do...while loops should be replaced with for loops. for(;foo,bar,baz;); is shorter than do foo,bar;while(baz); \$\endgroup\$ – ceilingcat Nov 24 '18 at 17:48
2
\$\begingroup\$

When you have to walk a string you can walk the pointer instead of incrementing the index.

Code :

#include <stdio.h>

// print each char
void f(char* s) {
    for (int i=0;s[i];i++) putchar(s[i]);
}

// same output than f;
void g(char* s)
{
    for (;*s;) putchar(*s++);
}

int main(void) {
    f("hello\n");
    g("hello\n");
    return 0;
}

example: Remove duplicated & switched case

\$\endgroup\$
2
\$\begingroup\$

Swap variables

If you ever need to swap variables, don't use the pattern with an extra variable or that addition-subtraction-method, just do some chained XORing:

a^=b^=a^=b;
\$\endgroup\$
  • 2
    \$\begingroup\$ This is undefined behavior, due to a lack of sequence points in between two modifications of the same object. See here: stackoverflow.com/questions/9958514/… \$\endgroup\$ – 2501 Apr 23 '17 at 19:44
2
\$\begingroup\$

Use #define instead of functions when possible

For example:

f(int i,char*s){/*do something with i and s*/;}

Using #define can eliminate the argument list type, curly-braces and closing semicolon:

#define f(i,s)/*do something with i and s*/
\$\endgroup\$
2
\$\begingroup\$

Inline arrays

If you need a non-int constant array and just use it once, you can do

float f(a){return (float[]){.3,.2,.7}[a];}

instead of

float z[]={.3,.2,.7};float f(a){return z[a];}

to save 3 bytes.

(In this case it can save one more byte since the blank after return can be omitted.)

\$\endgroup\$
2
\$\begingroup\$

Whenever a certain function is called several times, it's common to #define it to something shorter. However, certain compilers (MinGW and clang as far as I know) allows for something even more compact by using function pointers:

(*P)()=printf;
P("Test: %d\n", 10);

Other compilers might require an #include of the proper header file for it to work.

\$\endgroup\$
2
\$\begingroup\$

Overload functions (unportable)

Instead of declaring multiple functions...

d(x){return x*2;}
float r(float x){return 1/sqrt(x);}
...
printf( "%d %f\n", d(2), r(2) );

...declare one "function" that does different things depending on return and parameter types.

(*f)()=L"\xf33f048d\xc3c0520f"; // global
...
printf( "%d %f\n", f(2), ((float(*)(float))f)(2) );

Try it online! This works because some ABI's (Linux x86_64, in this example) use separate registers for floating point and integer arguments and return values.

The disassembly of the (*f)() "function"...

0:       8d 04 3f                lea    (%rdi,%rdi,1),%eax
3:       f3 0f 52 c0             rsqrtss %xmm0,%xmm0
7:       c3                      retq

On a x86_64 Linux machine, this function takes the first integer parameter, doubles it and places the result in %eax (char/short/int/long return value). It takes the first floating point parameter, computes a low precision reciprocal square root and places it in %xmm0 (float/double return value).

\$\endgroup\$
  • \$\begingroup\$ This would be a better answer if you decoded the x86 asm in a comment or something, and also link to a method for turning hand-written asm into strings. I don't want to go look up an opcode table. I can see it ends with a c3 RET (x86 being little-endian), but I can only guess that the other bytes are lea eax, [rdi+rdi] and rsqrtps xmm0,xmm0 (with no Newton iteration? that's very inaccurate...), because that's what would make sense. \$\endgroup\$ – Peter Cordes Jun 14 '18 at 15:37
2
\$\begingroup\$

Set an array of int to the same value (C99, Linux, BSD, OSX)

Instead of

int a[n]=...,x=...;
for(int i=n;i--;)a[i]=x

Try something like

int a[n]=...,x=...;
wmemset(a,x,n);

On MSVC on Windows, wmemset() works on arrays of short instead of int.

\$\endgroup\$
  • 1
    \$\begingroup\$ Iirc wchar_t is 32 bits wide with gcc on Windows as well, unless you specify the -fshort-wchar flag. \$\endgroup\$ – Dennis Jun 16 '18 at 4:41
2
\$\begingroup\$

Boolean constant string selection when the selector's true value is guaranteed to be one larger than the second option's length

At its heart, this tip attempts to golf a ternary if of the form cnd?str_true:string_false when two conditions are met, namely that both str_true and string_false are constant strings and cnd is either 0 or strlen(string_false)+1.

If the above conditions are met, the expression cnd?"true":"false" can be golfed* by one byte to "false\0true"+cnd (here cnd == 0 || cnd == 6 always holds); another byte can be shaved off by not escaping the null byte (a compiler dependent feature).

The tip in action

For this example, suppose the string selection's criterion is k%3's truthiness, where k-1 is never divisible by three. In this case the ternary if

k%3?"°@°":"_" // 13 bytes

can be golfed to:

"_\0°@°"+k%3 // 12 bytes

Which can be golfed down to eleven bytes if one does not escape the null byte.

Application in obfuscation

As the above requirements are rather strict, this tip is most likely not widely applicable. Nonetheless, the shown technique can also be used to potentially obfuscate a program at no further byte cost.

Given e as a truly boolean expression -- (e) == 0 || (e) == 1 holds -- with the proper operator precedence regarding the upcoming factor, the following snippets are interchangeable* at the same byte count -- when not escaping the null byte.

e?"lifeless":"lychee"
"lychee\0lifeless"+e*7

Bare in mind that this obfuscation is only non-detrimental to the byte count if the second option's string is not longer than eight characters -- since else the factor spans more than one byte.

*: If interpreted as constant strings.

\$\endgroup\$
  • \$\begingroup\$ If the strings to be selected are two or fewer octets in length, you can use wide characters. L"AB"+p will return "A" if p==0 and "B" if p==1. \$\endgroup\$ – ceilingcat Nov 24 '18 at 17:43
2
\$\begingroup\$

Get the length of a string with puts() instead of strlen()

According to the standard C specification, puts() returns a non-negative integer on success. In practice, most C libraries seem to treat puts(s) as equivalent to printf("%s\n", s), which returns an integer equal to the number of bytes written.

As a result, the return value of puts(s) is equal to 1 + strlen(s). If the additional console output can be ignored, this saves a few bytes.

\$\endgroup\$
  • \$\begingroup\$ "a few" in this case is 4. \$\endgroup\$ – Jonathan Frech Sep 13 at 1:04
1
\$\begingroup\$

For scanning a string into an array, you can use

gets(str);

instead of

scanf("%s",str);
\$\endgroup\$
  • 1
    \$\begingroup\$ Yeah, except you should never use gets. \$\endgroup\$ – MD XF May 13 '17 at 0:24
  • 4
    \$\begingroup\$ @MDXF Welcome to code golf \$\endgroup\$ – DollarAkshay Mar 31 '18 at 17:17
  • 2
    \$\begingroup\$ @MDXF: ... for the exact same reason you should never use "%s" instead of "%256s" as your scanf format string. (Or whatever the buffer size is.) \$\endgroup\$ – Peter Cordes Jun 14 '18 at 15:31
1
\$\begingroup\$

Sometimes, albeit rarely, if your code contains many for loops, #define F for( may save a byte or two (especially if some of the loops have an empty init section).

If it is applicable to your situation, #define F;for( may save even more bytes.

Examples:

https://codegolf.stackexchange.com/a/153117/61405

https://codegolf.stackexchange.com/a/149629/61405

\$\endgroup\$
1
\$\begingroup\$

When your algorithm produces output in reverse order, take a pointer to the end of a buffer and write it in decreasing order, returning a pointer to the first element. It's up to the caller to supply a buffer large enough for any this input, or for any possible input.

Base conversion / int-to-string is a classic example where this interface is used in real life, such as glibc's internal _itoa, used by the printf family of functions as well as some other internal callers. The max buffer size is 65 bytes for a 64-bit integer -> base 2 string.

// takes a pointer to one-past-the-end, which is also a valid option.
char *itoa_end(unsigned long val, char *p_end) {
  // does *not* zero terminate the buffer.  Use *--p_end = 0;
  const unsigned base = 10;
  char *p = p_end;
  do {
    *--p = (val % base) + '0';
    val /= base;
  } while(val);                  // runs at least once to print '0' for val=0.    

  // write(1, p,  p_end-p);
  return p;  // let the caller know where the leading digit is
}

For golfing, it can be more compact to take the pointer by reference and modify it, instead of returning it. (return is a long keyword, and code depending on gcc -O0 evaluating expressions in the return-value register isn't even C.)

For example, I used this in ASCII art uncompression from a base-n number (i.e. int->string with a digit lookup table), where I already needed a char* arg, so it was very cheap to declare another as a char **.

Use *p everywhere you have p in the simple version. *--*p decrements the caller's pointer, then dereferences that to reference the actual character.

/* int n = the number
 * int B = size of I = base
 * char I[] = input table
 * char **O = input/output arg passed by ref:
 *    on entry: pointer to the last byte of output buffer.
 *    on exit:  pointer to the first byte of the 0-terminated string in output buffer
 */
void semi_golfed_g(n,I,B,O)char*I,**O;
{
    for(**O=0 ; n ; n/=B)
        *--*O = I[n%B];
}
\$\endgroup\$
1
\$\begingroup\$

Use recursion over loops.

Recursive example

f(){printf("infiniteloop");f();}

For loop equivalent is 3 bytes longer.

f(){for(;;)printf("infiniteloop");}
\$\endgroup\$
  • \$\begingroup\$ I think you are missing a semicolon in your recursive example. \$\endgroup\$ – Jonathan Frech Jul 9 '18 at 23:48
  • \$\begingroup\$ Do you have an example for a terminating program which could be golfed in this way? Or does this tip only apply to infinite loops? \$\endgroup\$ – Jonathan Frech Jul 10 '18 at 0:11
  • \$\begingroup\$ Yes, I actually have the shortest c solution in this example \$\endgroup\$ – Geo Jul 11 '18 at 17:03
  • 4
    \$\begingroup\$ f(){f(printf("infiniteloop"));} would save a further byte in this example. Try it online! \$\endgroup\$ – Dennis Sep 23 '18 at 4:49
0
\$\begingroup\$

Calculating \$\lceil\log_{10}(n)\rceil\$

Especially in challenges where properties of decimal representations are of interest, one needs to find a number's decimal representation's length, or for \$n\in\mathbb{N}^+\$ equivalently, \$\lceil\log_{10}(n)\rceil\$.
In this post, several approaches are presented and discussed.

For a C source file containing approaches (a.1) to (b.3) together with a testing setup, see TIO.

I wrote this tip based on this answer of mine, searching for a smaller approach than (a.1).
If you know of any other approach possibly shorter in even a specific scenario, feel free to either add your own tip or add to the list below.

(a.1) An expression in n, 20 bytes

snprintf(0,0,"%d",n)

Versatility is a great property of the above approach, when used to determine a number's decimal representation's length, the most direct approach might be the most byte-effective.

0 is given its correct decimal representation length of 1.

GCC only throws a warning for ignoring #include <stdio.h>, otherwise the inclusion would be very byte-heavy at potentially 19+20=39 bytes. If instead of sprintf(0, one uses sprintf(NULL, the byte count is increased to 23 bytes. If using both, the byte count could jump to 42 bytes.

(a.2) A function in n, 29 bytes

a(n){n=snprintf(0,0,"%d",n);}

By being a function, this approach's versatility is high; (a.1)'s compiler-specifics also apply, when properly returning, the byte count increases to 5+29=34 bytes.

0 is given its correct decimal representation length of 1.

(b.1) A function in n, requiring another variable, 32 bytes

b(n,k){for(k=0;n;k++)n/=10;n=k;}

Of all approaches presented, this one has the worst byte count. However, considering potential compiler restrictions discussed in (a.1), it could prove more byte efficient, since the approach is nearer to the C core.

0 is given its incorrect decimal representation length of 0. One can make the case for defining \$\lceil-\infty\rceil:=0\$ which would make this approach closer to a logarithm implementation, when further defining \$\log(0):=-\infty\$.

Modification to calculate \$\lceil\log_b(n)\rceil\$ for a base \$b\in\mathbb{N}^+\$ is possible, changing the byte count by the bytes required to represent \$b\$ in C-source.

(b.2) A statement requiring existence of two variables, setting n=0, 20 bytes

for(k=0;n;k++)n/=10;

If another variable is already declared and n can be either discarded or needs to be cleared regardless and the use case is a whole block instead of a one-line expression, the above could be used. Since it is equivalent in byte count to (a.1), the behavioural differences have to be analyzed.

Minimally wrapped inside a function, it becomes (b.1), both being similar in features.

(b.3) A statement working additively on k, setting n=0, 17 (pot. 16) bytes

for(;n;k++)n/=10;

Another variation on (b.1), removing initialization of k. Furthermore, for(; leaves space for an expression, potentially allowing to save a semicolon's byte, effectively rendering this approach 16 bytes long.

(c.1) A statement in n, producing stdout-output, 14 bytes

printf("%d",n)

Courtesy of H.PWiz.

This approach's utter conciseness and simplicity may be alluring, its major drawback, however, is its stdout-output; tolerability being heavily challenge-dependent.

\$\endgroup\$
  • \$\begingroup\$ I suppose it's not alright for you to use printf, even when the submission is a function? \$\endgroup\$ – H.PWiz Sep 13 at 1:11
  • \$\begingroup\$ As in returning the number of characters printed, ignoring output to stdout? \$\endgroup\$ – Jonathan Frech Sep 13 at 1:13
  • \$\begingroup\$ Is there a standard null stream so that printf(stdnull,"%d",n) could be used? \$\endgroup\$ – Jonathan Frech Sep 13 at 1:18
  • \$\begingroup\$ I have added it as (c.1). \$\endgroup\$ – Jonathan Frech Sep 13 at 1:24

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.