I've been reading K&R's The C Programming Language lately to try to bone up on low-level concepts that are lacking from my substantially-abbreviated education.

One of the things that keeps poking out at me is the difference between what "best practices" are for different languages. For example, the biggest difference I see between C and Python conventions is the way data is passed between functions.

For example, take a function that reads the first line of data from a file. In Python, you'd take the filename as an argument and return the data:

def read_line(filename):  
    with open(filename, 'r') as my_file:
        return next(my_file)

In C, the typical implementation would take a char pointer as a parameter, mutate it in place, then return some sort of value indicating success or failure; possibly the length of the string:

#include <stdio.h>

#define MAX_STR_SIZE    1000

int rdln(char fname[], char *buff){  
    FILE *fp;
    int ccount = 0;
    if ((fp = fopen(fname, "r")) == NULL){
        return -1;
    } else {
        while((*(buff++) = getc(fp)) != EOF && ccount < MAX_STR_SIZE) {
            ccount++;
            if (*(buff - 1) == '\n'){
                *buff = '\0';
                return ccount;
            }
        }
        *buff = '\0';
        return ccount;
    }
}

Setting aside the pure linguistic differences (yes, the C version is more complicated to read, and yes, that's at least partially because I don't know how to write C that well yet), the philosophies are very different. Of course, you could write each using the philosophy of the other, but it would probably raise some eyebrows:

def read_line(filename, characters):  
    """
    `filename` is a string; `characters` is a list (mutable in Python).
    """
    ccount = 0
    with open(filename, 'r') as my_file:
        for char in next(my_file):
            characters.append(char)
            ccount += 1
    return ccount

Well, actually, today I learned some stuff, because I was going to have a block here showing the Python idiom in C, but you actually can't do that, because if you return a pointer to memory that's allocated inside a function from that function, the memory gets de-allocated, and you just end up with a pointer to empty space.

So, that definitely helps explain why the C idiom is the way it is - by passing variables as arguments, those variables are scoped to the calling function, rather than to the called function.

On to the next thing.