Skip to content
  • Functions & Call by Value · C

Functions & Call by Value

LearnViaNotes @learnvianotes· 3 min read

A function packages a computation behind a name and a prototype. C passes every argument by value — the function receives copies; to modify the caller’s variable you pass its address.

Declaration, definition, call

C
#include <stdio.h>

double average(const int *values, int count);   /* prototype */

int main(void) {
    int marks[] = {70, 85, 90};
    printf("%.2f\n", average(marks, 3));
    return 0;
}

double average(const int *values, int count) {  /* definition */
    if (count == 0) return 0.0;
    long sum = 0;
    for (int i = 0; i < count; i++) sum += values[i];
    return (double)sum / count;
}
Output
81.67
PartExampleNotes
Return typedoublevoid if nothing is returned
NameaverageExternal linkage by default; static to hide it
Parameters(const int *values, int count)(void) means no parameters; () means unspecified (pre-C23)
Body{ … }return expr; ends the call

Call by value

C
#include <stdio.h>

void broken_swap(int a, int b) {    /* swaps the copies only */
    int t = a; a = b; b = t;
}

void swap(int *a, int *b) {         /* receives addresses ("call by reference" emulation) */
    int t = *a; *a = *b; *b = t;
}

int main(void) {
    int x = 1, y = 2;
    broken_swap(x, y);
    printf("after broken_swap: %d %d\n", x, y);
    swap(&x, &y);
    printf("after swap:        %d %d\n", x, y);
    return 0;
}
Output
after broken_swap: 1 2
after swap:        2 1

Arrays and structs as parameters

  • An array argument decays to a pointer to its first element: void f(int a[]) is exactly void f(int *a). The size is lost — pass it separately.

  • A struct is copied in full. For big structs pass const struct T * to avoid the copy.

  • Mark pointer parameters you don’t modify as const — it documents intent and lets the compiler check it.

Returning several values

C
#include <stdio.h>

/* return a status, deliver results through out-parameters */
int divide(int a, int b, int *quot, int *rem) {
    if (b == 0) return -1;
    *quot = a / b;
    *rem = a % b;
    return 0;
}

int main(void) {
    int q, r;
    if (divide(17, 5, &q, &r) == 0)
        printf("17 = 5 * %d + %d\n", q, r);
    if (divide(1, 0, &q, &r) != 0)
        printf("division by zero rejected\n");
    return 0;
}
Output
17 = 5 * 3 + 2
division by zero rejected

inline and the order of evaluation

  • static inline int sq(int x) { return x * x; } — a hint to expand the body at the call site; typical in headers as a type-safe macro replacement.

  • The order in which arguments are evaluated is unspecified: in f(g(), h()) either may run first. Never depend on it.

  • A function with a non-void return type that falls off the end without return — and whose value is used — is undefined behaviour (-Wreturn-type).

C — rejected: non-void function does not return a value in all paths
int sign(int x) {
    if (x > 0) return 1;
    if (x < 0) return -1;
}   /* missing return when x == 0 */

Does C support call by reference?

What is a function prototype and why is it needed?

What is the difference between f() and f(void) in a declaration?

Free for students and teachers

Write notes like this one

Cards for every idea, quizzes and flashcards, read aloud — on the web and your phone.

Something wrong with this note? Open it to report