Struct iteration with/without a pointer I've written the following sample program as a way to help improve my understanding of passing pointers to a function, and it currently works:
#include &quot;stdio.h&quot;

typedef struct Car {
    char*           name;
    unsigned int    price;
} Car;

void print_cars(Car* cars[]) {
    for (int i=0; cars[i] != NULL;i++) {
        printf(&quot;\n&lt;Car: %s, Price: $%d&gt;&quot;, car-&gt;name, car-&gt;price);
    }
}
void depreciate(Car* cars[]) {
    for (int i=0; cars[i] != NULL; i++) {
        cars[i]-&gt;price = cars[i]-&gt;price * 0.95;
    }
}

int main(int argc, char* argv[]) {

    Car chevy = {.name = &quot;Chevy&quot;, .price = 45000};
    Car mazda = {.name = &quot;Mazda&quot;, .price = 30000};
    Car ferrari = {.name = &quot;Ferrari&quot;, .price = 200000};

    Car* my_cars[] = {&amp;chevy, &amp;mazda, &amp;ferrari, NULL};
    print_cars(my_cars);
    printf(&quot;\n--------- Depreciating -----------&quot;);
    depreciate(my_cars); // &lt;-- ignoring this
    print_cars(my_cars);

    return 1;

}


Ignoring the line that modifies the value of the struct, would it be possible to do the print_cars function without using a pointer? When I tried doing it I would receive the error:

new5.c:13:27: error: invalid operands to binary expression ('Car' (aka 'struct Car') and 'void *')

Which I think may be related to using the NULL in the my_cars array to signal the end of it, but wasn't positive. Additionally, is using NULL in a non-char array a common way to show that the end has been reached? Where else could this be improved?
While your code &quot;works&quot; for you, there are a lot of small mistakes in it. I'm listing them straight from top to bottom.
#include &quot;stdio.h&quot;

Since stdio.h is a header from the standard library, as opposed to a header you define yourself in your project, you should include it using #include &lt;stdio.h&gt; instead.
typedef struct Car {
    char*           name;
    unsigned int    price;
} Car;

The name of the car should be a const char * since later, you assign string literals like &quot;Chevy&quot; to that field, and string literals are read-only.
To prevent this possible bug in the future, let the C compiler warn you about issues like these. For GCC, pass the compile options -Wall -Wextra -Werror -O2. Since you didn't say which development environment you use, you have to find out how to add these options yourself.
void print_cars(Car* cars[]) {
    for (int i=0; cars[i] != NULL;i++) {
        printf(&quot;\n&lt;Car: %s, Price: $%d&gt;&quot;, car-&gt;name, car-&gt;price);
    }
}

Since print_cars does not modify the cars, its parameter should be const Car* cars[], just add the const.
There should be a single space around assignment operators. That is, write int i = 0 instead of int i=0. There should be a single space after the semicolon as well.
When a program produces output, the end-of-line marker \n should go to the end of the line, not to the beginning.
void depreciate(Car* cars[]) {
    for (int i=0; cars[i] != NULL; i++) {
        cars[i]-&gt;price = cars[i]-&gt;price * 0.95;
    }
}

Instead of writing cars[i]-&gt;price twice, you can make use of the combined assignment operator *= by writing: cars[i]-&gt;price *= 0.95.
The floating-point number 0.95 cannot be represented exactly in binary. You should experiment a little with a car price that would end up evenly. But even then you could end up with rounding errors. I wrote the following test snippet, which shows that for some prices, the actual result ends up lower than expected, because what you see as 0.95 is really 0.9499999999999999555910790149937383830547332763671875 for the computer.
#include &lt;stdio.h&gt;

int main(void)
{
    for (int i = 0; i &lt; 1000; i++) {
        printf(&quot;%d: %.20f, %.20f, %d\n&quot;,
            i,
            i * 0.95,
            i * 95 / 100.0,
            i * 95 / 100);
    }
}

To keep the programming simple, you should stick to the last variant i * 95 / 100, until you get more experienced with floating point numbers.
int main(int argc, char* argv[]) {

    ...
    return 1;
}

The function main is special regarding its return value. Returning 1 means failure, returning 0 means success. Many other C functions return 0 for success (just like main) and -1 for failure. Others return non-zero for success and zero for failure. Things vary a lot, and you have to learn the meaning for each function individually. There are some patterns though, so it's not completely chaotic.
All in all, it's a well-written program. After modifying the few details I mentioned, it's perfect.