I'd like to know if it would be possible to store constant string in
an array. I'd first like to avoid pointers so i can see how far we go
without pointers.
Example :
-o-
char str[8] ;
char str[0] = "ab" ;
char str[1] = "cd" ;
...
char str[7] = "op" ;
-o-
2° Would using a structure be more suitable?
3° What about a 2 dimensional array (even if it's a pain in c, with a
good algorithm behind, it should go through)...
4° And at last, if pointers were unvoidable would it be like this ?
-o-
char str[8] ;
char *pstr = str ;
pstr[0] = "ab";
pstr[1] = "cd" ;
-o-
I get for the last part : warning: assignment makes integer from
pointer without a cast
I know it should be 'a' and 'b' but i really need "ab", "cd" ...
No. C can't do it.
You can't store two characters in the space reserved for one...
If that would be possible RAM manufactures would go broke within minutes
:-)
> 2� Would using a structure be more suitable?
>
Maybe. You haven't told use what you want to do.
> 3� What about a 2 dimensional array (even if it's a pain in c, with a
> good algorithm behind, it should go through)...
>
> 4� And at last, if pointers were unvoidable would it be like this ?
>
> -o-
> char str[8] ;
> char *pstr = str ;
>
> pstr[0] = "ab";
> pstr[1] = "cd" ;
> -o-
Again the same mistake.
pstr[0] is ONE character wide. "ab" is TWO characters wide.
> I get for the last part : warning: assignment makes integer from
> pointer without a cast
>
Sure, the compiler is completely confused. It understands
that you want to store some part of the address of the
"ab" character string into the first char of pstr.
> I know it should be 'a' and 'b' but i really need "ab", "cd" ...
hint:
pstr[0] = 'a'
pstr[1] = 'b';
pstr[2] = 'c';
pstr[3] = 'd';
see?
You need 4 characters space to store "abcd". Isn't C wonderful?
This is as close as I can get to what I think you mean:
/* BEGIN new.c output */
array[0] ab
array[1] cd
array[2]
array[3]
array[4]
array[5]
array[6]
array[7] op
/* END new.c output */
/* BEGIN new.c */
#include <stdio.h>
#include <string.h>
int main(void)
{
char array[8][sizeof"ab"] = {"ab","cd"};
unsigned index;
puts("/* BEGIN new.c output */\n");
strcpy(array[7], "op");
for (index = 0; index != sizeof array / sizeof *array; ++index) {
printf("array[%u] %s\n", index, array[index]);
}
puts("\n/* END new.c output */");
return 0;
}
/* END new.c */
--
pete
Yet, nowhere in your message do you make any use of the keyword 'const'.
I've inserted that keyword where I think it would be needed to match the
above description.
> ... I'd first like to avoid pointers so i can see how far we go
> without pointers.
Trying to avoid pointers is pointless and nearly impossible in C. Any
time you call a function by name, the name of the function is
automatically converted into a pointer to the function. Any time you use
an lvalue of array type (which includes most used of string literals
except as initializers for a char array), it is automatically converted
into a pointer to the first element of the array. Trying to use C
without pointers is like trying to use English without the letter 'e'.
You can write C code that doesn't declare any pointer variables, and
such code can even be pretty useful; but you're still crippling yourself
as a C programmer by avoiding pointers.
> Example :
>
> -o-
> char str[8] ;
>
> char str[0] = "ab" ;
This defines str as an array of char (which is a constraint violation
(6.7p3), because str has already been defined in the same scope and same
name space) of length 0 (which is also a constraint violation
(6.7.5.2p1), the length of an array must always be >0).
> char str[1] = "cd" ;
> char str[7] = "op" ;
Those both violate 6.7p3, but at least they don't violate 6.7.5.2p1.
> -o-
>
> 2° Would using a structure be more suitable?
I'm not sure what you actually meant by the first section, and you don't
give any details about what kind of structure you're thinking about.
However, I can say, with absolute certainty, that which of the two
approaches is the better one to use depends entirely upon how you intend
to use it.
> 3° What about a 2 dimensional array (even if it's a pain in c, with a
> good algorithm behind, it should go through)...
This isn't too painful:
const char str2D[8][3] = {"ab", "cd", "", "", "", "", "", "op"};
The nastiest part is the '3'; you need to make that dimension long
enough to hold the longest string you intend to put in this array;
unlike the first dimension of the array, C doesn't provide a way of
automatically setting the remaining dimensions of an array to match the
length of the initializers.
> 4° And at last, if pointers were unvoidable would it be like this ?
>
> -o-
> char str[8] ;
> char *pstr = str ;
>
> pstr[0] = "ab";
> pstr[1] = "cd" ;
> -o-
> I get for the last part : warning: assignment makes integer from
> pointer without a cast
That's perfectly correct. The string literal "ab" causes a piece of
memory three bytes long to be set aside to hold the char values 'a',
'b', and '\0'. The string literal itself is automatically converted into
a pointer to the location where those chars are stored. Then you attempt
to store that pointer value into a char, which is an integer type, not a
pointer type.
If you can overcome your fear of pointers, what you want to do might
correspond to the following:
const char *str1D[8] = {"ab", "cd", NULL, NULL, NULL, NULL, NULL, "op"};
In C99, there's a new feature called "designated initializers" that can
simplify that definition, making it closer to the spirit of your
original code:
const char *str1D[8] = {"ab", "cd", [7] = "op"};
>Hi,
>
>I'd like to know if it would be possible to store constant string in
>an array. I'd first like to avoid pointers so i can see how far we go
>without pointers.
You are going to need to be more specific.
Do you have a constant string that you want to copy into an
array? (Probably not since otherwise you could just strcpy it into
the array.)
Do want the string to be in an array that is constant so it
can never be changed? (Since you cannot assign to a const object, you
would have to initialize the array at the point where it is defined..)
>
>Example :
>
>-o-
>char str[8] ;
>
>char str[0] = "ab" ;
This code contributes nothing but confusion to the discussion since it
attempts to assign a value with pointer type to an object of char
type.
>char str[1] = "cd" ;
>...
>char str[7] = "op" ;
>-o-
>
>2� Would using a structure be more suitable?
In what way would a structure rather than an array change your
question?
>
>3� What about a 2 dimensional array (even if it's a pain in c, with a
>good algorithm behind, it should go through)...
Why would you want a 2D array to hold a single string? What about 2D
arrays do you find painful?
>
>4� And at last, if pointers were unvoidable would it be like this ?
>
>-o-
>char str[8] ;
>char *pstr = str ;
How does this relate to your need for the string to be constant?
>
>pstr[0] = "ab";
This code is just as broken and for the same reason.
>pstr[1] = "cd" ;
>-o-
>I get for the last part : warning: assignment makes integer from
>pointer without a cast
And this surprises you why?
>
>I know it should be 'a' and 'b' but i really need "ab", "cd" ...
Start at the beginning. How many strings do you have? Is the number
known at compile time? Are the values of the strings known at compile
time? If not, at what point in time are the string values fixed so
that you need to treat them as constant for the remainder of the
program? It may help to consider that there is difference between a
constant pointer and a pointer to constant.
--
Remove del for email
Certainly:
char greeting[] = "hello";
But judging by your code that follows, I don't think that's what you
have in mind.
> I'd first like to avoid pointers so i can see how far we go
> without pointers.
If you're dealing with arrays, you're almost certainly using pointers,
at least implicitly. But you can use indexing operations without
necessarily thinking about the pointers behind the scenes.
> Example :
>
> -o-
> char str[8] ;
This declares str as an array of 8 chars.
> char str[0] = "ab" ;
> char str[1] = "cd" ;
> ...
> char str[7] = "op" ;
You're declaring str again, which I presume isn't what you had in
mind; you can't declare multiple objects of the same name in the same
scope. I'm really not sure what you're trying to do here.
> -o-
>
> 2� Would using a structure be more suitable?
>
> 3� What about a 2 dimensional array (even if it's a pain in c, with a
> good algorithm behind, it should go through)...
With the information you've given us so far, I can't tell.
> 4� And at last, if pointers were unvoidable would it be like this ?
>
> -o-
> char str[8] ;
> char *pstr = str ;
>
> pstr[0] = "ab";
> pstr[1] = "cd" ;
> -o-
> I get for the last part : warning: assignment makes integer from
> pointer without a cast
Right, because pstr[0] is a char and "ab", after conversion, is a
char*. You can't store a char* in a char.
> I know it should be 'a' and 'b' but i really need "ab", "cd" ...
Ok -- and what exactly do you want to do with them?
Take a look at this:
#include <stdio.h>
int main(void)
{
const char *arr[] = { "ab", "cd", "ef", "gh", "ij" };
int i;
for (i = 0; i < sizeof arr / sizeof arr[0]; i ++) {
puts(arr[i]);
}
return 0;
}
--
Keith Thompson (The_Other_Keith) ks...@mib.org <http://www.ghoti.net/~kst>
Nokia
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
This is an application from a tutorial in French...if you have some
French language skills you could understand. Skills in German,
Spanish, Italian should help too since it's about a simple verb
conjugation.
In French like in English, the end of a verb is a variable that is
link (or let say that "points" to another variable ; the pronoun ... )
Just for info ; In French, verb are divided into 3 groups. This rule
only applies to verbs that end with "er" like below chantER... So in
the program the radical : "chant" has to be taken away.
Example :
English x French
x
To sing x Chanter
---------- x -------------------------------------
x Pro[9] Verb+ Term[9]
x
I sing x Je chant + e => chante
You sing x Tu chant + es => chantes
He sings x Il chant + e => chante
She sings x Elle chant + e => chante
It sings x Ca chant + e => chante
We sing x Nous chant + ons => chantons
You sing x Vous chant + ez => chantez
They sing x Ils chant + ent => chantent
x Elles chant + ent => chantent
This seems complete but it would be more difficult to give an
explanation in English since you don't have as many variables with
syntax (lucky you!).
As you can see and I realize now, Pro[9] and Term[9] have different
string sizes and they should always match each other (so they should
be incremented together Pro[i] with Term[i])
Pro[0] = "Je"
Pro[3] = "Elle"
...
Term[5] = "ons"
Term[6] = "ez"
...
----------------
In another words : how i see this
----------------
Array of string Pronoun[9] = "Je" "Tu" "Il" ...
Array of string Term[9] = "e" "es" "e" ...
Simple string for Verb
Simple string for Shortverb
integer i for loop
Array of string that will host Pro[i] + ' ' + "Verb" + Term[i]
Enter a string
Read Verb
Check if input is a string that ends with 'e' 'r' '\0'
Replace in "Shortverb" 'e' with '\0'
print "result : "Verb" " and newline
For i = 0 ; i <= Len(Shortverb) ; i++
Concatenate and print Pro[i] + ' ' + "Shortverb" + Term[i] and newline
----------------
Result :
Je chante
Tu chantes
Il chante
...
Vous chantez
...
--------------
Even if i'll be doing very basic stuff for a while, I'd like not to
rely on pointer. As an accountant, learning to deal work with strings
and arrays can be helpful. I understand vba might be best for this,
however i'm not sure. I guess you'll wonder why i'm not learning vba
instead? This is because I first think C has more to offer in the
futur and makes it easier to get involved in web development or os
applications... and at last because of objects, learning vba requires
some resources to practice such as big data sheets or workbooks data
templates... With "C" i can start from scratch like now.
If you can help but plz keep it as simple as you can (i haven't
learned sizeof and what it does yet... i 'll get more on this as soon
as i can,
Thanks
Pascal
> I sing x Je chant + e => chante
> You sing x Tu chant + es => chantes
> He sings x Il chant + e => chante
> She sings x Elle chant + e => chante
> It sings x Ca chant + e => chante
> We sing x Nous chant + ons => chantons
> You sing x Vous chant + ez => chantez
> They sing x Ils chant + ent => chantent
> x Elles chant + ent => chantent
> For i = 0 ; i <= Len(Shortverb) ; i++
> Concatenate and print Pro[i] + ' ' + "Shortverb" + Term[i] and newline
If you want to avoid (explicit) pointers, try this:
#include <stdio.h>
#include <string.h>
#define wordmax 32
int main(void) {
char pro[wordmax][9] =
{"je","tu","il","elle","ca","nous","vous","ils","elles"};
char term[wordmax][9] = {"e","es","e","e","ons","ez","ent","ent"};
char verb[wordmax] = "chant";
char result[wordmax];
int i;
for (i=0; i<sizeof pro[0]; ++i) {
strcpy(result,pro[i]);
strcat(result,"\t");
strcat(result,verb);
strcat(result,term[i]);
puts(result);
}
}
It works by using fixed length char arrays (of size 32 here, but it can be
anything) containing the strings (each of length 0 to 31 characters, plus
the terminator.
In the main loop, a single printf() would have sufficed, but this
demonstrates some string manipulation.
--
bartc
Or possibly something like this:
/* BEGIN new.c output */
array[0] ab
array[1] cd
array[7] op
/* END new.c output */
/* BEGIN new.c */
#include <stdio.h>
int main(void)
{
const char *array[8] = {"ab","cd"};
unsigned index;
puts("/* BEGIN new.c output */\n");
array[7] = "op";
for (index = 0; index != sizeof array / sizeof *array; ++index) {
if (array[index] != NULL) {
Chanterelles are my favorite mushrooms.
Forget about that.
"Pointers" is a fundamental topic in C.
> As an accountant, learning to deal work with strings
> and arrays can be helpful. I understand vba might be best for this,
> however i'm not sure. I guess you'll wonder why i'm not learning vba
> instead? This is because I first think C has more to offer in the
> futur and makes it easier to get involved in web development or os
> applications... and at last because of objects, learning vba requires
> some resources to practice such as big data sheets or workbooks data
> templates... With "C" i can start from scratch like now.
>
> If you can help but plz keep it as simple as you can (i haven't
> learned sizeof and what it does yet... i 'll get more on this as soon
> as i can,
/* BEGIN new.c output */
Pronoun[0] Je
Term[0] e
Pronoun[1] Tu
Term[1] es
Pronoun[2] Il
Term[2] e
/* END new.c output */
/* BEGIN new.c */
#include <stdio.h>
int main(void)
{
const char *Pronoun[] = {"Je","Tu","Il"};
const char * Term[] = { "e","es", "e"};
int index;
puts("/* BEGIN new.c output */\n");
for (index = 0; index != 3; ++index) {
printf("Pronoun[%d] %s\n", index, Pronoun[index]);
printf(" Term[%d] %s\n", index, Term[index]);
putchar('\n');
}
puts("/* END new.c output */");
Yes.
> I'd first like to avoid pointers so i can see how far we go
> without pointers.
As soon as you do anything at all with an array other than
apply the sizeof operator to it, you're using pointers. You
may not see them, but they're there.
> Example :
>
> -o-
> char str[8] ;
Declares an array of eight modifiable characters.
> char str[0] = "ab" ;
Tries to declare an array of zero characters, which causes
the compiler to emit a diagnostic message because C doesn't have
zero-sized objects. Also tries to initialize those non-existent
array elements to contain the two characters 'a' and 'b'; since
two characters won't fit in zero spaces this makes no sense.
> char str[1] = "cd" ;
Declares an array of one modifiable character, but then
tries to initialize that one character to hold two character
values 'c' and 'd'. Since two characters don't fit in one
space, this makes no sense.
> ...
> char str[7] = "op" ;
Declares an array of seven modifiable characters.
Initializes the first two to the values 'o' and 'p', and
the remaining five to zero (not '0').
> -o-
>
> 2� Would using a structure be more suitable?
For what? What are you trying to do? I'm unable to
discern your purpose from the examples given.
> 3� What about a 2 dimensional array (even if it's a pain in c, with a
> good algorithm behind, it should go through)...
What about it?
> 4� And at last, if pointers were unvoidable would it be like this ?
>
> -o-
> char str[8] ;
> char *pstr = str ;
Declares an array of eight modifiable characters. Also
declares a pointer-to-char and initializes it to point at the
array's first element.
> pstr[0] = "ab";
Causes a nameless three-character array to be created
somewhere, containing 'a', 'b', and zero (not '0'). The array
is not "unmodifiable" in a formal sense, but any attempt to
modify it produces undefined behavior.
Then creates a pointer to the first character of that array
(the 'a') and tries to store the pointer in the thing pstr points
at. That thing is a char -- the first char in your eight-element
array -- and since a pointer-to-char is not the same thing as a
char, the attempted assignment makes no sense and the compiler
emits a diagnostic message.
> pstr[1] = "cd" ;
The identities of the characters in the new nameless array
are different, and the attempted assignment is to the eight-char
array's second slot instead of its first, but otherwise it's
like the earlier attempt: Nonsensical and diagnostic-generating.
> -o-
> I get for the last part : warning: assignment makes integer from
> pointer without a cast
>
> I know it should be 'a' and 'b' but i really need "ab", "cd" ...
What are you trying to do?
--
Eric Sosman
eso...@ieee-dot-org.invalid
> bpasc...@googlemail.com wrote:
<snip>
>> I get for the last part : warning: assignment makes integer from
>> pointer without a cast
>>
>> I know it should be 'a' and 'b' but i really need "ab", "cd" ...
>
> What are you trying to do?
To be more specific, what high-level objective are you (the OP) trying
to achieve? Your original question: "I'd like to know if it would be
possible to store constant string in an array. I'd first like to
avoid pointers so i can see how far we go without pointers" is far
from clear. Try to frame your question in non-C terms for now. For
example, your question might mean precisely what it says: "store
constant string in an array", in which case the answer is easy
enough: const char foo[] = "Initial string"; but judging from your
later followup you might actually mean something like "how can I set
up an array to contain strings that I don't plan to change?"
If you simply want an array of strings that you don't plan to change,
the easiest way is to use an array of pointers to string literals. If
you aren't happy with pointers yet, however, that answer isn't
necessarily going to satisfy you.
--
Richard Heathfield <http://www.cpax.org.uk>
Email: -http://www. +rjh@
"Usenet is a strange place" - dmr 29 July 1999
This line unintentionally left unblank
Others have pointed out the contradiction between what you do here and
what you do immediately afterwards.
> char str[0] = "ab" ;
> char str[1] = "cd" ;
> ...
> char str[7] = "op" ;
What I imagine you're trying to do could be conceivable in a higher-
level language as attempting to do:
char str[16]; /* Note larger size, 16 letters */
str[0,1] = ['a','b']; /* Not legal in in C */
str[2,3] = ['c','d'];
...
str[14,15] = ['o'.'p'];
...and you end up with str[] containing "abcdefghijklmnop".
Well, not really, because in C, the above string won't fit into str
[16]: remember that "..." requires a NUL ('\0') at the end.
> 2° Would using a structure be more suitable?
>
> 3° What about a 2 dimensional array (even if it's a pain in >c, with a
> good algorithm behind, it should go through)...
>
> 4° And at last, if pointers were unvoidable would it be like > this ?
Problem: C does not have a native string type. When you try to copy
more than one character at a time, you find that you can't. The
easiest way to accomplish this is by calling strcpy() - which, alas
for you, has as it's arguments two char pointers. C++, which also does
not have a native string type, has a standard string class which,
through operator-overloading,
can be used almost as if it were a native type.
What it seems you are trying to do is add "ab" + "cd" to get "abcd".
If the array containing "ab" is long enough (in this case, at least
char[5]) then you can use strcat(). If the strings you have are of
constant size (I think that's what you meant by saying "constant
strings"), then you might be able to use
strcpy(str, "ab");
strcpy(str+2, "cd");
strcpy(str+4, "ef");
which will save the nanoseconds strcat() spends to find the end of the
first string.
To conclude: to do what you are doing in C requires the use of
pointers. Even a 2-D array won't save you the work required to copy
more than 1 datum at a time.
Using a struct would be very limiting:
struct two_char {
char a, b;
} str[8];
You would still need two assignments for two characters.
str[0].a = 'a', str[0].b = 'b';
str[1].a = 'c', str[1].b = 'd';
etc.
The best I can come up with is (after the above declaration):
struct two_char yada = {'o', 'p'};
str[7] = yada; /* copying a struct /is/ possible */
But (1) you're limited to 2 chars at a time, any more would require a
new struct; and (2) the format "... = {'a', 'b'} can only be used
during initialization, not during assignment.
I may have given you enough information to use or misuse as you will.
But remember, if you misuse it terribly enough, demons /will/ fly out
of your nose. If it doesn't happen on its own, certain members of
c.l.c will visit you and shove the demons into your nose just to make
them fly out. You have been warned ;)
Marty Amandil
-- <Insert your favorite humorous sign-off here>
Actually, I think what he's trying to do (but can't do in C without
overcoming his phobia about pointers) is more like the following:
const char *str[8];
str[0] = "ab" ;
str[1] = "cd" ;
...
str[7] = "op" ;
Notice the syntax is very similar to what he actually wrote; but the
small syntactic differences turn meaningless code into correct code.
The rows/columns of the arrays are mixed up (which is quite common for me).
The declarations should be:
char pro[9][wordmax]...
char term[9][wordmax]...
And the for-loop is simplest just counting from 0 to <9.
However both versions work because the pronouns and terminations are all
less than 9 characters, and the for-loop was a fluke.
--
Bart
Nice! I now need to close my book (snif) and try to implement what you
have written. Because of this over work, i'm blowing out so strong not
many demons like "redundant" tv dish shows will remain for a while :)
Other replies above are very useful too.
Thanks for this.
Pascal
I know the OP said he wanted to avoid explicit pointers, but
it seems so much neater to use them
char *pro[] =
{"je","tu","il","elle","ca","nous","vous","ils","elles"};
char *term[] = {"e","es","e","e","ons","ez","ent","ent"};
[just curious, what's the "ca" thingy? (I failed french)]
this makes sense because 'j' is a character (a char in C terminology)
and "je" is a string, that is it is a pointer to a contiguous sequence
of
chars. A contiguous sequence of chars is not a char. Hence this makes
no sense
char nifnif[2] = "je";
that's an array of two characters whilst "je" is a string or
pointer-to-char. A pointer-to-char won't go in a char. But will go in
pointer-to-char variable (or an array of them).
> char verb[wordmax] = "chant";
char *verb = "chant";
> char result[wordmax];
> int i;
>
> for (i=0; i<sizeof pro[0]; ++i) {
> strcpy(result,pro[i]);
> strcat(result,"\t");
> strcat(result,verb);
> strcat(result,term[i]);
> puts(result);
>
> }
# define ARRAY_SIZE(A) (sizeof(A)/sizeof(A[0])
for (i = 0; i < ARRAY_SIZE (pro); i++)
printf ("%s s%s\n", pro[i], verb, term[i});
<snip>
> In the main loop, a single printf() would have sufficed, but this
> demonstrates some string manipulation.
I only read this after I wrote the code above. I think the printf()
is neater.
--
Nick Keighley
10.3. Transput declarations
{ "So it does!" said Pooh, "It goes in!"
"So it does!" said Piglet, "And it comes out!"
"Doesn't it?" said Eeyore, "It goes in and out like
anything,"
Winnie-the-Pooh, A.A. Milne.}
From the "Revised Report on the Algorithmic Language ALGOL 68"
ca or well written : ça, means it or that ... here :
he sings (il chante),
seh sings(elle chante),
it sings (ça chante) : "ça" is aimed mostly at artefacts (ex.: it's
moving = ça bouge) or when "ça" as a pronoun of a verb is used by an
adult on other things like a person or an animal, it's to express
quite a bad though or make a negative mockery in a specific context
(that thing sings or that thing knows how to sing = ça chante ou ça
sait chanter...) and it can be used by baby childs just for example
because he can't yet make distinctions between animals and toys.
Pascal
http://www.accreditation.freesurf.fr/e.teachyourselfengfr/english/ensfreng0.html
ca or well written : ça, means it or that ... here :
> char *pro[] =
> {"je","tu","il","elle","�a","nous","vous","ils","elles"};
> char *term[] = {"e","es","e","e","ons","ez","ent","ent"};
>> for (i=0; i<sizeof pro[0]; ++i) {
>> strcpy(result,pro[i]);
>> strcat(result,"\t");
>> strcat(result,verb);
>> strcat(result,term[i]);
>> puts(result);
>>
>> }
>
> # define ARRAY_SIZE(A) (sizeof(A)/sizeof(A[0])
>
> for (i = 0; i < ARRAY_SIZE (pro); i++)
> printf ("%s s%s\n", pro[i], verb, term[i});
>
> <snip>
>
>> In the main loop, a single printf() would have sufficed, but this
>> demonstrates some string manipulation.
>
> I only read this after I wrote the code above. I think the printf()
> is neater.
sprintf() is also useful for simple string copy/concatenate, if the result
needs to be passed elsewhere:
sprintf (result,"%s %s%s", pro[i], verb, term[i]);
puts(result);
(and 'verb' should be 'verbroot' or 'verbstem' really).
--
Bart
The definition is not over and in fact seem a quite short.
I should add that "ça" pronounced a bit like "saw" could be used by
someone who has little knowledge in french (a bit like a baby). For
instance a tourist in France can show a leather coat jacket in a shop
and not know that the name in french is : "une veste en cuir" and ask
for the price :
How much does it cost or
How much does that cost ?... in french : Combien est-ce que ça coute ?
That one ? ... in french : Celui-là ?
No, this one. ... in french : Non, celui-ci - - - loop until the right
one :)
This is just to broaden the use of "ça" even if it's not the right
place, i think i'm done, sorry.
Yes. I have a string aversion to tutorials that suggest exercises
that are much better done with features not yet introduced. A small
amount of this is inevitable, but no one should be writing
string-based programs in C without a basic understanding of pointing
to (the start of) an array of characters, and the basic library
functions for manipulating them.
It is a waste of time to learn the wrong what and then the right way.
To the OP: consider getting a copy of K&R2.
--
Ben.
Hi,
Some have been requestiong where i was getting my tut from. I was
reluctant to answer because it's in french and for many it wouldn't
mean much.
Here it is : http://www.ltam.lu/Tutoriel_Ansi_C/
look at application 8.8
And the solution to the application is there : http://www.ltam.lu/Tutoriel_Ansi_C/homesol.htm
Often for this tutorial i find the solution from the author not
applicable outside this tutorial. Even if for now, i don't find
exciting calling that DOS or Unix terminal to see the outputs of what
i'm learning, i hope soon to apply this on more human stuff maybe on
cell phones or whatever...
That's why i'd like to add some more stuff that would make it look
more real if i would use it outside this tutorial.
In the 8.8, the solution works well with little changes from what is
published (maybe a long time ago) :
#include <stdio.h>
#include <string.h>
main()
{
/* Déclarations */
char VERB[20]; /* chaîne contenant le verbe */
char AFFI[30]; /* chaîne pour l'affichage */
int L; /* longueur de la chaîne */
/* Saisie des données */
printf("Verbe : ");
fgets(VERB, 20, stdin) ;
/* Contrôler s'il s'agit d'un verbe en 'er' */
L=strlen(VERB);
if ((VERB[L-3]!='e') || (VERB[L-2]!='r'))
puts("\aCe n'est pas un verbe du premier groupe.!");
else
{
/* Couper la terminaison 'er'. */
VERB[L-3]='\0';
/* Conjuguer ... */
AFFI[0]='\0';
strcat(AFFI, "je ");
strcat(AFFI, VERB);
strcat(AFFI, "e");
puts(AFFI);
}
return 0;
}
It just prints one pronoun otherwise you'd have to write the last
block down from "/*conjuguer ...*/" as many time as there are
pronouns.
I don't find this very efficient when a loop can tweak it and print
all pronouns.
I understand the author did just want to focus on string.h functions.
Because i'm spending 40 % of my time learning by heart, blocks of
structures and functions,
40 % doing applications from the tutorial above,
10 % reading and browsing the web for information
and the last 10 % locating bugs.
Learning by heart is special but i'm lazy and i kinda find it easier
than starting an application from scratch... If i find myself a way
to achieve an application from this tutorial, let say with 2 more
loops and 1 or 2 more if (my code is heavier than the author's) then,
i find it less rewarding as when i can apply something i have learned
by heart and it works.
Pascal
>> It is a waste of time to learn the wrong what and then the right
>> way.
"wrong way" of course.
>> To the OP: consider getting a copy of K&R2.
>>
>> --
>> Ben.
Its best to snips sigs -- even short ones. Better, also, to leave the
attribution line (the "so and so writes:" bit at the top) which you've
cut.
> Some have been requestiong where i was getting my tut from. I was
> reluctant to answer because it's in french and for many it wouldn't
> mean much.
>
> Here it is : http://www.ltam.lu/Tutoriel_Ansi_C/
Apart from the detail of using gets, the worst of it the order in which
things are introduced. Casts (rarely needed/used) come in chapter 3
but function have to wait until chapter 10 (last but one). Pointers
(a basic overview thereof) should be covered at the same time as
arrays and after functions so you can start to write functions to do
interesting things with arrays and, later, strings.
> look at application 8.8
>
> And the solution to the application is there : http://www.ltam.lu/Tutoriel_Ansi_C/homesol.htm
<snip>
It's absurd. The code presents includes ". . ." showing where you
have to repeat all the code! This is what functions a for.
<snip>
--
Ben.
Pascal, your articles are showing up 2 or 3 time each. Suggestion:
Don't assume a post hasn't gone through until you've checked the
newsgroup a while later.
Actually, it does. It sets nifnif[0] to 'j' and nifnif[1] to 'e'.
It's potentially dangerous, though; since the size of the array
exactly matches the length of the string literal, no trailing '\0' is
stored (this is a special-case rule).
To avoid that problem:
char nifnif[] = "je";
This makes the compiler determine the length of the string;
sizeof nifnif will be 3.
An initializer for a char array is one of the three contexts in which
an array expression *isn't* implicitly converted to a pointer to the
array's first element (the other two being the operand of a unary "&"
or "sizeof" operator).
>> It is a waste of time to learn the wrong what and then the
>> right way.
>>
>> To the OP: consider getting a copy of K&R2.
>
> Hi,
>
> Some have been requestiong where i was getting my tut from. I
> was reluctant to answer because it's in french and for many it
> wouldn't mean much.
You might be interested to know that K&R2 has been translated into
many languages, including French.
From the K&R2 site <http://cm.bell-labs.com/cm/cs/cbook/>:
# French: Le Langage C, Masson, ISBN 2-225-82070-8
# French: Le Langage C: Norme ANSI, Dunod, ISBN 2-100-05116-4 (2nd
ed.)
<snip>
--
int i;main(){for(;i["]<i;++i){--i;}"];read('-'-'-',i+++"hell\
o, world!\n",'/'/'/'));}read(j,i,p){write(j/p+p,i---j,i/i);}
~ Anonymous (1984 IOCCC winner)
Hi,
I think a comfortable level in algorithmic is required to learn from
this book as i've seen some its applications on the web. It really
looked above my present understanding and expectation of programming.
Below is what took me a few hours :( from the first post in this
discussion.
There are 2 codes ; the first one with pointers, the second one with
structures arrays.
I'm not sure but i think the second post is closer to what i'd
implement with higher languages... There are still pointers in it but
it seems to me the layout is closer to higher programming languages.
Extracting pointers from it is out of reach for me...
I don't want to avoid pointers, i just would like to find there are
alternatives to pointers. It sounds weird since pointers are the core
of C... I also think, pointers skip some algorithms implementation. At
a very basic level like mine in programming, i find it easier to lay
down code code on a blank paper with a pen and algorithm rather than
start straight with pointers...
===
#include <stdio.h>
#include <string.h>
/* THIS PROGRAM CONJUGATES A FRENCH VERB FROM THE 1ST GROUP
(like chanter, penser...) AT PRESENT TIME USING UBIQUITOUS C
POINTERS*/
int main(void)
{
int n = 20 ;
char Verb[n] ;
char Verb2[n] ;
int i, j, cnt ;
/* Below is largely inspired from Pete's code in this
discussion */
const char *pro[] = { "je", "tu", "il", "elle", "nous", "vous",
"ils", "elles" } ;
const char *term[] = { "e", "es", "e", "e", "ons", "ez", "ent",
"ent" } ;
puts("\n\nEntrez un verbe du 1er groupe : ") ;
fgets(Verb, 20, stdin) ;
puts("------------\n");
cnt = strlen(Verb) ;
strcpy(Verb2, Verb) ;
if ( (Verb2[cnt-3] != 'e') && (Verb2[cnt-2] != 'e') )
puts("\aCe n'est pas un verbe du premier groupe.!");
else
Verb2[cnt-3] = '\0' ;
for (i = 0, j = 0; i < sizeof pro / sizeof pro[0], i < sizeof
term / sizeof term[0]; i ++)
printf("%s %s%s\n", pro[i], Verb2, term[i] ) ;
printf("\n\n");
return 0;
}
===
===
#include <stdio.h>
#include <string.h>
/* THIS PROGRAM CONJUGATES A FRENCH VERB FROM THE 1ST GROUP
(like chanter, penser...) AT PRESENT TIME USING STRUCTURES*/
typedef struct Conju Conju2 ;
struct Conju
{
char *Pro ;
char *Term ;
} ;
int main(void)
{
Conju2 Conju[7] ;
int n ;
char verb[40] ;
char verb2[40] ;
int i ; int cnt ; int cnt2 ; int cnt3 ;
Conju[0].Pro = "Je " ;
Conju[1].Pro = "Tu " ;
Conju[2].Pro = "Il ";
Conju[3].Pro = "Elle ";
Conju[4].Pro = "Nous " ;
Conju[5].Pro = "Vous ";
Conju[6].Pro = "Ils " ;
Conju[7].Pro = "Elles " ;
Conju[0].Term = "e" ;
Conju[1].Term = "es" ;
Conju[2].Term = "e" ;
Conju[3].Term = "e" ;
Conju[4].Term = "ons";
Conju[5].Term = "ez" ;
Conju[6].Term = "ent" ;
Conju[7].Term = "ent " ;
printf("\n\nEntrez un verbe du 1er groupe : ") ;
fgets(verb, 50, stdin) ;
cnt = strlen(verb) ;
strcpy(verb2, verb) ;
if ( (verb2[cnt - 3] != 'e') || (verb2[cnt - 2] != 'r') )
printf("\nCe n'est pas un verbe du 1er groupe") ;
else
verb2[cnt-3] = '\0' ;
printf("\n\n%s", verb) ;
printf("\n\n%s\n\n", verb2 ) ;
for ( i = 0 ; i < 8 ; i++ )
printf("\n%s%s%s", Conju[i].Pro, verb2, Conju[i].Term) ;
printf("\n\n") ;
return 0 ;
}
I just think the 2nd code is closer to higher programming languages...
Pascal
snip
>#include <stdio.h>
>#include <string.h>
>
>/* THIS PROGRAM CONJUGATES A FRENCH VERB FROM THE 1ST GROUP
> (like chanter, penser...) AT PRESENT TIME USING UBIQUITOUS C
>POINTERS*/
>
>int main(void)
>{
>
> int n = 20 ;
> char Verb[n] ;
> char Verb2[n] ;
This is valid only in C99.
> int i, j, cnt ;
>
> /* Below is largely inspired from Pete's code in this
>discussion */
>
> const char *pro[] = { "je", "tu", "il", "elle", "nous", "vous",
>"ils", "elles" } ;
> const char *term[] = { "e", "es", "e", "e", "ons", "ez", "ent",
>"ent" } ;
>
> puts("\n\nEntrez un verbe du 1er groupe : ") ;
> fgets(Verb, 20, stdin) ;
> puts("------------\n");
> cnt = strlen(Verb) ;
>
> strcpy(Verb2, Verb) ;
>
> if ( (Verb2[cnt-3] != 'e') && (Verb2[cnt-2] != 'e') )
Surely the last expression should be 'r' and the && should be ||. As
it reads now, the verb etre will pass your test.
> puts("\aCe n'est pas un verbe du premier groupe.!");
It's nice to put out the error message but then you process the data
anyway as if it were acceptable input.
> else
> Verb2[cnt-3] = '\0' ;
Are you sure there are no 19 letter verbs?
>
> for (i = 0, j = 0; i < sizeof pro / sizeof pro[0], i < sizeof
>term / sizeof term[0]; i ++)
First, can the two quotients ever be different?
Second, are you aware that the comma operator discards the results of
the left operand? Therefore, sizeof pro takes no part in determining
if the loop should terminate. If you really need to check both, you
probably want the logical and (&&) operator.
Unfortunately, this object does not exist.
>
> Conju[0].Term = "e" ;
> Conju[1].Term = "es" ;
> Conju[2].Term = "e" ;
> Conju[3].Term = "e" ;
> Conju[4].Term = "ons";
> Conju[5].Term = "ez" ;
> Conju[6].Term = "ent" ;
> Conju[7].Term = "ent " ;
Neither does this one.
>
> printf("\n\nEntrez un verbe du 1er groupe : ") ;
> fgets(verb, 50, stdin) ;
verb is only 40 char, not 50.
>
> cnt = strlen(verb) ;
>
> strcpy(verb2, verb) ;
>
> if ( (verb2[cnt - 3] != 'e') || (verb2[cnt - 2] != 'r') )
> printf("\nCe n'est pas un verbe du 1er groupe") ;
You did the if right but you still process the invalid data.
> else
> verb2[cnt-3] = '\0' ;
>
> printf("\n\n%s", verb) ;
> printf("\n\n%s\n\n", verb2 ) ;
>
> for ( i = 0 ; i < 8 ; i++ )
> printf("\n%s%s%s", Conju[i].Pro, verb2, Conju[i].Term) ;
The last iteration invokes undefined behavior.
>
> printf("\n\n") ;
>
> return 0 ;
>}
--
Remove del for email
> Some have been requestiong where i was getting my tut from. I was
> reluctant to answer because it's in french and for many it wouldn't
> mean much.
>
> Here it is : http://www.ltam.lu/Tutoriel_Ansi_C/
Ditch it. It doesn't know whether it is a tutorial for ISO C (and what
do Frenchmen have to do with ANSI, anyway), C for MS-DOS, or Borland C;
in fact, the writer even seems to think that Borland's choices for
integer sizes are a requirement of MS-DOS, which isn't the case. It uses
gets(), and doesn't mention that this is a highly dangerous function
which should never be used; this is always a sign of an author who
shouldn't be teaching, but learning himself. It declared main as main(),
which is strictly speaking correct, but bad style. And as has already
been said, the order in which it does things is educationally unwise.
In short, it is a bad tutorial. What's worse, it is a deceptively bad
tutorial, because while not good, it is also not atrocious, so if you're
a beginner, it _looks_ like quite a good tutorial. But it will lead you
astray - in fact, it already _is_ leading you astray.
Ditch it. Get K&R instead.
Richard
jacob navia wrote:
> bpasc...@googlemail.com wrote:
>> Hi,
>>
>> I'd like to know if it would be possible to store constant string in
>> an array. I'd first like to avoid pointers so i can see how far we go
>> without pointers.
>>
>> Example :
>>
>> -o-
>> char str[8] ;
>>
>> char str[0] = "ab" ;
>> char str[1] = "cd" ;
>> ...
>> char str[7] = "op" ;
>> -o-
>>
>
> No. C can't do it.
>
> You can't store two characters in the space reserved for one...
>
> If that would be possible RAM manufactures would go broke within minutes
> :-)
>
>
>> 2� Would using a structure be more suitable?
>>
>
> Maybe. You haven't told use what you want to do.
>
>
>> 3� What about a 2 dimensional array (even if it's a pain in c, with a
>> good algorithm behind, it should go through)...
>>
>> 4� And at last, if pointers were unvoidable would it be like this ?
>>
>> -o-
>> char str[8] ;
>> char *pstr = str ;
>>
>> pstr[0] = "ab";
>> pstr[1] = "cd" ;
>> -o-
>
>
> Again the same mistake.
>
> pstr[0] is ONE character wide. "ab" is TWO characters wide.
>
To nitpick somewhat, "ab" is as wide as the pointer width, and it points
to a constant array of size sizeof(char)*3. pstr[0] = "ab"; would
probably generate a warning about converting pointers to ints without
casts and another one about truncating int to char.
- --
- --Falcon Darkstar Christopher Momot
- --
- --OpenPGP: (7902:4457) 9282:A431
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.9 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org
iQIcBAEBAgAGBQJKdglkAAoJEOGPymTbQp7GFxIQALO3Lsos6czp6GosvZeB5kwu
BVAB6S/oyLsEXuBpqFac7c3D4JVjyhuT6h0/YyTTgNirASvoNUi4RJBb1zEAFVPt
oIaR6ALFVDM05Dw5AgKauR5XHVvlU6S0hNc32SzhneSeXbqmbtg9cjEwLqvrb/Rq
jIbh4J/aXB0OZ24RWgNIy3Jtr9oAlxMOBd4YF7ZJGVyTTTLo8q+fV1cyocGFYrPN
pbI0vpkMLR4xF32p5/MEtARdCI7xMXTAURZPifcbVU7YZJ7meW9LcAQbt2+SaKyN
ODRh+W9nJZqqhhXTAlTXoWVwIL/Ipq/K7dA+g8mW4QdyA3ZvFLqfzAKwAIW/90DA
fZ+jvuFmwPyHAkGRJeAHX8RTL2xqpNiLx1Qk8aeSwSIreCYWci8ssCevqhkQuNyo
kIJczUMj2NV4sfvcw/5WbHJh3QqwYGiz18BMsjhl/+rDdWeErNt7HhnOtRNpxh5d
PObkOOvJ7yJpbtjSTgHBJqlxWnZrPFCEeshmPwCzizi1fnPw+Eph3VwdFASF5Q9u
PWCp6MdTQLl5VqBIhjGQD94gcji2TLebn+EoCYMzXDtukIW0EhqcA709VXW9UOqZ
DszceiRhO+nm0vyK5yNkzJISub4MmPUL0IbJe72Q5ZTaZTaO7ZKE8UC0/Ye2KRtv
8AbcYIEEhmxWWHRoAB+q
=v5mX
-----END PGP SIGNATURE-----
To nitpick a bit more, "ab" itself is three characters wide in
most contexts ('a', 'b', '\0'). Since it's an array expression,
it's implicitly converted to a char* pointer to the array's first
element in most, but not all, contexts.
Yet another exception is that this:
char not_a_string[2] = "ab";
is legal, and sets not_a_string to { 'a', 'b' } (no terminating '\0').
Hi,
Why if the code compiles well under linux and windows without
warnings, should i be looking for "perfection" ?
I'll read your review carefully so i see what i need to bring my
attention on or just what i need to "update" even if i'm just starting
to learn. Thanks in any case.
Your review might help understand why almost the same structure apply
to english verbs is not working, it prints things like :
I
sing
...
He
sings
...
For the english version, let say to make thinks simple, i skip any
other verb that end with -y or -o ...
About the tutorial where i'm learning C, i have to say again i don't
feel to complain much because it's free and simple to start with. I
chose a french tutorial because i didn't think i'll rely so much on
usenet and in the french versions, replies for similar posts as this
one can take a long time... As i said, i'm not waiting a reply before
keeping on learning something else but french usenet discussions are
not so "active".
This tutorial even if the code is "outdated" makes reference to
algorithms structures. I think algorithms is something i must
concentrate on if one day i don't want to keep learning things by
heart and learn other languages. I have to say i didn't attend ant
computer or programming courses in college or university so i don't
know really apart from looking on the web, how a computer language
degree is made with.
And if i feel like starting with any other good C book, i have to go
through this basic tutorial and like any other ones (i have seen
similar ones in english with applications also that looked
interesting...).
I was wondering, why are there so few C online courses offers ? C++,
Java Certificates are very common but C???
Is learning C like learning how to walk and C++ or Java how to drive ?
Thx,
Pascal
Because a lack of warnings doesn't imply that the code is correct,
and compilers are generally unable to warn about undefined behavior.
(The language defines certain errors as undefined behavior precisely
because they're errors that the compiler can't always be expected
to diagnose.)
The worst possible result of undefined behavior is that the program
behaves just as you expect it to. That doesn't mean you were lucky;
it means the error will be more difficult to track down -- until
it goes bad at exactly the worst possible moment.
(I'm basing this just on Barry's comment -- for which, BTW, you
deleted the attribution line. I haven't studied your code.)
You shouldn't be worried about perfection yet, you've got a very long
way to go before worrying about that. For now, worry about removing the
most serious defects in your code - and undefined behavior is one of the
most serious categories of defects your code can have. One of the key
reasons why it is so serious is that compilers are not required to
diagnose it, and the reason why they're not required to do so is that,
on many implementations, diagnosing any particular instance of undefined
behavior might be too difficult to justify requiring those
implementations to do so.
The fundamental problem that he's referring to is the fact that the
Conju array was declared as having only 7 elements, whereas your code,
in three different places, refers to Conj[7], which would (if it did not
have undefined behavior) refer to the non-existent 8th element of the
array. This might work without a problem if the position where the 8th
element would go doesn't happen to be currently in use by any other part
of the program, but that's just random luck, and it's bad luck, because
it makes your program appear to work correctly despite the fact that it
has a very serious problem.
>
>>
>> The last iteration invokes undefined behavior.
>>
>>
>
>Hi,
>
>Why if the code compiles well under linux and windows without
>warnings, should i be looking for "perfection" ?
Perfection may or may not be a goal worth striving for. I leave that
to the philosophers, especially since I cannot help you get there. My
comments were aimed much lower, just mere competence. If you don't
think undefined behavior is something worth eliminating, even for a
hobbyist, then you are wasting your time here as well as ours.
> > >> To the OP: consider getting a copy of K&R2.
>
> I think a comfortable level in algorithmic is required to learn from
> this book
I've no idea what "comfortable level in algorithmic" means.
("comfortable with algorithms"?). But I'm pretty sure K&R doesn't
require it.
> as i've seen some its applications on the web.
you've seen K&R quoted on the web?
> It really
> looked above my present understanding and expectation of programming.
it does take careful reading. But your care is well rewarded.
<snip>
> Some have been requestiong where i was getting my tut from. I was
> reluctant to answer because it's in french and for many it wouldn't
> mean much.
sorry couldn't resist:-
"tut: Noun. Rubbish, nonsense. E.g."Whatever he told you about me is
just a load of tut."" Dictionary of Slang
:-)
>int main(void)
>{
> int n = 20 ;
> char Verb[n] ;
> char Verb2[n] ;
>>>C99 is very recent i guess, since i think the code above works under gcc linux but not djgpp even if the 2 run with same standard, maybe between the two, one has all updates working. I'm not sure at all about what i'm saying. I know for another code i spent an hour debugging it as it was working very well under linux or windows i don't remember which one.
> if ( (Verb2[cnt-3] != 'e') && (Verb2[cnt-2] != 'e') )
Surely the last expression should be 'r' and the && should be ||. As
it reads now, the verb etre will pass your test.
>>>
a typo mistake and i didn't notice it on execution as i quickly check
with expected entries (verbe that end with e and r : chanter, penser,
trouver...
Good remark for && that should be ||...
It's nice to put out the error message but then you process the data
anyway as if it were acceptable input.
>>>
I believe a do-while loop will be better here.
Are you sure there are no 19 letter verbs?
>>>
95% sure. A resizable array would do fine. I'm currently learning
stdlib - malloc, calloc, realloc ...
> for (i = 0, j = 0; i < sizeof pro / sizeof pro[0], i < sizeof term / sizeof term[0]; i ++)
First, can the two quotients ever be different?
>>>
I don't know at all how this code works. I got it from Pete's post/
reply earlier in this discussion. I take it as it is, i guess if i
keep on coding, sooner or later i'll understand
Second, are you aware that the comma operator discards the results of
the left operand? Therefore, sizeof pro takes no part in determining
if the loop should terminate. If you really need to check both, you
probably want the logical and (&&) operator.
>>>
If i understand well ; "...i < sizeof pro / sizeof pro[0], i < sizeof
term / sizeof term[0]..." --- "...i < sizeof term / sizeof term[0]" is
the taken into consideration alone? As this code as it is, is from
Pete earlier in this post, I can't tell much. See if he still reads
posts in this discussion.
Unfortunately, this object does not exist.
Neither does this one.
>>>
What object ? There are 2 distinct code and both works indepentantly
from the other. Variable names slighlty change "verb" is used in one
and "Verb" is used in the other one.
You did the if right but you still process the invalid data.
>>> yes, same as above
The last iteration invokes undefined behavior.
>>>
Do you mean i < 8 is not right ? Earlier was declared Conju2 Conju
[7]. This declaration means there are 8 values if zero is a value.
This is quite in computing, I have seen it with vba...
Thanks for this review,
Pascal
Hi Keith,
My last post is a reply to Barry's comment. There, i mention the code
which i think has undefined behavior. Barry didn't say much about it
so i could only guess where would this would be.
>>>
for ( i = 0 ; i < 8 ; i++ )
printf("\n%s%s%s", Conju[i].Pro, verb2, Conju
[i].Term) ;
The code is in fourth post earlier in this current discussion page.
Thanks,
Pascal
Hi,
As my 2 last replies a few minutes ago, Conj[7] in a loop has 8
itiration starting from 0 and, i have assigned Conj[7] with a value
that the code takes in consideration. So the code should behave well
here or did i miss something when i was learning these.
I know in vba we can set base 0 to 1. I don't know if that can be done
in C (it would help!). Maybe this can be done if Array[0] is set with
a no value and any loops in this array start at 1...
Thanks,
Pascal
The above was written by James Kuyper. Please stop snipping
attribution lines.
> As my 2 last replies a few minutes ago, Conj[7] in a loop has 8
> itiration starting from 0 and, i have assigned Conj[7] with a value
> that the code takes in consideration. So the code should behave well
> here or did i miss something when i was learning these.
Yes, you missed something. You declared Conju as:
Conju2 Conju[7];
Either assigning a value to Conju[7] or reading the value of Conju[7]
invokes undefined behavior, since Conju[7] does not exist. The
elements that do exist are Conju[0], Conju[1], ..., Conju[6].
If the memory location that *would* have held Conju[7] happens
not to be used by anything else, then it's likely you'd get away
with it. Getting away with it is the worst thing that can happen.
If you actually need to refer to Conju[7], you need to define the
array with 8 elements. If you define Conju with 7 elements, you must
not refer to Conju[7].
> I know in vba we can set base 0 to 1. I don't know if that can be done
> in C (it would help!). Maybe this can be done if Array[0] is set with
> a no value and any loops in this array start at 1...
No, C arrays start at 0. There are ways to pretend that they
start at 1; some ways work but waste space, others invoke undefined
behavior. If you're trying to learn C, you should learn to deal
with 0-based arrays; don't fight the language.
I now see my mistake. It'll take time before i get away from such
basic mistakes!
Thanks
<=== Conju2 Conju[7] ;
===> Conju[8] ;
Conju[0].Pro = "Je " ;
Conju[1].Pro = "Tu " ;
Conju[2].Pro = "Il ";
Conju[3].Pro = "Elle ";
Conju[4].Pro = "Nous " ;
Conju[5].Pro = "Vous ";
Conju[6].Pro = "Ils " ;
Conju[7].Pro = "Elles " ;
Conju[0].Term = "e" ;
>
Actually Keith wrote the following. You should preserve attributions.
>> The worst possible result of undefined behavior is that the program
>> behaves just as you expect it to. That doesn't mean you were lucky;
>> it means the error will be more difficult to track down -- until
>> it goes bad at exactly the worst possible moment.
>>
>> (I'm basing this just on Barry's comment -- for which, BTW, you
>> deleted the attribution line. I haven't studied your code.)
>>
>> --
>> Keith Thompson (The_Other_Keith) ks...@mib.org <http://www.ghoti.net/~kst>
>> Nokia
>> "We must do something. This is something. Therefore, we must do this."
>> -- Antony Jay and Jonathan Lynn, "Yes Minister"
You should not quote signatures unless you are commenting on them
specifically.
>
>Hi Keith,
>
>My last post is a reply to Barry's comment. There, i mention the code
>which i think has undefined behavior. Barry didn't say much about it
>so i could only guess where would this would be.
>>>>
> for ( i = 0 ; i < 8 ; i++ )
> printf("\n%s%s%s", Conju[i].Pro, verb2, Conju
>[i].Term) ;
Conju was defined as an array of 7 structures. The legal subscripts
run from 0 to 6. This loop will attempt to access the non-existent
structure Conju[7] which still invokes undefined behavior.
>
>The code is in fourth post earlier in this current discussion page.
Usenet is not known for preserving chronological order.
>Hi Barry,
snip
>> for (i = 0, j = 0; i < sizeof pro / sizeof pro[0], i < sizeof term / sizeof term[0]; i ++)
>
>First, can the two quotients ever be different?
>
>>>>
>I don't know at all how this code works. I got it from Pete's post/
>reply earlier in this discussion. I take it as it is, i guess if i
>keep on coding, sooner or later i'll understand
Pete only sent two messages in this thread, on 29 July and 30 July.
Neither contains that code.
Copying code without understanding is a bad habit to get into.
snip
>
> Unfortunately, this object does not exist.
>
>Neither does this one.
>
> >>>
> What object ? There are 2 distinct code and both works indepentantly
>from the other. Variable names slighlty change "verb" is used in one
>and "Verb" is used in the other one.
Why did you snip the line of code the comment referred to? Your reply
style makes it very difficult to have a coherent discussion.
> I know in vba we can set base 0 to 1. I don't know if that can be done
> in C (it would help!).
There used to be something called "training wheels"
that people put on bicycles for their children.
I think eventually people realised
that you can't learn to ride a bike that way.
> Maybe this can be done if Array[0] is set with
> a no value and any loops in this array start at 1...
Whenever I see code like that, I think
"Pascal programmers, forced to write C at gunpoint".
--
pete
Whenever I see code like that, I think "Aaaaargh - why am
I reading Numerical Recipies in C?"!
Phil
--
If GML was an infant, SGML is the bright youngster far exceeds
expectations and made its parents too proud, but XML is the
drug-addicted gang member who had committed his first murder
before he had sex, which was rape. -- Erik Naggum (1965-2009)
> Even if i'll be doing very basic stuff for a while, I'd like not to
> rely on pointer. As an accountant, learning to deal work with strings
> and arrays can be helpful.
See, that's a problem. Strings and arrays *are* pointers in C.
An array is a pointer to a block of contiguous memory containing
like-typed values; a string is an array of characters.
If you intend to use strings and arrays, you must use pointers.
You may, however, use them very gently, in a way that means you
can think of them as strings and arrays and needn't worry too
much about getting them tangled.
In your place, with your application, I would start off like this:
-----------------------------------------------------------
/* this typedef makes mot into a type which can hold
strings up to 15 characters long. */
typedef char[16] mot;
/* Now make noms an array which can hold up to 9 mots, initialized to
the French pronouns */
mot noms[9] = {"Je","Tu","Il","Elle","Ca","Nous","Vous", "Ils","Elles"};
/* Finally make an array for the corresponding suffixes for regular
verb conjugations */
mot terminaisons[9] = {"e","es","e","e","e","ons","ez","ent","ent"};
--------------------------------------------------------------
Now, I won't lie to you; mot is a pointer type. noms and terminaisons
are pointers to memory blocks filled with more pointers. You can think
of them as strings and arrays if you're more comfortable that way, but
strings and arrays are only specialized kinds of pointers.
Bear
Confusing arrays with pointers is very common, probably because of the
fact that arrays are often converted into pointers by the rules of C.
With three exception, an lvalue of array type is usually automatically
converted into a pointer to the first element of the array. A
declaration of a function parameter as if it were an array is
automatically converted into a declaration of a pointer to the element
type of the array.
If an array was a pointer, then given the following declaration:
int array[10];
sizeof(array) would be equal to sizeof(int*) rather than 10*sizeof(int),
and &array would have the type int**, rather than int (*)[10].
> ... a string is an array of characters.
According to 7.1.1p1, "A string is a contiguous sequence of characters
terminated by and including the first null character". That sequence
need not constitute an entire array; it could just be part of one, such
as, for example, the string starting at ("Hello, world!" + 7), which
consists of 7 characters and has a length of 6.
> In your place, with your application, I would start off like this:
>
> -----------------------------------------------------------
> /* this typedef makes mot into a type which can hold
> strings up to 15 characters long. */
> typedef char[16] mot;
,,,
> Now, I won't lie to you; mot is a pointer type.
No, mot is an array type, though it would be converted into a pointer
type if used to declare a function parameter. sizeof(mot) will be 16,
which, on most implementations, will not be the same as sizeof(char*).
I would recommend against using such a typedef, because of the peculiar
rules that C has for handling arrays. It's generally a bad idea to use a
typedef to hide the fact that that something is either an array or a
pointer, because it can lead to code that looks right but doesn't
actually work (and vice versa).
No, that is WRONG!
An array is a block of memory, not a pointer to the block. Try taking
the size of an array to see this. It's just that there is an automatic
conversion from the array name to a pointer to the first element of the
array in most situations. However, not keeping the distinction clear
leads to a lot of confusion.
> If you intend to use strings and arrays, you must use pointers.
Now that is, basically, true.
> You may, however, use them very gently, in a way that means you
> can think of them as strings and arrays and needn't worry too
> much about getting them tangled.
>
> In your place, with your application, I would start off like this:
>
> -----------------------------------------------------------
> /* this typedef makes mot into a type which can hold
> strings up to 15 characters long. */
> typedef char[16] mot;
I don't like typedefs of array types.
> /* Now make noms an array which can hold up to 9 mots, initialized to
> the French pronouns */
> mot noms[9] = {"Je","Tu","Il","Elle","Ca","Nous","Vous", "Ils","Elles"};
>
> /* Finally make an array for the corresponding suffixes for regular
> verb conjugations */
> mot terminaisons[9] = {"e","es","e","e","e","ons","ez","ent","ent"};
> --------------------------------------------------------------
>
> Now, I won't lie to you; mot is a pointer type.
You may not be lying, but you are definitely WRONG. mot is an array
type, not a pointer type.
> noms and terminaisons
> are pointers to memory blocks filled with more pointers.
No, they are arrays. Arrays of arrays to be more precise.
> You can think
> of them as strings and arrays if you're more comfortable that way, but
> strings and arrays are only specialized kinds of pointers.
This is also wrong.
I suggest you read chapter 6 of the comp.lang.c FAQ over at
http://c-faq.com/
--
Flash Gordon
No, no, INT_MAX times no!
Arrays are not pointers. Pointers are not arrays.
An array is not a pointer to a block of contiguous memory, it
is the block itself. Arrays are manipulated using pointers, but
pointers to individual elements, not usually to the whole array.
(You can have a pointer to an array, but it's not the same thing
as a pointer to the array's first element; it's of a different type.)
A string is a data format, not a data type; an array may *contain*
a string.
You need to read and understand section 6 of the comp.lang.c FAQ
<http://www.c-faq.com>.
I understand C vocabulary can rely on pointer for anything... That's
why i understand as well from studying for the last 3-4 months / 20-40
hrs a week, i haven't really started learning C since i was trying to
keep myself away from pointers.
As i said earlier, i'm new to programming. Like any other subjects a
good understanding of the basics will help later on unlike starting
straight with :
while ( *pc++ = *pb++ ) ; which is for me an obscure way to copy
elements from pb to pc (formerly declared as : char buffer[128] ; char
clearbuf[128] ; char *pb = buffer ; char *pc = clearbuf and sp on ...
it took me a while to understand this...arghhhh ! I think this is
still simple in the pointers chapter, pointers to functions and
memalloc will make things a lot more spicy.
About this discussion, you all should have a $10 fine for overspeed. I
really was looking for a "non-pointer" way to achieve this. Here it is
a few html pages later on the tutorial site i'm learning from :
#include <stdio.h>
#include <string.h>
int main(void)
{
char SUJ[6][5] = {"je","tu","il","nous","vous","ils"};
char TERM[6][5] = {"e","es","e","ons","ez","ent"};
char VERB[20];
int L;
int I;
printf("Verbe : ");
scanf("%s", VERB);
L=strlen(VERB);
if ((VERB[L-2] != 'e') || (VERB[L-1] != 'r'))
printf("\"%s\" n'est pas un verbe du premier groupe.\n",VERB);
else
{
VERB[L-2]='\0';
for (I=0 ; I<6 ; I++)
printf("%s %s%s\n",SUJ[I], VERB, TERM[I]);
}
return 0;
}
It works just fine without any *pointers, structures and so on.
Just 2 dimensional arrays made it.
I guess this is the end of this discussion. Whatever the output, I
learned a lot from any discussion i initiate or that i can read from
others. I should soon be posting a lot as i'm about to enter pointers
chapter.
There are still a few things i'd like to learn on how to do without
pointers. By the way, how is it possible to achieve a good level in
programming without getting things done with simplicity? I'm not a
simple person and as i can understand that, i will not be a good
programmer or not in an easy way. However, as C is a lot about
pointers, i might find things easier when i know more about them.
Thx,
Pascal
Ouch! OK. You go at whatever speed you need to. It is hard to hold
back and not suggest improvements (see below!) but you can always
ignore a post.
> I
> really was looking for a "non-pointer" way to achieve this. Here it is
> a few html pages later on the tutorial site i'm learning from :
You wanted a "non-star" way to do it -- you can't use arrays without using
pointers; it is just that your tutorial has kept this from you.
<snip code>
Just for your consideration, here is how I would write the same
program that you wrote. There are lots of little changes. Some are
significant (limiting the length of a string scan is a very good thing
to get into the habit of doing) and others are just stylistic
alternatives. Just seeing an alternative can sometimes be helpful:
#include <stdio.h>
#include <string.h>
int main(void)
{
char verb[20];
int len;
printf("Verbe : ");
scanf("%19s", verb);
len = strlen(verb);
if (strcmp(verb + len - 2, "er") != 0)
printf("\"%s\" n'est pas un verbe du premier groupe.\n", verb);
else {
char *suj[] = {"je", "tu", "il", "nous", "vous", "ils"};
char *term[] = {"e", "es", "e", "ons", "ez", "ent"};
int i;
for (i = 0; i < sizeof suj / sizeof suj[0]; i++)
printf("%4s %.*s%s\n", suj[i], len - 2, verb, term[i]);
}
return 0;
}
--
Ben.
If you think you're not ready yet for pointers, then you should be
attempting much simpler things. Pointers are so fundamental to C that
you shouldn't be trying anything this complicated until after you're
learned a lot more about them.
To build on your analogy, you're trying to drive to the local
supermarket with your car still in first gear, and feel that we're
"overspeeding" you by suggesting that you should at least shift into 2nd
gear. If your car has a manual transmission, that analogy might be
entirely lost on you - sorry!
> #include <stdio.h>
> #include <string.h>
>
>
> int main(void)
> {
>
> char SUJ[6][5] = {"je","tu","il","nous","vous","ils"};
> char TERM[6][5] = {"e","es","e","ons","ez","ent"};
> char VERB[20];
> int L;
> int I;
>
> printf("Verbe : ");
> scanf("%s", VERB);
>
>
> L=strlen(VERB);
>
> if ((VERB[L-2] != 'e') || (VERB[L-1] != 'r'))
> printf("\"%s\" n'est pas un verbe du premier groupe.\n",VERB);
>
> else
> {
> VERB[L-2]='\0';
>
> for (I=0 ; I<6 ; I++)
> printf("%s %s%s\n",SUJ[I], VERB, TERM[I]);
> }
>
> return 0;
> }
>
>
> It works just fine without any *pointers, structures and so on.
>
> Just 2 dimensional arrays made it.
printf is automatically converted to a pointer to a function in this
context. VERB is automatically converted to a pointer to char in
virtually every context where you've used it except the declaration.
SUJ[I] and TERM[I] are both pointers to char.
You might want to reconsider the feasibility of avoiding pointers which
using C.
The argument to printf is a pointer.
> scanf("%s", VERB);
Both arguments to scanf are pointers.
>
>
> L=strlen(VERB);
The argument to strlen is a pointer.
>
> if ((VERB[L-2] != 'e') || (VERB[L-1] != 'r'))
> printf("\"%s\" n'est pas un verbe du premier groupe.\n",VERB);
Both arguments to printf are pointers.
>
> else
> {
> VERB[L-2]='\0';
>
> for (I=0 ; I<6 ; I++)
> printf("%s %s%s\n",SUJ[I], VERB, TERM[I]);
All four arguments to printf are pointers.
> }
>
> return 0;
>}
>
>
>It works just fine without any *pointers, structures and so on.
Only if you consider 10 pointers to be "without any." But there are
no structures.
What does the "so on" mean? If you want to use only a very trivial
subset of the language, be prepared to write only trivial programs.
>
>Just 2 dimensional arrays made it.
>
>I guess this is the end of this discussion. Whatever the output, I
>learned a lot from any discussion i initiate or that i can read from
>others. I should soon be posting a lot as i'm about to enter pointers
>chapter.
>There are still a few things i'd like to learn on how to do without
>pointers. By the way, how is it possible to achieve a good level in
C without pointers has all the utility of accounting without
arithmetic.
>programming without getting things done with simplicity? I'm not a
>simple person and as i can understand that, i will not be a good
>programmer or not in an easy way. However, as C is a lot about
>pointers, i might find things easier when i know more about them.
--
Remove del for email
> bpasc...@googlemail.com wrote:
> ...
>> About this discussion, you all should have a $10 fine for
>> overspeed. I
>> really was looking for a "non-pointer" way to achieve this. ...
>
> If you think you're not ready yet for pointers, then you should be
> attempting much simpler things. Pointers are so fundamental to C
> that you shouldn't be trying anything this complicated until after
> you're learned a lot more about them.
>
> To build on your analogy, you're trying to drive to the local
> supermarket with your car still in first gear, and feel that we're
> "overspeeding" you by suggesting that you should at least shift into
> 2nd gear.
I think it's worse than that. He's trying to drive to the local
supermarket on flat tyres, and feels that we're "overspeeding" him by
suggesting that he inflates them.
<snip>
--
Richard Heathfield <http://www.cpax.org.uk>
Email: -http://www. +rjh@
"Usenet is a strange place" - dmr 29 July 1999
This line unintentionally left unblank
...
> Just seeing an alternative can sometimes be helpful:
...
> char verb[20];
...
> scanf("%19s", verb);
This is just asking for trouble, when you modify the declaration of verb.
If instead, one writes
/* Pascal, look away: this is definitely overspeed */
#define VERB_LEN 19
#define Scan_String(len, array) scanf("%" #len "s", array)
...
char verb[VERB_LEN + 1]
...
Scan_String(VERB_LEN, verb)
then the scanf call remains correct if you change the length of verb.
<snip>
> About this discussion, you all should have a $10 fine for overspeed. I
> really was looking for a "non-pointer" way to achieve this. Here it is
> a few html pages later on the tutorial site i'm learning from :
Others have pointed out lots of pointers in the solution, I'll point out
some real errors in it.
> #include <stdio.h>
> #include <string.h>
>
>
> int main(void)
> {
>
> char SUJ[6][5] = {"je","tu","il","nous","vous","ils"};
> char TERM[6][5] = {"e","es","e","ons","ez","ent"};
> char VERB[20];
> int L;
> int I;
>
> printf("Verbe : ");
> scanf("%s", VERB);
Someone else pointed out that you can overflow the buffer here. I don't
know about French, but in Britain there are place names a lot more than
20 characters.
However, if you don't overflow the buffer but instead enter a single
character here...
> L=strlen(VERB);
L will be set to one...
> if ((VERB[L-2] != 'e') || (VERB[L-1] != 'r'))
So the above "underflows" the buffer, I.e. reads before the start of it.
> printf("\"%s\" n'est pas un verbe du premier groupe.\n",VERB);
>
> else
> {
> VERB[L-2]='\0';
The above therefor could write to the location before the start of the
buffer.
> for (I=0 ; I<6 ; I++)
> printf("%s %s%s\n",SUJ[I], VERB, TERM[I]);
> }
>
> return 0;
> }
>
>
> It works just fine without any *pointers, structures and so on.
It works as long as you restrict your input. I would be a little dubious
about a tutorial which has such a fundamental error as reading/writing
before the start of an array.
> Just 2 dimensional arrays made it.
>
> I guess this is the end of this discussion. Whatever the output, I
> learned a lot from any discussion i initiate or that i can read from
> others. I should soon be posting a lot as i'm about to enter pointers
> chapter.
> There are still a few things i'd like to learn on how to do without
> pointers. By the way, how is it possible to achieve a good level in
> programming without getting things done with simplicity? I'm not a
> simple person and as i can understand that, i will not be a good
> programmer or not in an easy way. However, as C is a lot about
> pointers, i might find things easier when i know more about them.
Pointers are simple, they point at things (or not), just like fingers.
Step out of your house with your hand down by your side. Your finger has
been initialised to a null pointer (by putting it down by your side).
Now point it to the first house, and you have set it to point at
something. Move it three houses along, and you have added three to it.
Get someone to demolish the entire street, and it is now a wild pointer
that does not point at a house!
Simple.
The only thing is you have specialised fingers for pointing at different
types of things.
In my opinion most of the trouble people have with pointers is either
thinking they are complex or thinking you need to understand all the low
level detail.
--
Flash Gordon
> >I understand C vocabulary can rely on pointer for anything... That's
> >why i understand as well from studying for the last 3-4 months / 20-40
> >hrs a week, i haven't really started learning C since i was trying to
> >keep myself away from pointers.
probably a bad idea. I think you've got a little scared of them.
And clc isn't helping you at all!
Come on guys take your pedantry busting meds!
Try to distinguish between *explicit* use of pointers; which is what
bpascal mans when he says "pointers" and *implicit* use of pointers
which is what you lot mean. You can call printf() and use arrays
without any knowledge of pointers.
K&R doesn't mention pointers until chapter 5!! That's page 93!!
By that time they've done a huge chunk of the language.
> >As i said earlier, i'm new to programming. Like any other subjects a
> >good understanding of the basics will help later on unlike starting
> >straight with :
> >while ( *pc++ = *pb++ ) ; which is for me an obscure way to copy
> >elements from pb to pc
it *still* looks that way to me and I've been programming in C for a
decade
or so. I know (and use) the idiom but I'd never claimed it was
obvious.
> >(formerly declared as : char buffer[128] ; char
> >clearbuf[128] ; char *pb = buffer ; char *pc = clearbuf and sp on ...
> >it took me a while to understand this...arghhhh ! I think this is
> >still simple in the pointers chapter, pointers to functions and
> >memalloc will make things a lot more spicy.
that's malloc() (or calloc() or realloc())
> >About this discussion, you all should have a $10 fine for overspeed. I
> >really was looking for a "non-pointer" way to achieve this. Here it is
> >a few html pages later on the tutorial site i'm learning from :
>
> >#include <stdio.h>
> >#include <string.h>
>
> >int main(void)
> >{
>
> > char SUJ[6][5] = {"je","tu","il","nous","vous","ils"};
> > char TERM[6][5] = {"e","es","e","ons","ez","ent"};
> > char VERB[20];
> > int L;
> > int I;
I don't like uppercase for identifiers. Traditionally all UC is
reserved for
macros
> > printf("Verbe : ");
>
> The argument to printf is a pointer.
but not knowing this doesn't do any harm. You'd put toddlers up
against Mr.Bolt
<snip>
> >It works just fine without any *pointers, structures and so on.
exactly!
> Only if you consider 10 pointers to be "without any." But there are
> no structures.
He no more needs to know there are pointers there than he needs to
know which registers are being used. Learn to do abstraction it can
be a useful skill if you want to continue programming.
> What does the "so on" mean? If you want to use only a very trivial
> subset of the language, be prepared to write only trivial programs.
4 chapters of k&r doesn't look so trivial to me!
<snip>
> C without pointers has all the utility of accounting without
> arithmetic.
bollocks
> >programming without getting things done with simplicity? I'm not a
> >simple person and as i can understand that, i will not be a good
> >programmer or not in an easy way. However, as C is a lot about
> >pointers, i might find things easier when i know more about them.
yes pointers are important but you are also right about learning at
your own speed.
[insert stupid analogy about breaking the car into individual atoms
and carrying it to the shops in a paper bag]
:-)
--
Nick Keighley
Avoid hyperbole at all costs,
it's the most destructive argument on the planet.
- Mark McIntyre in comp.lang.c
<snip>
> Pointers are simple, they point at things (or not), just like fingers.
> Step out of your house with your hand down by your side. Your finger has
> been initialised to a null pointer (by putting it down by your side).
> Now point it to the first house, and you have set it to point at
> something. Move it three houses along, and you have added three to it.
> Get someone to demolish the entire street, and it is now a wild pointer
> that does not point at a house!
>
> Simple.
>
> The only thing is you have specialised fingers for pointing at different
> types of things.
>
> In my opinion most of the trouble people have with pointers is either
> thinking they are complex or thinking you need to understand all the low
> level detail.
I don't think the syntax helps. I found the syntax confusing as a
beginner
and I'd used Pascal, BCPL and assembler. I had a clear model of the
hardware.
My copy does so in chapter 1, on page 24, though to be fair this is a
forward reference to the "the details" in chapter 5.
<snip>
--
Ben.
> On Mon, 17 Aug 2009 21:16:59 -0400, Ben Bacarisse
> <ben.u...@bsb.me.uk> wrote:
>
> ...
>> Just seeing an alternative can sometimes be helpful:
> ...
>> char verb[20];
> ...
>> scanf("%19s", verb);
>
> This is just asking for trouble, when you modify the declaration of verb.
> If instead, one writes
Agreed.
> /* Pascal, look away: this is definitely overspeed */
>
> #define VERB_LEN 19
> #define Scan_String(len, array) scanf("%" #len "s", array)
>
> ...
> char verb[VERB_LEN + 1]
> ...
> Scan_String(VERB_LEN, verb)
>
> then the scanf call remains correct if you change the length of
> verb.
But consider the context. I wanted to show some tidying up with
minimal language features. Stringification in a macro body is not a
minimal feature!
--
Ben.
I've pointed out his implicit use of pointers, not so much because of
the importance of understanding how such implicit conversions work, but
to point out to him the ubiquity of pointers in C, and the corresponding
futility of trying to do anything complicated in C without understanding
pointers.
>>> As i said earlier, i'm new to programming. Like any other subjects a
>>> good understanding of the basics will help later on unlike starting
>>> straight with :
>>> while ( *pc++ = *pb++ ) ; which is for me an obscure way to copy
>>> elements from pb to pc
>
> it *still* looks that way to me and I've been programming in C for a
> decade
> or so. I know (and use) the idiom but I'd never claimed it was
> obvious.
When I first learned C, I considered it be a trivial obvious thing that
any entry level C programmer could be expected to understand, since it
is mentioned and fully explained in K&R, and I understood it completely
on first reading. Since that time I've used that construct to screen
dozens of prospective employees, only one of whom was able to properly
answer my questions about how it works and what it does. I've come to
realize that I was wrong about that.
<snip>
>> In my opinion most of the trouble people have with pointers is either
>> thinking they are complex or thinking you need to understand all the low
>> level detail.
>
> I don't think the syntax helps. I found the syntax confusing as a
> beginner
> and I'd used Pascal, BCPL and assembler. I had a clear model of the
> hardware.
In my case I had programmed in Basic, Pascal, Modula 2, several
different assemblers, Forth, Logo and various other languages before
learning C. I ended up learning it because the only decent compilers for
the processor we were committed to using were C compilers (we had tried
a Pascal one, but it was worse than useless).
I can see that the C syntax can be confusing, which is one reason why
when I want to explain pointers I don't use the C syntax. Instead I use
English and things people are familiar with. That way non-programmers
can understand the concept as well (and I've successfully explained bugs
due to pointer miss-use to non-programmers).
--
Flash Gordon
> i haven't really started learning C since i was trying to
> keep myself away from pointers.
Yes.
If you keep yourself away from pointers,
then you really aren't trying to learn C.
--
pete
Hi Ben,
It's just way above what i can currently understand. However, it looks
nice !
Thanks,
Pascal
Either you're overestimating the difficulty of understanding pointers,
or you're underestimating your own capacity to understand them, or you
have no chance whatsoever of ever learning to be a proficient C
programmer - I'm not sure which. Regardless of which of the above
options is true, you're really wasting your time (and ours) by trying
to learn any significant amount of C without first learning a lot more
than you currently know about pointers. There's some baby stuff you
can learn before learning pointers; but your messages imply that
you've already learned everything that's worthwhile learning before
going on to pointers.
Just to say, I'm allergic to pointer, i'm just very carefull as i know
they are very powerfull and C is the language that best uses them and
it might if i keep on learning C to understand some other languages
and get the best of what pointers have. I'm saying again, i have
learning how to programm from scratch 3-4 months ago (15-25 hours a
week). I think the best i'm able to deal with the basics or "baby
stuff" as James in the post above calls it, the less trouble i'll have
with pointers....
Back to business, i found this code there (for those who can read
french...and c) : http://www.siteduzero.com/tutoriel-3-35363-realiser-des-saisies-securisees-grace-a-fgets.html
#include <stdio.h>
#include <string.h>
static void purger(void)
{
int c ;
while ( ( c = getchar() ) != '\n' && c != EOF ) ;
}
static void clean(char *chaine)
{
char *p = strchr(chaine, '\n') ;
if (p)
*p = 0 ;
else
purger() ;
}
int main(void)
{
char chaine[20] ;
printf("\n\nEnter some text : \n") ;
fgets(chaine, sizeof chaine, stdin) ;
clean(chaine) ;
printf("\nThe text entered is : '%s' ", chaine) ;
return 0 ;
}
The code above is about cleaning the buffer from '\n' until EOF ( EOF
= CTRL-Z or D ?)
I understand broadly the buffer is about memory managment and is
closer to computer instructions from the processor than RAM. Anything
can go into the buffer : video streaming, printer jobs.
Fgets unlike scanf has a limit in the number of caracters entered ?
However, like scanf, fgets reads and holds '\n'. I'm not sure of the
last one, if someone could confirm it would help.
while ( ( c = getchar() ) != '\n' && c != EOF ) ;
tells to read any newline left (here it would be located in array
"chaine" in main) after the user has entered more or less 20
characters and press ENTER... So, fgets reads <ENTER> or '\n' or EOF
if greater than 20 characters and keeps it in the buffer? So in the
next entry, if '\n' is in left in the buffer, the code will skip the
user's entry.
Then the instruction getchar() tells to grab anything left in the
buffer but '\n', assigns it to a variable c and in the meantime
somehow creates a new buffer that could hold any characters but '\n'.
char *p = strchr(chaine, '\n') ;
strchr returns the position of '\n' in chaine to *p . As i understand
from reading about strchr in webpages, char *p is an array of
characters ? And in this code it will only hold one value : '\n'.
if (p)
It tells to proceed if p is anything but empty or null. And if it's
not null, it assigns 0 in place of '\n'.
purger()
If *p is null, then it looks to empty the buffer from the presence of
'\n' and to do so purger() is called.
I'm not sure if what i understand is correct. I think this code is a
milestone for manipulating text entries and i intend to use it from
now on unless there is something better.
I feel sleepy and i hope what i have written makes some sense.
Thanks,
Pascal
I AM NOT ALLERGIC TO POINTER sorry, typo mistake
>
> Thanks,
>
> Pascal
When there is no more input, getchar returns EOF (a negative integer)
to tell you that there is not more input. When you are typing at a
program you can signal that there is to be no more input using the
keyboard, but it is often configurable and it varies from system to
system. Ctrl+Z and Ctrl+D are common.
> I understand broadly the buffer is about memory managment and is
> closer to computer instructions from the processor than RAM. Anything
> can go into the buffer : video streaming, printer jobs.
That is so general it won't help you here. This is all about an input
buffer. Most systems let you prepare a line and send it to your
program when you hit return. This lets you correct errors before the
program sees it. The code you show is all about reading to the end of
a line (usually one full input buffer).
> Fgets unlike scanf has a limit in the number of caracters entered ?
> However, like scanf, fgets reads and holds '\n'. I'm not sure of the
> last one, if someone could confirm it would help.
fgets does (read and store the newline). scanf is very general and
can do either.
> while ( ( c = getchar() ) != '\n' && c != EOF ) ;
> tells to read any newline left (here it would be located in array
> "chaine" in main) after the user has entered more or less 20
> characters and press ENTER... So, fgets reads <ENTER> or '\n' or EOF
> if greater than 20 characters and keeps it in the buffer? So in the
> next entry, if '\n' is in left in the buffer, the code will skip the
> user's entry.
> Then the instruction getchar() tells to grab anything left in the
> buffer but '\n', assigns it to a variable c and in the meantime
> somehow creates a new buffer that could hold any characters but
> '\n'.
This sounds wrong though it may simply be that you are having trouble
saying it in English. The page you link to explained it all quote
well, I thought, so I am wary of trying to do better in a language
that is not your own.
> char *p = strchr(chaine, '\n') ;
> strchr returns the position of '\n' in chaine to *p . As i understand
> from reading about strchr in webpages, char *p is an array of
> characters ? And in this code it will only hold one value : '\n'.
>
> if (p)
> It tells to proceed if p is anything but empty or null. And if it's
> not null, it assigns 0 in place of '\n'.
>
> purger()
> If *p is null, then it looks to empty the buffer from the presence of
> '\n' and to do so purger() is called.
>
>
> I'm not sure if what i understand is correct. I think this code is a
> milestone for manipulating text entries and i intend to use it from
> now on unless there is something better.
>
> I feel sleepy and i hope what i have written makes some sense.
It is easier to explain backwards rather than in the order you show
the code. The user types some text. You read it using fgets. If it
fits (i.e. the input is not too long) then strchr finds a \n in the
array which gets replaced by the string terminator (0). If the line
is too long for the array, then strchr finds no \n, but you (the user)
have typed more characters than have been read, so the program reads
and that are left (i.e. up to the \n that fgets never saw).
This is only one way to read input. It is useful in some programs and
harmful in others. It all depends on what the program is for. I'd
suggest that throwing input away like this is rarely the best thing to
do, but it can help in simple interactive programs.
--
Ben.
Hi,
I'm confused about the very confusing language i used at some point
for that post.
I understand you all by your expertise make this place very lively and
professional as well.
Pascal
And i understand i'm asking very simple and basic programming
questions and this forum gather people with different level of
expertise. I understand for someone who deals everyday with advanced C
code, it's not always easy to answer basic programming questions.
C the language.
"Can C do it?"
C the language.
"Yes, C can!"
(Okay, to all those going "WTF?", it's sung to the tune of the "Bob the
Builder" theme song.")
--
Kenneth Brody
Hi Ben,
You say there are other ways to do the same thing. This way is not
easy to deal with with little a basic knowledge of getchar and the
buffer. I found an explanation there :
http://ubuntuforums.org/showthread.php?t=1059917
However, why isn't more simple to do :
...
char Txt[20] ;
printf("\nEnter some string : ") ;
fgets(Txt, 20, stdin) ;
cnt = strlen(Txt) ;
..
The last itiration of cnt will always be '\0' ?
So why use getchar() != '\n' when fgets with strlen don't store '\n'.
I don't know if EOF would be read by strlen since i don't know much
about the behavior of EOF.
Thanks,
Pascal
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
char Txt[20];
size_t cnt;
printf("\nEnter some string : ");
if (fgets(Txt, (int) sizeof Txt, stdin)) {
cnt = strlen(Txt);
/* Do more stuff here... */
/*
It is possible that the read fails,
in which case Txt might contain unterminated garbage.
*/
} else {
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
> bpasc...@googlemail.com wrote:
>
> > printf("Verbe : ");
> > scanf("%s", VERB);
>
> Someone else pointed out that you can overflow the buffer here. I don't
> know about French, but in Britain there are place names a lot more than
> 20 characters.
He's not reading place names, he's reading verbs. AFAICT there are no
infinitive forms of verbs that are longer than 20 characters in French.
It's still not wise, though, partly because some come close and a typo
is easily made, and partly because someone might feed it something which
isn't a verb at all, intentionally or by accident.
Richard
>> This is only one way to read input. It is useful in some programs and
>> harmful in others. It all depends on what the program is for. I'd
>> suggest that throwing input away like this is rarely the best thing to
>> do, but it can help in simple interactive programs.
>>
>> --
>> Ben.
It's best to snip sig blocks (even tiny ones).
<snip>
> You say there are other ways to do the same thing. This way is not
> easy to deal with with little a basic knowledge of getchar and the
> buffer. I found an explanation there :
> http://ubuntuforums.org/showthread.php?t=1059917
>
> However, why isn't more simple to do :
>
> ...
> char Txt[20] ;
> printf("\nEnter some string : ") ;
> fgets(Txt, 20, stdin) ;
Two things: (a) it is good to get into the habit removing arbitrary
numbers from your code so I'd write fgetc(Txt, sizeof Txt, stdin) so I
don't need to repeat the 20; (b) always check the return from input
functions -- one day it will save your life.
A good programmer feels nervous about seeing:
> cnt = strlen(Txt) ;
after an input call that might not have done anything at all.
> ..
>
> The last itiration of cnt will always be '\0' ?
Yes, and something like the code above is fine if it suits your
purpose, but the whole point of the other code was to deal with the
situation where the input does not fit. The remaining input
characters are still there in the input buffer and this is, sometimes,
undesirable (sometimes it is exactly what you want).
> So why use getchar() != '\n' when fgets with strlen don't store '\n'.
If my program prompts for my name and then my age:
Enter you name: Benjamin Salavador Bacarisse
Enter your age:
Sorry, "acarisse" is not a valid age.
The simple fgets stopped after 19 chars (it used the 20th for the \0)
and when the program tried to get the age (may using scanf("%d",
&age)) the scanf saw the remaining characters.
If, after reading the name, I check if there was a newline (maybe
using strchr(Txt, '\n')) I can take action when the input is obviously
too long (i.e. when there is not newline in Txt). The action I need
might be to throw the data away:
int c;
while ((c = getchar()) != '\n') /* do nothing */;
but this loop won't ever end if there is newline (for example if I
enter "Ben^D^D" on my Linux system). Hence we really need:
while ((c = getchar()) != '\n' && c != EOF) /* do nothing */;
> I don't know if EOF would be read by strlen since i don't know much
> about the behavior of EOF.
EOF is not a character. It does not get put in the string (in fact it
can't be put into a string[1]). EOF is in int (not a char) designed
so that no valid character can be confused with it[1]. When you type
^D or ^Z or whatever, the program never sees this[2] -- it is an
instruction to the operating system to close the program's input
stream. Since stdin is closed, the next gechar() returns the special
(negative) value EOF.
[1] Except on peculiar hardware that beginners should definitely put
to one side for a while.
[2] Except on very old operating system that are best forgotten.
--
Ben.
Hi,
Your reply tells a lot Ben. Many thanks. I started to write the one
below before i read yours. I already have the answer from you about
most questions. So this below would be additional informations.
About getchar() != '\n' it seems gcc under linux needs this more than
gcc(djgpp) in Windows. Although gcc linux and gcc or djgpp in windows
should be the same.
From http://ubuntuforums.org/showthread.php?t=1059917, someone says :
"while (getchar() != '\n');
is that the test - (getchar() != '\n') - gets executed each time you
go round the loop, so this fetches a character and tests it against
'\n', and goes back round to execute the condition again if the first
test fails (i.e. the character is '\n'). One of the key things here is
the semi-colon at the end of the statement - which effectively creates
an empty loop - so the condition (including the getchar() function)."
End of quotes (he and i are beginners)
So far, i understand '\n' is located somewhere in the buffer among
other characters that don't impact futur input from stdin.
And as it is said above, the getchar looks for characters (that are in
the buffer ?). What action does it do then ? It reads, memorized or i
don't know what, these characters from the buffer and skips '\n'.
So at the end, we can say getchar() != '\n' CREATES and fills a new
buffer from reading the current one with while. That new buffer
doesn't include '\n'. I'm not just of this assertion.
Not over, i don't think i'm right from what i have just written. It's
all i can understand. But next it gets worse :
int c ;
while ( ( c = getchar() ) != '\n' && c != EOF ) ;
getchar is supposed to work with characters ? Why c is declared as an
int.?
As Ben has said above (in the previous post), EOF is a number (-1 I
think) . So is it why we need an integer variable (here c) ? (Only to
deal with EOF)
I went through http://c-faq.com/~scs/cclass/notes/sx6c.html 6.2
section deals well with getchar but more with EOF than '\n'.
Variable c gets a char value from getchar. Does it then for each
character it can get fills a new buffer with anything but '\n' and
affects that very current character to variable c.
Why a variable is needed here ? Just to secure the not equal
expression ?
6.2 section from the site above says :
Quote :
"The simple example we've been discussing illustrates the tradeoffs
well. We have four things to do:
1. call getchar,
2. assign its return value to a variable,
3. test the return value against EOF, and
4. process the character (in this case, print it out again).
We can't eliminate any of these steps. We have to assign getchar's
value to a variable (we can't just use it directly) because we have to
do two different things with it (test, and print). Therefore,
compressing the assignment and test into the same line is the only
good way of avoiding two distinct calls to getchar. You may not agree
that the compressed idiom is better for being more compact or easier
to read, but the fact that there is now only one call to getchar is a
real virtue.
Don't think that you'll have to write compressed lines like
while((c = getchar()) != EOF)
right away, or in order to be an ``expert C programmer.'' But, for
better or worse, most experienced C programmers do like to use these
idioms (whether they're justified or not), so you'll need to be able
to at least recognize and understand them when you're reading other
peoples' code."
End of quote
It says "we have to do two different things with it (test, and
print)". I think this assertion is closely related to the code they
run and explain in the same page.
However, with '\n', we just need to test it and not to print it ? So
why is a int variable needed ? The question should be how come int
variable c can be both in getchar() and !=EOF ?
What's the point of testing a int variable against '\n' ? '\n' is a
character, isn't it?
Pascal
int c;
while (((c = getchar()) != EOF) && (c != '\n')) {}
(equivalent to what you wrote, but slightly repunctuated for my
preferences: extra parentheses for clarity, and {} to make it
more obvious that it's an empty while loop).
Yes, the reason c is declared as int is so that we can test it
against EOF, which is guaranteed to be a value different than
anything which can be represented by a char. (Usually implemented
as -1, but that value is not required by any standard).
The reason we do this instead of simply
while (getchar() != '\n') {}
is that it's possible that your standard input stream might end
with no newline character.
Yes, they should be the same. The external representation of text
files differs between Linux and Windows, but the end-of-line sequence
should be converted to '\n' on either system. I don't understand what
you mean when you say that one system "needs this more" than the
other.
[...]
> And as it is said above, the getchar looks for characters (that are in
> the buffer ?). What action does it do then ? It reads, memorized or i
> don't know what, these characters from the buffer and skips '\n'.
>
> So at the end, we can say getchar() != '\n' CREATES and fills a new
> buffer from reading the current one with while. That new buffer
> doesn't include '\n'. I'm not just of this assertion.
There is buffering going on, but it's not something you need to worry
about. getchar() reads the next character from the specified input
stream and returns its value (or returns the value of EOF if there are
no more characters to read). '\n' is just another character as far as
getchar() is concerned.
>
> Not over, i don't think i'm right from what i have just written. It's
> all i can understand. But next it gets worse :
>
> int c ;
> while ( ( c = getchar() ) != '\n' && c != EOF ) ;
>
> getchar is supposed to work with characters ? Why c is declared as an
> int.?
Because getchar() returns an int result.
Suppose you're designing a function that reads the next character from
an input stream and gives you its value. The obvious thing to do is
to return a char value, but that's not enough. You also need to be
able to indicate that there are no more characters to be read. So
it's returning two piece of information: the next character (if any)
and an indication of whether there was a next character.
There are several ways this could be done. It could return a
structure containing a char and some sort of flag. It could take a
pointer argument, and store the flag value via that pointer. It could
store the flag in a global (ick!).
The method chosen by the creators of getchar() was something called
in-band signalling: returning a single result that's big enough to
store *either* a character value or a flag value.
If there is another character to be read, getchar() reads it, treats
it as an unsigned char value (so it's guaranteed to be non-negative),
converts that value to int, and returns it. If there isn't (either
because you've reached the end of the file or because there was an
error), getchar returns the value EOF (typically -1, but the only
guarantee is that it's negative). Assuming that INT_MAX >= UCHAR_MAX,
this single result gives you all the information you need.
> As Ben has said above (in the previous post), EOF is a number (-1 I
> think) . So is it why we need an integer variable (here c) ? (Only to
> deal with EOF)
Yes, only to deal with EOF. If it weren't for the need to store that
extra information, getchar() could return a char.
But note that char is also an integer type; it's just a relatively
narrow one, typically used to hold character codes. C represents
characters as numbers.
[...]
> What's the point of testing a int variable against '\n' ? '\n' is a
> character, isn't it?
'\n' is a character. It's also an integer. On most systems you're
likely to encounter, it's the ASCII linefeed character), so '\n'==10.
If getchar() reads a newline from its input stream, it returns the
value '\n'.
--
Keith Thompson (The_Other_Keith) ks...@mib.org <http://www.ghoti.net/~kst>
Nokia
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
The standard requires that all members of the basic character set are
represented by positive values, but allows char to be signed, and also
allows for an extended character set which may contain characters whose
values could be negative.
The standard does not require that EOF be distinct from all char values,
For a fully conforming implementation which chooses to have INT_MAX <
UCHAR_MAX, if you use getc() to read a byte from the input stream whose
value is (unsigned char)EOF, it must return EOF.
getchar() is still quite obscur. Explanations above make it less
dark... But compiling with getchar under Windows and Linux adds insult
to injury. I don't feel bad running one day Windows and another day
Linux at least for testing code to make it portable.
I assigned myself to make a code work both in windows and linux...
For this getchar understanding task, I tested the code below in this
site :
http://c-faq.com/~scs/cclass/notes/sx6b.html
Under linux, it works as one can expect.
Under windows, i get : the same line over and over saying something
with Null ... and a strange number, the same over and over as if it's
a result from the loop in the code.
The code from the link above :
#include <stdio.h>
/* copy input to output */
main()
{
int c;
c = getchar();
while(c != EOF)
{
putchar(c);
c = getchar();
}
return 0;
}
Under windows, i tried to add this line of code several times in the
code where the system expects an entry : while ( getchar() != '\n' )
{}
I think if someone can tell me why these lines of code don't compile
in my Windows system (i'm using djgpp), it will be a great step for
understanding C.
---
Now again about getchar. I'd like to understand more about the part
where the user enters data with getchar() handling it like in the code
above. The user enters a character or a string of characters and hits
enter and (in linux) the string or characters entered are displayed.
When the user enters a characters, the stdin places it into the buffer
and so on for each character entered until <Enter> is pressed down.
Let say i entered "bcd<Enter>". It goes into the buffer like
'b''c''d''\n' ?
Then it reads first 'b' and what does it do with it ?
Does It just leave it in the buffer as it is since it's not '\n' ...
and right after putchar() prints it on the screen, it does the same
for 'c' until getchar() == '\n' or getchar() = '\n' (i don't which one
is correct getchar() == or getchar() = ).
Does Getchar() read and take '\n' from its location in the buffer ?
Where does '\n' go then ?
Getchar could be seen as "search and destroy" in the buffer (stdin
stream) for any value equal to '\n' otherwise it just leave it as it
is ?
Is there a way to access and take a picture of the buffer ? Let say
with hexa values as descriptions ?
Pascal
That's to be expected.
> Under windows, i get : the same line over and over saying something
> with Null ... and a strange number, the same over and over as if it's
> a result from the loop in the code.
Describing a rough approximation of the output you got doesn't do
anybody any good. If you can copy-and-paste the *exact* output (or at
least a portion of it), we have a fighting chance of diagnosing the
problem.
> The code from the link above :
> #include <stdio.h>
>
> /* copy input to output */
>
> main()
> {
> int c;
>
> c = getchar();
>
> while(c != EOF)
> {
> putchar(c);
> c = getchar();
> }
>
> return 0;
> }
With one minor exception, that's perfectly good standard C. The one
exception is that "main()" should be "int main(void)". I advise you
to make that change, but it's very unlikely to be the cause of your
problem; most compilers should treat "int main(void)" and "main()"
essentially identically.
> Under windows, i tried to add this line of code several times in the
> code where the system expects an entry : while ( getchar() != '\n' ) ;
The code you posted is correct. Other than changing "int main(void)"
to "main()", you shouldn't change it. If it's not working, changing
the code isn't the solution.
> I think if someone can tell me why these lines of code don't compile
> in my Windows system (i'm using djgpp), it will be a great step for
> understanding C.
From your rather vague description above ("the same line over and over
saying something with Null ..."), I assumed you were describing the
program's run-time behavior. Now you're saying the code doesn't
compile. Again, you need to copy-and-paste the *exact* output you're
getting, and tell us exactly what you did to get it.
The code you quoted above should compile without error, and when you
run the resulting program, it should do exactly what it's supposed to
do, namely copy standard input to standard output. It should do this
regardless of whether you're using gcc on Linux or djgpp on Windows.
If you're getting some other result, it's because you're doing
something else wrong, and you haven't given us enough information to
guess what that might be.
> Now again about getchar. I'd like to understand more about the part
> where the user enters data with getchar() handling it like in the code
> above.
[snip]
I suggest you worry about getting the code working first.
Consider this program:
#include <stdio.h>
int main(void) {
int c;
while ((c = getchar()) != EOF)
putchar(c);
return 0;
}
There is nothing special about getchar(). It is exactly getc(stdin) just
as putchar(c) is putc(c, stdout). Both input and output are line
buffered and there are two separate buffers. Let's consider the input
buffer.
When we start the program without arguments, the input buffer is empty
and the call to getchar() blocks, waiting for data from the underlying
buffered i/o system.
As you now type 'Hello There' on your keyboard, getchar() is still
blocked and sees nothing. You can use some editing features to change
'There' to 'Sweetheart' for example. getchar() is still blocking.. until
you press Enter. This puts '\n' as the last character of the buffer and
un-blocks the buffer. Now all characters in the buffer, including the
'\n' are sent, one at a time, to getchar().
The buffer is effectively emptied in this process. There is no Stamdard
way to examine the buffer itself.
When the buffer is empty Unix-like systems interpret ^D as EOF to quit
the program. Windows interprets ^Z the same way.
--
Joe Wright
"Yea though I walk through the valley of the shadow of death, I will
fear no evil, for I am the meanest SOB in the valley." Jerry Sanders
I think it's clearer to say that they interpret ^D or ^Z as an
end-of-file indicator. The word EOF is certainly derived from the
words End Of File, but EOF has a very specific meaning in C, a macro
defined in <stdio.h>, and its best (especially when communicating
with newbies) to use the term EOF only to refer to that macro or
to its value.
When the user types ^D or ^Z, it's interpreted by (some layer of)
the OS as an end-of-file indication. If a C program is reading
from the correspoding input stream by repeatedly calling getchar(),
after the getchar() has processed the last character that preceded
the ^D or ^Z, the *end-of-file indicator* for the stream is set.
When getchar() is called on a stream whose end-of-file indicator
is set, it returns the value of EOF.
Note that neither ^D (ASCII value 4), nor ^Z (ASCII value 26),
nor EOF (a negative int value, typically -1) is (necessarily)
ever stored in a file. ^D and ^Z are used to signal to the OS
that no more data from the keyboard is to be written to the file.
EOF is returned by getchar() to indicate that there's no more data
to be read from the standard input stream. They're both a form of
in-band signalling.
(Just to confuse matters, a ^Z character physically stored in an
MS-DOS or Windows text file *can* be used to indicate the logical
end of the file -- but it's more common for the end of a file to
be defined just by the lack of any more data, as indicated by
the file system's stored value for the size of the file in bytes.)
Does that error appear when you RUN the code or COMPILE the code?
Spell the error messages exactly as they appear and post them.
Loops in the code don't cause looping error messages during compilation.
(At least not in non-seriously-broken compilers.)
>Under windows, i tried to add this line of code several times in the
>code where the system expects an entry : while ( getchar() != '\n' )
>{}
If you tried and failed to add this line of code, please explain
what error message your editor and/or compiler produced when you
failed. DId you run out of disk space for the source code?
>I think if someone can tell me why these lines of code don't compile
>in my Windows system (i'm using djgpp), it will be a great step for
>understanding C.
>Now again about getchar. I'd like to understand more about the part
>where the user enters data with getchar() handling it like in the code
>above. The user enters a character or a string of characters and hits
>enter and (in linux) the string or characters entered are displayed.
stdin is not always connected to a terminal device (often, a terminal
device is the console keyboard, but it can be a serial terminal or
a virtual terminal over a network). Even Windows allows redirection
of stdin from a file. Terminal devices are not always read via
stdin. Some of the behavior you are seeing comes from a terminal
device driver. Some comes from the C library stdio code.
There are many potential buffers involved. If stdin is connected
to a virtual terminal connected to a physical keyboard over a
network, there are many buffers on the two end machines and possibly
a few buffers in each of possibly dozens of computers, VPN servers,
routers, wireless access points, or switches between them.
>When the user enters a characters, the stdin places it into the buffer
>and so on for each character entered until <Enter> is pressed down.
>Let say i entered "bcd<Enter>". It goes into the buffer like
>'b''c''d''\n' ?
The Linux terminal driver does line canonicalization (in the normal
mode it's used - to change mode you need OS-specific C code). A
line of input is collected, and nothing is passed on until the
entire line is finished (the user presses a key usually labelled
<ENTER>). Line editing is handled here: if you enter <backspace>
the line canonicalization process removes the previous character.
There is a character to cancel the line and start over. So, if you
type: b Q <backspace> c d <ENTER> after you press 'd', no data has
been sent on, and after you press <ENTER>, b c d \n is sent on.
Line canonicalization needs some kind of buffer to store a whole
line until it's finished.
I am not sure where line canonicalization is done in Windows.
Line canonicalization is done on terminal input, not files. Backspaces
in files will be read as backspaces.
The C library is responsible for translating line endings (\r\n in
Windows) in files or terminal input to the C standard \n, and
translates the other way on the way out. This happens whether you
are reading a terminal or a file on stdin. The C library, for
efficiency reasons, will generally grab a bunch of input (a disk
block or a whole line released from line canonicalization) and
dispense it in single-character chunks (if getchar() or getc() is
used), or smaller pieces (if fread() is used for small records).
>Then it reads first 'b' and what does it do with it ?
stdio reads a bunch of input (typically a whole line or file block)
after <ENTER> is pressed. getchar() takes the first available
character ('b') and returns it. The next getchar() returns 'c'.
The next one returns 'd'. The next one returns a newline (\n).
For the next one the stdio buffer is now empty, so it waits reading
another bunch of input.
>Does It just leave it in the buffer as it is since it's not '\n' ...
>and right after putchar() prints it on the screen, it does the same
>for 'c' until getchar() == '\n' or getchar() = '\n' (i don't which one
>is correct getchar() == or getchar() = ).
"Until getchar() = 'c'" is wrong in C code. = is an assignment
operator, and you can't assign to a function return value like that.
If you want to step outside of the C code to talk ABOUT the code,
and use it as a short cut for saying "Until getchar() returns a
value of 'c'", most people but the hard-core pedants will understand
you. I'd still prefer to use "Until getchar() == 'c'".
>Does Getchar() read and take '\n' from its location in the buffer ?
It's getchar(), not Getchar(). C function names are case-sensitive.
>Where does '\n' go then ?
It is returned by getchar().
>Getchar could be seen as "search and destroy" in the buffer (stdin
>stream) for any value equal to '\n' otherwise it just leave it as it
>is ?
No. Line canonicalization accumulates an entire line, then passes
it on, before any of it gets to the stdio buffer.
getchar() takes a character from the stdio buffer, updates the
bookkeeping to indicate the character has been used, and returns
it. If there are no characters in the stdio buffer, it will get
some, waiting if necessary.
>Is there a way to access and take a picture of the buffer ?
Not in Standard C. There isn't a "THE" buffer, there are several.
Some of them are on other machines. It may be possible to write a
system-specific routine for the stdio buffer, which grunges around
inside a FILE object for stdin and determines what part of the
buffer is still in use. If you look at the contents of a FILE
struct and the code for getchar() and the functions it calls, it
shouldn't be too difficult. Chances are this will not be portable
between Windows and Linux.
>Let say
>with hexa values as descriptions ?
Does a printf() format of "%2.2x" suggest anything?
> When the user types ^D or ^Z, it's interpreted by (some layer of)
> the OS as an end-of-file indication. If a C program is reading
> from the correspoding input stream by repeatedly calling getchar(),
> after the getchar() has processed the last character that preceded
> the ^D or ^Z, the *end-of-file indicator* for the stream is set.
> When getchar() is called on a stream whose end-of-file indicator
> is set, it returns the value of EOF.
>
The end-of-file indicator is set differently for a file or for the
keyboard. And yes, the I/O system knows which. Sending a line to
getchar() ending with '\n' does not set the end-of-file (eof) indicator.
The eof gets set only when you attempt to read beyond the last byte of a
file or when, from the keyboard, ^D or ^Z follows '\n'.
> Note that neither ^D (ASCII value 4), nor ^Z (ASCII value 26),
> nor EOF (a negative int value, typically -1) is (necessarily)
> ever stored in a file. ^D and ^Z are used to signal to the OS
> that no more data from the keyboard is to be written to the file.
> EOF is returned by getchar() to indicate that there's no more data
> to be read from the standard input stream. They're both a form of
> in-band signalling.
>
The ^D or ^Z keypresses immediately following '\n', followed by '\n' or
Enter is the keyboard version of end-of-file. Otherwise 4 and 26 are
just charters with that value.
> (Just to confuse matters, a ^Z character physically stored in an
> MS-DOS or Windows text file *can* be used to indicate the logical
> end of the file -- but it's more common for the end of a file to
> be defined just by the lack of any more data, as indicated by
> the file system's stored value for the size of the file in bytes.)
>
The ^Z written as a character to signify the end of a text file is an
artifact of CP/M carried over into early MSDOS. CP/M wrote files in
128-byte chunks. The filesystem couldn't tell you whether a file was 3
bytes or 123 bytes. You needed to read it and stop at the 1A.
Relatively modern systems retain this legacy. Many Microsoft text files
still end with 1A for no other obvious reason.
A line ending with '\n' doesn't signal end-of-file for a disk file
either.
The input model, as far as getchar() is concerned, is pretty much
the same either for a disk file or for input from a keyboard.
Both are modeled as input text streams, and both are composed of
a sequence of lines, each terminated by '\n'. The end-of-file
condition is triggered differently: for a disk file, typically as
defined by the filesystem's idea of how many bytes the file contains,
and for keyboard input, typically by the user entering some special
key combination. But the behavior as seen by a C program calling
getchar() is very similar. (The C implementation, including the OS,
goes to considerable effort to make them look similar.)
>> Note that neither ^D (ASCII value 4), nor ^Z (ASCII value 26),
>> nor EOF (a negative int value, typically -1) is (necessarily)
>> ever stored in a file. ^D and ^Z are used to signal to the OS
>> that no more data from the keyboard is to be written to the file.
>> EOF is returned by getchar() to indicate that there's no more data
>> to be read from the standard input stream. They're both a form of
>> in-band signalling.
>>
> The ^D or ^Z keypresses immediately following '\n', followed by '\n'
> or Enter is the keyboard version of end-of-file. Otherwise 4 and 26
> are just charters with that value.
s/charters/characters/
nNote also that, under Unix, typing ^D twice in the middle of a line
also signals an end-of-file condition; getchar() can then return
EOF without having previously returned '\n'. And ^V^D causes
getchar() to return '\004'. (Both ^V and ^D can be reconfigured
to other values.) I'm less familiar with how Windows does this.
>> (Just to confuse matters, a ^Z character physically stored in an
>> MS-DOS or Windows text file *can* be used to indicate the logical
>> end of the file -- but it's more common for the end of a file to
>> be defined just by the lack of any more data, as indicated by
>> the file system's stored value for the size of the file in bytes.)
>>
> The ^Z written as a character to signify the end of a text file is an
> artifact of CP/M carried over into early MSDOS. CP/M wrote files in
> 128-byte chunks. The filesystem couldn't tell you whether a file was 3
> bytes or 123 bytes. You needed to read it and stop at the 1A.
>
> Relatively modern systems retain this legacy. Many Microsoft text
> files still end with 1A for no other obvious reason.
And, IIRC, a 1A byte in the middle of a Windows text file is treated
as an end-of-file marker (but only if you read it in text mode;
in binary mode it's just another byte).
Hi,
I understand this isn't the best way to describe something. My excuse
for the delay, it's just that windows takes so long to boot...
The message i get :
"from (null):4294967295,
from (null):4294967295,"
...
It happens when i compile : gcc myfile.c -o myfile.exe
Overnight i thought about it and I have to tell that earlier in the
day this happened i "re-arrange" folders in my djgpp directory. But i
only moved folders where i had saved codes NOT folders with
application system files in it (unless i moved a file i shouldn't have
moved by mistake...). SO IF THIS SIMPLE CODE IS WORKING IN YOUR
WINDOWS MACHINE IT MIGHT BE THAT I MESSED UP WITH A FILE and i need to
see this with people at djgpp. I am certain i rearranged files (only
folders with code i had written and nothing else) just before trying
to compile the code from http://c-faq.com/~scs/cclass/notes/sx6b.html.
However, i can compile any other code that includes printf, scanf...
in Windows.
Thanks
Pascal
Erk. ^D^D /may/ signal to the tty that it is to report on an e-o-f
condition to the program attached to it. On my Unix consoles here,
it certainly doesn't:
FreeBSD 5.3 zsh - mid-line ^D tab completes, ^D^D backs out
SunOS 5.8 csh - mid-line ^D tab completes, ^D^D duplicates.
SunOS 5.9 bash - mid-line ^D does nothing perpetually
Linux bash - mid-line ^D does nothing perpetually
So I can't reproduce it on a console. (It may behave differently
via a telnet or SSH session, perhaps, as there are two ends to consider.)
Phil
--
If GML was an infant, SGML is the bright youngster far exceeds
expectations and made its parents too proud, but XML is the
drug-addicted gang member who had committed his first murder
before he had sex, which was rape. -- Erik Naggum (1965-2009)
>Erk. ^D^D /may/ signal to the tty that it is to report on an e-o-f
>condition to the program attached to it. On my Unix consoles here,
>it certainly doesn't:
>
>FreeBSD 5.3 zsh - mid-line ^D tab completes, ^D^D backs out
>SunOS 5.8 csh - mid-line ^D tab completes, ^D^D duplicates.
>SunOS 5.9 bash - mid-line ^D does nothing perpetually
>Linux bash - mid-line ^D does nothing perpetually
All those shells are probably putting the terminal in raw mode (or at
least a not-fully-cooked mode) and interpreting the characters
themselves. Try it inside "cat" on each system. It should
echo the line after the first one, and exit after the second.
-- Richard
--
Please remember to mention me / in tapes you leave behind.
Absolutely. Context is everything. "under Unix" wasn't quite
enough context to isolate the behaviour posited.
> Try it inside "cat" on each system. It should
> echo the line after the first one, and exit after the second.
In that context, all of the above perform exactly as you state.
How about 'a C program, using getchar(), under Unix' ?
I believe getchar() was in the original context.
SaSW, Willem
--
Disclaimer: I am in no way responsible for any of the statements
made in the above text. For all I know I might be
drugged or something..
No I'm not paranoid. You all think I'm paranoid, don't you !
#EOT
I went on to check many files i had been practising c with (tutorial
files) with getchar in it and when getchar is in the file like in the
c-faq.com code, it works only in linux and returns an infinite loop :
from (null):4294967295 in windows.
When getchar has some tweakings in it such as the !='\n' check...it
seems it works on both platforms and not as i said earlier, IT ALSO
WORKS IN WINDOWS, sorry if i misled you.
As a newbie, i understand that getchar() is not easy to deal with. I
guess that if i read until i understand what was said above and keep
on coding.
Replies earlier are of great quality, thanks
Pascal
I came to this conclusion :
Make a code work under windows following C99 standards with some
tweaks and without conio... will be equivalent to implement the code
in linux following C99 standards strictly speaking (without any
tweaks) ?
So far, after 3-4 months of learning, user's inputs seem to be the
most difficult chapter when for a few lines of code as a beginner, i'd
like the code to work on as many plateform as possible.
Many websites show scanf and %s to read strings with classic variables
as well as with pointers (my tutorial as well). To my eyes and
experience, scanf seems very easy to implement on both plateform...
In some other websites and here in this forum, some say scanf is not
best to read strings of characters because of security reasons. Then
what would be the best counterpart ?
Thanks,
Pascal