Identifying variables: what process do you follow?

K

Kevin Walzer

I'm trying to learn C. I have a fairly extensive background with C-based
scripting languages (Python,Tcl, others), so a great deal of C is
proving easy to pick up (control structures, functions, etc.). However,
what is *really* tripping me up is the entire process of identifying and
declaring variables at the beginning of your program, i.e.:

short int short_max = SHRT_MAX;
int integer_min = INT_MIN;
double double_max = DBL_MAX;

Generally, when developing a program in a scripting language, I follow
an interative development process, starting with some core
functionality, adding functions and variables as the program evolves. In
other words, I don't know in advance what variables I will need to declare.

With C, such an approach doesn't seem practical. You need to identify
some variables ahead of time just to have a program that will compile!
So, I'm wondering what approach seasoned C programmers use for larger
programs, i.e. ones larger than the simple single-function ones I'm
learning from my C textbook. Is there a design process that identifies
such things?

I hope this question about "mental models," getting into the C mindset,
isn't off-topic. TIA.

--Kevin
 
R

Richard Heathfield

Kevin Walzer said:
I'm trying to learn C. I have a fairly extensive background with C-based
scripting languages (Python,Tcl, others), so a great deal of C is
proving easy to pick up (control structures, functions, etc.). However,
what is *really* tripping me up is the entire process of identifying and
declaring variables at the beginning of your program, i.e.:

short int short_max = SHRT_MAX;
int integer_min = INT_MIN;
double double_max = DBL_MAX;

s/program/function/

Whilst it is possible and legal and all that to define objects at the
beginning of the *program* (at "file scope", outside any function), it is
better practice to define each object at the smallest scope that is
practical. Almost invariably, this means no wider than "function scope" -
and this makes functional decomposition and top-down development much
easier.
Generally, when developing a program in a scripting language, I follow
an interative development process, starting with some core
functionality, adding functions and variables as the program evolves. In
other words, I don't know in advance what variables I will need to
declare.

That's all right - neither do I. :)
With C, such an approach doesn't seem practical. You need to identify
some variables ahead of time just to have a program that will compile!
So, I'm wondering what approach seasoned C programmers use for larger
programs, i.e. ones larger than the simple single-function ones I'm
learning from my C textbook. Is there a design process that identifies
such things?

I want to write a good answer to this bit for you, but it will probably be
rather long, and I don't have time right now. I will have time in a day or
two (or, perhaps, tonight). I'll "watch" this thread. If nobody else has
given you a decent explanation before then, I'll do my best to fill the
gap.
I hope this question about "mental models," getting into the C mindset,
isn't off-topic.

So do I, or we'll both get lynched by an angry mob. :)
 
B

Ben Pfaff

Kevin Walzer said:
Generally, when developing a program in a scripting language, I follow
an interative development process, starting with some core
functionality, adding functions and variables as the program
evolves. In other words, I don't know in advance what variables I will
need to declare.

With C, such an approach doesn't seem practical. You need to identify
some variables ahead of time just to have a program that will compile!

I usually write code and the corresponding variable declarations
in tandem. Sometimes it is obvious in advance what variables
will be needed ("I know I'll need a loop index"), so I'll declare
those. Then I go and write the code that uses them. Usually
there's a variable or two that I forgot to declare, so I go back
and insert that declaration. Then I look over the whole function
and try to informally prove to myself that it works. Often, it
obviously doesn't, so I adjust the code and the variable
declarations to fix it.
 
A

Alan Curry

With C, such an approach doesn't seem practical. You need to identify
some variables ahead of time just to have a program that will compile!
So, I'm wondering what approach seasoned C programmers use for larger
programs, i.e. ones larger than the simple single-function ones I'm
learning from my C textbook. Is there a design process that identifies
such things?

Most of us don't type the complete program in a single pass from beginning to
end. If you use an editor instead, you'll have the ability to go back and add
variable declarations. The Standard Text Editor (ed) is sufficient, but there
are even more helpful editors available today, which actually make use of the
cursor positioning abilities of the terminal, enabling you to see the code as
you edit it!

With this modern wonder, the full-screen text editor, you may begin writing a
C function without including any local variable declarations. When you come
to a point where you need a local variable, instruct the editor to relocate
the cursor to the beginning of the function. This is often done by the
repeated use of a key labeled with an arrow pointing in an upwardly
direction, each press of which will cause the editor to respond by moving the
cursor onto the preceding line of your source code.

Having arrived at the beginning of the function, insert the declaration.
Locate the cursor movement key of opposing orientation to the one previously
employed. Press repeatedly until the return of the cursor to its starting
position is actualized.

Advanced users may find editor shortcuts for moving the cursor to the desired
locations with fewer keypresses.

.... Seriously, what are you editing with, "cat > file.c" ?
 
J

Justin Spahr-Summers

With C, such an approach doesn't seem practical. You need to identify
some variables ahead of time just to have a program that will compile!

C99 (which is the latest standard) allows mixed declarations and code,
but is not widely implemented in full; however, in C90, you can also
do something like the following:

int myfunction (void) {
int a = 5;
/* do stuff with 'a' here */
{
int b = 6;
/* do stuff with 'a' and 'b' here */
}

/* do more stuff with 'a' here */
return a;
}

The scope of the variable 'b' begins at the inner opening brace and
ends at the inner closing brace, and as long as you keep its
declaration at the very beginning of that scope, it's legal in both
C90 and C99. Any amount of nested braces is allowed as well.
 
K

Kevin Walzer

Alan said:
Most of us don't type the complete program in a single pass from beginning to
end. If you use an editor instead, you'll have the ability to go back and add
variable declarations. The Standard Text Editor (ed) is sufficient, but there
are even more helpful editors available today, which actually make use of the
cursor positioning abilities of the terminal, enabling you to see the code as
you edit it!

With this modern wonder, the full-screen text editor, you may begin writing a
C function without including any local variable declarations. When you come
to a point where you need a local variable, instruct the editor to relocate
the cursor to the beginning of the function. This is often done by the
repeated use of a key labeled with an arrow pointing in an upwardly
direction, each press of which will cause the editor to respond by moving the
cursor onto the preceding line of your source code.

Having arrived at the beginning of the function, insert the declaration.
Locate the cursor movement key of opposing orientation to the one previously
employed. Press repeatedly until the return of the cursor to its starting
position is actualized.

Advanced users may find editor shortcuts for moving the cursor to the desired
locations with fewer keypresses.

... Seriously, what are you editing with, "cat > file.c" ?

Emacs, actually.
 
C

CBFalconer

Justin said:
.... snip ...

int myfunction (void) {
int a = 5;
/* do stuff with 'a' here */
{
int b = 6;
/* do stuff with 'a' and 'b' here */
}
/* do more stuff with 'a' here */
return a;
}

The scope of the variable 'b' begins at the inner opening brace
and ends at the inner closing brace, and as long as you keep its
declaration at the very beginning of that scope, it's legal in
both C90 and C99. Any amount of nested braces is allowed as well.

Err'm. From the C standard:

5.2.4.1 Translation limits

[#1] The implementation shall be able to translate and
execute at least one program that contains at least one
instance of every one of the following limits:12)

-- 127 nesting levels of blocks

which seems to me to define 'any amount' as 127. :)
 
P

Peter Pichler

Kevin said:
You need to identify
some variables ahead of time just to have a program that will compile!

Easy. Declare all possible variables you can think of upfront and when
you've finished writing your function, let the compiler tell you which
ones have not been used and delete them. (A similar principle to
counting sheep in a flock: count the legs and divide by four.)

Just kidding, Ben and Alan gave you the real answer.
 
J

jaysome

C99 (which is the latest standard) allows mixed declarations and code,
but is not widely implemented in full; however, in C90, you can also
do something like the following:

int myfunction (void) {
int a = 5;
/* do stuff with 'a' here */
{
int b = 6;
/* do stuff with 'a' and 'b' here */
}

/* do more stuff with 'a' here */
return a;
}

The scope of the variable 'b' begins at the inner opening brace and
ends at the inner closing brace, and as long as you keep its
declaration at the very beginning of that scope, it's legal in both
C90 and C99. Any amount of nested braces is allowed as well.

If the scope of the variable 'b' begins at the inner opening brace,
shouldn't I be allowed to do something like this?

int myfunction (void) {
int a = 5;
/* do stuff with 'a' here */
{
int b0 = b;
int b = 6;
/* do stuff with 'a' and 'b' here */
}

/* do more stuff with 'a' here */
return a;
}

When I do this, I get a compiler error:

error C2065: 'b' : undeclared identifier

What gives?

Thanks in advance
--
jaysome

"No product of human intellect comes out right the first time. We
rewrite sentences, rip out knitting stitches, replant gardens, remodel
houses, and repair bridges. Why should software be any different?"

(RTCA/DO-248A, Second Annual Report for Clarification of DO-178B
"Software Considerations in Airborne Systems and Equipment
Certification". RTCA, Inc., Washington, D. C., September 13, 2000.)
 
J

Justin Spahr-Summers

If the scope of the variable 'b' begins at the inner opening brace,
shouldn't I be allowed to do something like this?

int myfunction (void) {
int a = 5;
/* do stuff with 'a' here */
{
int b0 = b;
int b = 6;
/* do stuff with 'a' and 'b' here */
}

/* do more stuff with 'a' here */
return a;

}

When I do this, I get a compiler error:

error C2065: 'b' : undeclared identifier

What gives?

I was thinking in a hurry after a long day. It obviously begins where
the declaration is. I'm fairly certain you realize that, but the OP
might not, so thanks for bringing it up.
 
C

CBFalconer

jaysome said:
.... snip ...


If the scope of the variable 'b' begins at the inner opening
brace, shouldn't I be allowed to do something like this?

int myfunction (void) {
int a = 5;
/* do stuff with 'a' here */
{
int b0 = b;
int b = 6;

It _can_ begin at the brace. It does begin when b is declared.

--
Please do not top-post. Your answer belongs after (or intermixed
with) the quoted material to which you reply, after snipping all
irrelevant material. See the following links:

<http://www.catb.org/~esr/faqs/smart-questions.html>
<http://www.caliburn.nl/topposting.html>
<http://www.netmeister.org/news/learn2quote.html>
<http://cfaj.freeshell.org/google/> (taming google)
<http://members.fortunecity.com/nnqweb/> (newusers)
 
T

Tor Rustad

Kevin said:
Generally, when developing a program in a scripting language, I follow
an interative development process, starting with some core
functionality, adding functions and variables as the program evolves. In
other words, I don't know in advance what variables I will need to declare.

Neither do I in C, with local variables. We are not supposed to use
global variables anyway.
With C, such an approach doesn't seem practical. You need to identify
some variables ahead of time just to have a program that will compile!

Nope, just watch this:

int main(void)
{
return 0;
}

it compile! Now you can build on that, and put in functionality:

void do_task_1(void)
{
}
void do_task_2(void)
{
}
int main(void)
{
do_task_1();
do_task_2();

return 0;
}

and guess what, the above compile too! Note there are still no variables
there. This is the real power in C, by the technique of
split-and-conquer, you get the ability to handle very complex tasks.

Instead of one massive script, you split the C program in a number of
modules (i.e. source files).

So, I'm wondering what approach seasoned C programmers use for larger
programs, i.e. ones larger than the simple single-function ones I'm
learning from my C textbook. Is there a design process that identifies
such things?

Yes. Sometimes you have a well-designed system to make, all the specs
are there, all the interfaces are set. In such a case, we use a top-down
approach, start with the inter-face, and work my way down to all those
nasty variables.

When prototyping a solution, a more iterative approach may be more
useful, than the top-down. When interfacing HW, I sometimes use
bottom-up, before doing the top level design.
 
R

Richard Heathfield

Tor Rustad said:
Kevin Walzer wrote:


Nope, just watch this:

int main(void)
{
return 0;
}

it compile! Now you can build on that, and put in functionality:

void do_task_1(void)
{
}
void do_task_2(void)
{
}
int main(void)
{
do_task_1();
do_task_2();

return 0;
}

and guess what, the above compile too! Note there are still no variables
there. This is the real power in C, by the technique of
split-and-conquer, you get the ability to handle very complex tasks.

<snip>

This is broadly the approach that I was hoping to find time to outline for
the OP. Well, I thought I'd found the time this evening to expand Tor's
approach with a real-world example, and then spent about an hour trying to
think of an example that was (a) complex enough to be a useful
demonstration of functional decomposition and (b) simple enough to be not
too confusing. Alas, I didn't manage to think of anything!

So I'm going to fold. It's an article that does need to be written, but it
isn't going to happen any time soon, at least not from this desk. (Sigh.)
 
C

CBFalconer

Richard said:
Tor Rustad said:
.... snip ...

<snip>

This is broadly the approach that I was hoping to find time to
outline for the OP. Well, I thought I'd found the time this
evening to expand Tor's approach with a real-world example, and
then spent about an hour trying to think of an example that was
(a) complex enough to be a useful demonstration of functional
decomposition and (b) simple enough to be not too confusing.
Alas, I didn't manage to think of anything!

So I'm going to fold. It's an article that does need to be
written, but it isn't going to happen any time soon, at least
not from this desk. (Sigh.)

This is basically top-down programming, and what I generally
recommend. I suggest that the example will be clearer if you
develop a general purpose filter (stdin to stdout). This will
require sections for interpreting commands, via the command line
options, giving help, and processing a complete file. The action
on the file can be confined to a function, possibly on a per line
basis.

At any rate the result is a compilable 65 line program that I keep
about for modification to the desired filter:

/* Generic filter program with redirection detection 2004-04-04 */

#include <stdio.h>
#include <stdlib.h>

/* ------------------- */

/* This is very likely to be non-portable */
/* DOES NOT check fp open for reading */
/* NULL fp is considered a keyboard here! */
static int akeyboard(FILE *fp)
{
#ifndef __TURBOC__ /* Turbo C is peculiar */
# ifdef __STDC__
/* This dirty operation allows gcc -ansi -pedantic */
extern int fileno(FILE *fp);
extern int isatty(int fn);
# endif
#endif
return ((fp != NULL) && isatty(fileno(fp)));
} /* akeyboard */

/* ------------------- */

void help(void)
{
puts("Got here because no input redirection detected");
} /* help */

/* ------------------- */

int initialize(int argc, char *argv[])
{
if (akeyboard(stdin)) {
help();
return 0;
}
return 1;
} /* initialize */

/* ------------------- */

void cleanup(void)
{
} /* cleanup */

/* ------------------- */

int filter(FILE *in, FILE *out)
{
puts("Input is redirected, carry-on");
return 0;
} /* filter */

/* ------------------- */

int main(int argc, char *argv[])
{
if (!initialize(argc, argv)) return EXIT_FAILURE;
else {
(void)filter(stdin, stdout);
cleanup();
}
return 0;
} /* main */
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,777
Messages
2,569,604
Members
45,208
Latest member
RandallLay

Latest Threads

Top