Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.c > #147078 > unrolled thread
| Started by | DFS <nospam@dfs.com> |
|---|---|
| First post | 2019-10-19 13:35 -0400 |
| Last post | 2019-10-27 13:09 -0700 |
| Articles | 20 on this page of 60 — 17 participants |
Back to article view | Back to comp.lang.c
How to use a struct with qsort()? DFS <nospam@dfs.com> - 2019-10-19 13:35 -0400
Re: How to use a struct with qsort()? Malcolm McLean <malcolm.arthur.mclean@gmail.com> - 2019-10-19 10:22 -0700
Re: How to use a struct with qsort()? DFS <nospam@dfs.com> - 2019-10-19 14:19 -0400
Re: How to use a struct with qsort()? Ben Bacarisse <ben.usenet@bsb.me.uk> - 2019-10-19 19:36 +0100
Re: How to use a struct with qsort()? Melzzzzz <Melzzzzz@zzzzz.com> - 2019-10-19 18:44 +0000
Re: How to use a struct with qsort()? Barry Schwarz <schwarzb@delq.com> - 2019-10-19 10:23 -0700
Re: How to use a struct with qsort()? Ike Naar <ike@sdf.lonestar.org> - 2019-10-19 19:09 +0000
Re: How to use a struct with qsort()? DFS <nospam@dfs.com> - 2019-10-19 15:51 -0400
Re: How to use a struct with qsort()? already5chosen@yahoo.com - 2019-10-19 13:09 -0700
Re: How to use a struct with qsort()? DFS <nospam@dfs.com> - 2019-10-19 16:26 -0400
Re: How to use a struct with qsort()? already5chosen@yahoo.com - 2019-10-19 13:51 -0700
Re: How to use a struct with qsort()? DFS <nospam@dfs.com> - 2019-10-19 17:24 -0400
Re: How to use a struct with qsort()? already5chosen@yahoo.com - 2019-10-19 14:49 -0700
Re: How to use a struct with qsort()? DFS <nospam@dfs.com> - 2019-10-19 18:26 -0400
Re: How to use a struct with qsort()? already5chosen@yahoo.com - 2019-10-19 16:32 -0700
Re: How to use a struct with qsort()? DFS <nospam@dfs.com> - 2019-10-20 09:22 -0400
Re: How to use a struct with qsort()? Paul <nospam@needed.invalid> - 2019-10-26 04:15 -0400
Re: How to use a struct with qsort()? DFS <nospam@dfs.com> - 2019-10-26 09:37 -0400
Re: How to use a struct with qsort()? Bart <bc@freeuk.com> - 2019-10-26 15:40 +0100
Re: How to use a struct with qsort()? DFS <nospam@dfs.com> - 2019-10-28 19:49 -0400
Re: How to use a struct with qsort()? Paul <nospam@needed.invalid> - 2019-10-29 01:59 -0400
Re: How to use a struct with qsort()? Paul <nospam@needed.invalid> - 2019-10-30 04:54 -0400
Re: How to use a struct with qsort()? Bart <bc@freeuk.com> - 2019-10-30 11:54 +0000
Re: How to use a struct with qsort()? Keith Thompson <kst-u@mib.org> - 2019-10-30 08:58 -0700
Re: How to use a struct with qsort()? Öö Tiib <ootiib@hot.ee> - 2019-11-07 01:10 -0800
Re: How to use a struct with qsort()? Bart <bc@freeuk.com> - 2019-11-07 10:51 +0000
Re: How to use a struct with qsort()? Paul <nospam@needed.invalid> - 2019-10-26 15:03 -0400
Re: How to use a struct with qsort()? Ben Bacarisse <ben.usenet@bsb.me.uk> - 2019-10-26 21:50 +0100
Re: How to use a struct with qsort()? Tim Rentsch <tr.17687@z991.linuxsc.com> - 2019-11-04 16:02 -0800
Re: How to use a struct with qsort()? Jorgen Grahn <grahn+nntp@snipabacken.se> - 2019-10-21 11:58 +0000
Re: How to use a struct with qsort()? Tim Rentsch <tr.17687@z991.linuxsc.com> - 2019-10-23 04:51 -0700
Re: How to use a struct with qsort()? Bart <bc@freeuk.com> - 2019-10-19 23:25 +0100
Re: How to use a struct with qsort()? Keith Thompson <kst-u@mib.org> - 2019-10-19 15:38 -0700
Re: How to use a struct with qsort()? David Brown <david.brown@hesbynett.no> - 2019-10-20 14:44 +0200
Re: How to use a struct with qsort()? DFS <nospam@dfs.com> - 2019-10-22 15:42 -0400
Re: How to use a struct with qsort()? Tim Rentsch <tr.17687@z991.linuxsc.com> - 2019-10-23 05:47 -0700
Re: How to use a struct with qsort()? Bart <bc@freeuk.com> - 2019-10-23 16:40 +0100
Re: How to use a struct with qsort()? Keith Thompson <kst-u@mib.org> - 2019-10-23 13:51 -0700
Re: How to use a struct with qsort()? Bart <bc@freeuk.com> - 2019-10-23 23:07 +0100
Re: How to use a struct with qsort()? Keith Thompson <kst-u@mib.org> - 2019-10-23 15:50 -0700
Re: How to use a struct with qsort()? Bart <bc@freeuk.com> - 2019-10-24 01:20 +0100
Re: How to use a struct with qsort()? Keith Thompson <kst-u@mib.org> - 2019-10-23 18:20 -0700
Re: How to use a struct with qsort()? Bart <bc@freeuk.com> - 2019-10-24 10:40 +0100
Re: How to use a struct with qsort()? Keith Thompson <kst-u@mib.org> - 2019-10-24 11:00 -0700
Re: How to use a struct with qsort()? Ben Bacarisse <ben.usenet@bsb.me.uk> - 2019-10-20 00:30 +0100
Re: How to use a struct with qsort()? Bart <bc@freeuk.com> - 2019-10-20 00:44 +0100
Re: How to use a struct with qsort()? Ben Bacarisse <ben.usenet@bsb.me.uk> - 2019-10-20 01:27 +0100
Re: How to use a struct with qsort()? Manfred <noname@add.invalid> - 2019-10-25 20:30 +0200
Re: How to use a struct with qsort()? DFS <nospam@dfs.com> - 2019-10-25 16:07 -0400
Re: How to use a struct with qsort()? Ike Naar <ike@sdf.lonestar.org> - 2019-10-26 07:27 +0000
Re: How to use a struct with qsort()? Keith Thompson <kst-u@mib.org> - 2019-10-26 02:11 -0700
Re: How to use a struct with qsort()? Bart <bc@freeuk.com> - 2019-10-26 11:06 +0100
Re: How to use a struct with qsort()? Manfred <noname@invalid.add> - 2019-10-26 16:58 +0200
Re: How to use a struct with qsort()? DFS <nospam@dfs.com> - 2019-10-26 18:17 -0400
Re: How to use a struct with qsort()? Keith Thompson <kst-u@mib.org> - 2019-10-26 16:08 -0700
Re: How to use a struct with qsort()? DFS <nospam@dfs.com> - 2019-10-26 21:33 -0400
Re: How to use a struct with qsort()? Keith Thompson <kst-u@mib.org> - 2019-10-26 22:10 -0700
Re: How to use a struct with qsort()? Ben Bacarisse <ben.usenet@bsb.me.uk> - 2019-10-27 01:48 +0100
Re: How to use a struct with qsort()? Manfred <noname@invalid.add> - 2019-10-27 19:29 +0100
Re: How to use a struct with qsort()? Barry Schwarz <schwarzb4aarp@gmail.com> - 2019-10-27 13:09 -0700
Page 3 of 3 — ← Prev page 1 2 [3]
| From | Bart <bc@freeuk.com> |
|---|---|
| Date | 2019-10-24 01:20 +0100 |
| Message-ID | <%66sF.406317$3C5.184897@fx01.am4> |
| In reply to | #147180 |
On 23/10/2019 23:50, Keith Thompson wrote: > Bart <bc@freeuk.com> writes: > One of your examples was > struct T T; > It could have been > struct COFF_Reloc_Rec COFF_Reloc_Rec; > Do we agree that using the same identifer for a struct tag and for an > object of the struct type is a bad idea? Or for a typedef name and an > object of that type? That's what you did in your example. Perhaps a > longer name would have made that clearer. Yet C allows that, and in the same scope. That's only possible using struct (and enum) tags, so avoiding struct tags makes it impossible to do that. > I don't recall anyone suggesting using the same name for a type and > for an object of that type. You did so in your example. If that > wasn't your intent, I'll accept that -- but then I'm not sure what point > you were making. In the original example, 'struct words' was used, with 'wordrec' used for a variable, even though 'words' would have been a better name for the variable. Yet the language allows, via struct tags, both 'struct words' and the variable 'words' to be used together. > Yes, I understand that. "int*" is not an anonymous type. It has a > name, and that name is "int*". (See the definition of "type-name" in > the C syntax. It's not just an identifier.) As I said, the context here was user-names for struct tags, typedefs and variables. I don't know what unambiguous denotation can be used for each of those to make it clear I'm not talking about type constructs. > Great. In this case, doing so may have unintentionally obscured your > point. Really? You see 'struct T T' and you should instantly see the problem.
[toc] | [prev] | [next] | [standalone]
| From | Keith Thompson <kst-u@mib.org> |
|---|---|
| Date | 2019-10-23 18:20 -0700 |
| Message-ID | <lnzhhraqh0.fsf@kst-u.example.com> |
| In reply to | #147181 |
Bart <bc@freeuk.com> writes:
> On 23/10/2019 23:50, Keith Thompson wrote:
>> One of your examples was
>> struct T T;
>> It could have been
>> struct COFF_Reloc_Rec COFF_Reloc_Rec;
>> Do we agree that using the same identifer for a struct tag and for an
>> object of the struct type is a bad idea? Or for a typedef name and an
>> object of that type? That's what you did in your example. Perhaps a
>> longer name would have made that clearer.
>
> Yet C allows that, and in the same scope. That's only possible using
> struct (and enum) tags, so avoiding struct tags makes it impossible to
> do that.
Yes, C allows all kinds of things that are bad ideas. All languages do.
You haven't answered my question. Do you agree that using the same name
for an object and the tag for the object's name is a bad idea? I
believe you do, but I don't want to put words in your mouth.
Are you saying that (a) you dislike struct tags, and (b) the reason you
dislike struct tags is that they make it possible to use the same
identifier for an object and for the tag for the object's type? I can
understand (a). If you're claiming (b), I find that very odd.
>> I don't recall anyone suggesting using the same name for a type and
>> for an object of that type. You did so in your example. If that
>> wasn't your intent, I'll accept that -- but then I'm not sure what point
>> you were making.
>
> In the original example, 'struct words' was used, with 'wordrec' used
> for a variable, even though 'words' would have been a better name for
> the variable. Yet the language allows, via struct tags, both 'struct
> words' and the variable 'words' to be used together.
>
>> Yes, I understand that. "int*" is not an anonymous type. It has a
>> name, and that name is "int*". (See the definition of "type-name" in
>> the C syntax. It's not just an identifier.)
>
> As I said, the context here was user-names for struct tags, typedefs and
> variables. I don't know what unambiguous denotation can be used for each
> of those to make it clear I'm not talking about type constructs.
I suppose you're talking about "type names that are either a single
identifier or the keyword struct, union, or enum followed by a single
identifier". So what point are you making about such type names?
>> Great. In this case, doing so may have unintentionally obscured your
>> point.
>
> Really? You see 'struct T T' and you should instantly see the problem.
I see two problems. One is the use of the non-descriptive name "T",
which we've thoroughly covered. The other is the use of the same
identifier as a tag and as an object name.
You make the point that using a struct tag makes it possible to
use the same identifier for a struct tag and for an object of the
struct type. I agree (though I don't agree that it's a big deal,
since it can easily be avoided by picking sensible names). Did you
have another point?
I don't intend to continue posting on this thread for much longer, so
please make any points you wish me to respond to as soon as possible.
--
Keith Thompson (The_Other_Keith) kst-u@mib.org <http://www.ghoti.net/~kst>
Will write code for food.
void Void(void) { Void(); } /* The recursive call of the void */
[toc] | [prev] | [next] | [standalone]
| From | Bart <bc@freeuk.com> |
|---|---|
| Date | 2019-10-24 10:40 +0100 |
| Message-ID | <CkesF.853476$qd4.170475@fx17.am4> |
| In reply to | #147183 |
On 24/10/2019 02:20, Keith Thompson wrote:
> Bart <bc@freeuk.com> writes:
>> Really? You see 'struct T T' and you should instantly see the problem.
>
> I see two problems. One is the use of the non-descriptive name "T",
> which we've thoroughly covered.
Yes. It is totally irrelevant, and is chosen to highlight the actual
point that exactly the same identifier can be used for very different
purposes. I still fail to understand why you mentioned it in the first
place.
If I was talking about the following ways of using arrays in C:
int A[10];
int *B = malloc(40);
int (*C)[]=malloc(40);
would you also be sidetracked by the fact that A, B, C are
non-descriptive single letter names?
The other is the use of the same
> identifier as a tag and as an object name.
>
> You make the point that using a struct tag makes it possible to
> use the same identifier for a struct tag and for an object of the
> struct type. I agree (though I don't agree that it's a big deal,
> since it can easily be avoided by picking sensible names).
You wouldn't. A beginner might, since there is nothing that stops it.
> Did you
> have another point?
Did you have another pointless objection?
[toc] | [prev] | [next] | [standalone]
| From | Keith Thompson <kst-u@mib.org> |
|---|---|
| Date | 2019-10-24 11:00 -0700 |
| Message-ID | <lnsgniaurn.fsf@kst-u.example.com> |
| In reply to | #147188 |
Bart <bc@freeuk.com> writes:
> On 24/10/2019 02:20, Keith Thompson wrote:
>> Bart <bc@freeuk.com> writes:
>
>>> Really? You see 'struct T T' and you should instantly see the problem.
>>
>> I see two problems. One is the use of the non-descriptive name "T",
>> which we've thoroughly covered.
>
> Yes. It is totally irrelevant, and is chosen to highlight the actual
> point that exactly the same identifier can be used for very different
> purposes. I still fail to understand why you mentioned it in the first
> place.
I fail to understand why we're still talking about it. We've been
agreeing on this point for the last several followups.
>> The other is the use of the same identifier as a tag and as an object
>> name.
>>
>> You make the point that using a struct tag makes it possible to
>> use the same identifier for a struct tag and for an object of the
>> struct type. I agree (though I don't agree that it's a big deal,
>> since it can easily be avoided by picking sensible names).
>
> You wouldn't. A beginner might, since there is nothing that stops it.
>
>> Did you have another point?
>
> Did you have another pointless objection?
If you're not going to answer straightforward questions, this
discussion is over.
--
Keith Thompson (The_Other_Keith) kst-u@mib.org <http://www.ghoti.net/~kst>
Will write code for food.
void Void(void) { Void(); } /* The recursive call of the void */
[toc] | [prev] | [next] | [standalone]
| From | Ben Bacarisse <ben.usenet@bsb.me.uk> |
|---|---|
| Date | 2019-10-20 00:30 +0100 |
| Message-ID | <87k190z53b.fsf@bsb.me.uk> |
| In reply to | #147089 |
DFS <nospam@dfs.com> writes:
> Here's the program as it stands, which works great except for
> this sorting issue. You can test it by using words_alpha.txt from
> https://github.com/dwyl/english-words
Just a heads-up: you've excluded people who can't build MS-Windows
programs. I'm not sure why since the task appears to be a simple text
processing one, but some people won't bother with a Windows build.
Anyway, a comment or two...
> //build struct
> struct words {char *word; double wordpf;};
> struct words **wordrec = NULL;
You want a simple "struct words *wordrec" here. You can get by with an
array of pointers, but I can't see the point.
> //sort structure by prime factors, then word
> int comparepf(const void *p1, const void *p2)
> {
> const struct words *a = p1;
> const struct words *b = p2;
> //printf("%.0lf %.0lf\n",a->wordpf,b->wordpf);
> if(a->wordpf > b->wordpf)
> return 1;
> else if (a->wordpf < b->wordpf)
> return -1;
> else
> return 0;
> }
This function is wrong if the array is of struct pointers. It is
written for my preferred solution: an array of structs. Therefore,
though it might be simplest to correct this function, I'd change the
other parts instead.
> //memory
> wordrec = (struct words **)realloc(wordrec,(wordcnt+1) * sizeof(struct words *));
There's a lot to be said about this line, but let's just fix a couple of
things:
wordrec = realloc(wordrec, (wordcnt+1) * sizeof *wordrec);
i.e. drop the cast and use the size of the pointer rather than repeating
what type it is. Had you done this originally, you could change the
type of wordrec as I am suggesting above and not have to bother about
this line.
> wordrec[wordcnt] = (struct words *)malloc(sizeof(struct words));
If you change wordrec to be an array of structs you don't need this line
at all!
> wordrec[wordcnt]->word = malloc(strlen(wordin)+1);
and this line becomes
wordrec[wordcnt].word = malloc(strlen(wordin)+1);
> qsort(struct wordrec, wordcnt, sizeof(struct wordrec), comparepf);
This won't compile. If you make the changes I suggest, you'll need
qsort(wordrec, wordcnt, sizeof *wordrec, comparepf);
But if keep wordrec as an array of pointers you have the element size
wrong. Each one is sizeof(struct wordrec *) not sizeof(struct
wordrec). You can avoid this problem by always using the size of data
itself so you never have to write the type put again. In other words
qsort(wordrec, wordcnt, sizeof *wordrec, comparepf);
will work for an array of structs and for an array of pointers to
structs. The compare function has to be written differently, but
neither the allocation lines nor the qsort line needs to change if you
swap to an array of structs.
--
Ben.
[toc] | [prev] | [next] | [standalone]
| From | Bart <bc@freeuk.com> |
|---|---|
| Date | 2019-10-20 00:44 +0100 |
| Message-ID | <jdNqF.986025$R83.745664@fx23.am4> |
| In reply to | #147098 |
On 20/10/2019 00:30, Ben Bacarisse wrote: > DFS <nospam@dfs.com> writes: > >> Here's the program as it stands, which works great except for >> this sorting issue. You can test it by using words_alpha.txt from >> https://github.com/dwyl/english-words > > Just a heads-up: you've excluded people who can't build MS-Windows > programs. I'm not sure why since the task appears to be a simple text > processing one, but some people won't bother with a Windows build. Removing Windows and timing related code (QueryPerformance, elapsedtime etc) makes it compile under Linux (with a fix for line 111). (Such timing is probably premature here, but I anyway just use clock(), or just time the whole program.)
[toc] | [prev] | [next] | [standalone]
| From | Ben Bacarisse <ben.usenet@bsb.me.uk> |
|---|---|
| Date | 2019-10-20 01:27 +0100 |
| Message-ID | <878spgz2eo.fsf@bsb.me.uk> |
| In reply to | #147089 |
DFS <nospam@dfs.com> writes:
> Here's the program as it stands, which works great except for
> this sorting issue.
You can make it work by removing the sort line! It turns out you don't
use the fact that the list is sorted. Now that might be a temporary
issue. If so, you need to take a look at the bsearch function.
I was able to get you code to work (after removing the Windows stuff)
with only two changes. (1) Correct the compare function so that it
expects two pointer to pointer arguments; and (2) correct the qsort line
as I showed before. There are other issues (missing ctype.h for
example) but this was the minimum change.
It's not my preferred correction (you don't need pointers to structs in
the array) but it does work.
> //sort structure by prime factors, then word
> int comparepf(const void *p1, const void *p2)
> {
> const struct words *a = p1;
> const struct words *b = p2;
Put
const struct words **ap = p1, *a = *ap;
const struct words **bp = p2, *b = *bp;
here to get started.
> //printf("%.0lf %.0lf\n",a->wordpf,b->wordpf);
> if(a->wordpf > b->wordpf)
> return 1;
> else if (a->wordpf < b->wordpf)
> return -1;
> else
> return 0;
> }
> qsort(struct wordrec, wordcnt, sizeof(struct wordrec), comparepf);
qsort(wordrec, wordcnt, sizeof *wordrec, comparepf);
--
Ben.
[toc] | [prev] | [next] | [standalone]
| From | Manfred <noname@add.invalid> |
|---|---|
| Date | 2019-10-25 20:30 +0200 |
| Message-ID | <qovf0n$1lfh$1@gioia.aioe.org> |
| In reply to | #147089 |
On 10/19/2019 10:26 PM, DFS wrote:
> int primes[26] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41,
> 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101};
> char *charset = "abcdefghijklmnopqrstuvwxyz";
Since primes and charset are strictly coupled, it is a good idea to
enforce consistency of their sizes as in:
#include <assert.h>
static const unsigned int primes[] =
{
2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41,
43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101
};
static const char charset[] = "abcdefghijklmnopqrstuvwxyz";
static_assert(sizeof(primes)/sizeof(primes[0]) ==
(sizeof(charset)/sizeof(charset[0])-1),
"charset and primes mismatch");
[...]
> //compute product of primes corresponding to the letters of the input word
> double calcpf(char *str, int len) {
> double pf = 1;
> for(i=0;i<len;i++) {
FWIW the following will result in an access violation whenever str[i] is
not found in charset (e.g for an uppercase char). Since str comes from
an external source (the dictionary file), the program should be able to
handle this possibility.
In general, it is not a good idea to index into an array so blindly.
> pf *= primes[(int)(strchr(charset, str[i]) - charset)];
> }
> return pf;
> }
[toc] | [prev] | [next] | [standalone]
| From | DFS <nospam@dfs.com> |
|---|---|
| Date | 2019-10-25 16:07 -0400 |
| Message-ID | <xCIsF.37804$LV2.24120@fx28.iad> |
| In reply to | #147232 |
On 10/25/2019 2:30 PM, Manfred wrote:
> On 10/19/2019 10:26 PM, DFS wrote:
>> int primes[26] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41,
>> 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101}; char
>> *charset = "abcdefghijklmnopqrstuvwxyz";
> Since primes and charset are strictly coupled, it is a good idea to
> enforce consistency of their sizes as in:
> #include <assert.h>
> static const unsigned int primes[] =
> {
> 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41,
> 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101
> };
> static const char charset[] = "abcdefghijklmnopqrstuvwxyz";
> static_assert(sizeof(primes)/sizeof(primes[0]) ==
> (sizeof(charset)/sizeof(charset[0])-1),
> "charset and primes mismatch");
>
> [...]
Thanks for the tips.
>> //compute product of primes corresponding to the letters of the input
>> word
>> double calcpf(char *str, int len) {
>> double pf = 1;
>> for(i=0;i<len;i++) {
> FWIW the following will result in an access violation whenever str[i] is
> not found in charset (e.g for an uppercase char). Since str comes from
> an external source (the dictionary file), the program should be able to
> handle this possibility.
> In general, it is not a good idea to index into an array so blindly.
>> pf *= primes[(int)(strchr(charset, str[i]) - charset)];
>
>> }
>> return pf;
>> }
Thanks, but of course I know how to handle incoming vs acceptable data.
This is just personal code. The dictionary is local and under my
control, and is all lowercase.
[toc] | [prev] | [next] | [standalone]
| From | Ike Naar <ike@sdf.lonestar.org> |
|---|---|
| Date | 2019-10-26 07:27 +0000 |
| Message-ID | <slrn3s58qr7ta4.j26.ike@sdf.lonestar.org> |
| In reply to | #147232 |
On 2019-10-25, Manfred <noname@add.invalid> wrote:
> On 10/19/2019 10:26 PM, DFS wrote:
>> int primes[26] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41,
>> 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101};
>> char *charset = "abcdefghijklmnopqrstuvwxyz";
> Since primes and charset are strictly coupled, it is a good idea to
> enforce consistency of their sizes as in:
> #include <assert.h>
> static const unsigned int primes[] =
> {
> 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41,
> 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101
> };
> static const char charset[] = "abcdefghijklmnopqrstuvwxyz";
> static_assert(sizeof(primes)/sizeof(primes[0]) ==
> (sizeof(charset)/sizeof(charset[0])-1),
> "charset and primes mismatch");
Why the "-1" ?
primes[] and charset[] have the same number of elements (26).
[toc] | [prev] | [next] | [standalone]
| From | Keith Thompson <kst-u@mib.org> |
|---|---|
| Date | 2019-10-26 02:11 -0700 |
| Message-ID | <lnv9sban20.fsf@kst-u.example.com> |
| In reply to | #147237 |
Ike Naar <ike@sdf.lonestar.org> writes:
> On 2019-10-25, Manfred <noname@add.invalid> wrote:
>> On 10/19/2019 10:26 PM, DFS wrote:
>>> int primes[26] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41,
>>> 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101};
>>> char *charset = "abcdefghijklmnopqrstuvwxyz";
>> Since primes and charset are strictly coupled, it is a good idea to
>> enforce consistency of their sizes as in:
>> #include <assert.h>
>> static const unsigned int primes[] =
>> {
>> 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41,
>> 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101
>> };
>> static const char charset[] = "abcdefghijklmnopqrstuvwxyz";
>> static_assert(sizeof(primes)/sizeof(primes[0]) ==
>> (sizeof(charset)/sizeof(charset[0])-1),
>> "charset and primes mismatch");
>
> Why the "-1" ?
> primes[] and charset[] have the same number of elements (26).
No, charset[] has 27 elements. It's initialized from a string literal,
so there's a trailing '\0'.
--
Keith Thompson (The_Other_Keith) kst-u@mib.org <http://www.ghoti.net/~kst>
Will write code for food.
void Void(void) { Void(); } /* The recursive call of the void */
[toc] | [prev] | [next] | [standalone]
| From | Bart <bc@freeuk.com> |
|---|---|
| Date | 2019-10-26 11:06 +0100 |
| Message-ID | <kUUsF.1229971$WI2.370840@fx34.am4> |
| In reply to | #147232 |
On 25/10/2019 19:30, Manfred wrote:
> On 10/19/2019 10:26 PM, DFS wrote:
>> int primes[26] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41,
>> 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101}; char
>> *charset = "abcdefghijklmnopqrstuvwxyz";
> Since primes and charset are strictly coupled, it is a good idea to
> enforce consistency of their sizes as in:
> #include <assert.h>
> static const unsigned int primes[] =
> {
> 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41,
> 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101
> };
> static const char charset[] = "abcdefghijklmnopqrstuvwxyz";
> static_assert(sizeof(primes)/sizeof(primes[0]) ==
> (sizeof(charset)/sizeof(charset[0])-1),
> "charset and primes mismatch");
Looks like overkill. Since charset is defined as a 'char' array in the
preceding line, you can assume that sizeof(charset[0]) is 1.
After all, it does assume that charset[] is initialised from a string,
so has a "-1" (as pointed out by someone), but it will go wrong if
initialised from {'a',...'z'};
It also does not report an error if the letters are not in order
(although for this program it doesn't matter, very often it will do).
Neither will it do so if both primes and charset both have too many
elements, so long as they both have the same number. Nor when they both
have too few (you additionally need an assert that prime has 26 elements).
Nor when some elements of prime[] are not prime numbers. Or it has
duplicates. Or characters inside charset are not a-z or are duplicates.
In short, so many assumptions are being made anyway...
(TBF, use of charset[] is already overkill, since its entire purpose
seems to be to convert 'a' to 'z' into 0 to 25, which is trivially done
by subtracting 'a'.
Since the program seems to rely on a word list downloaded from the
internet, the chances of that file being 8-bit EBCDIC are infinitesimal.)
[toc] | [prev] | [next] | [standalone]
| From | Manfred <noname@invalid.add> |
|---|---|
| Date | 2019-10-26 16:58 +0200 |
| Message-ID | <qp1mtt$1f9h$1@gioia.aioe.org> |
| In reply to | #147240 |
On 10/26/19 12:06 PM, Bart wrote:
> On 25/10/2019 19:30, Manfred wrote:
>> On 10/19/2019 10:26 PM, DFS wrote:
>>> int primes[26] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41,
>>> 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101}; char
>>> *charset = "abcdefghijklmnopqrstuvwxyz";
>> Since primes and charset are strictly coupled, it is a good idea to
>> enforce consistency of their sizes as in:
>> #include <assert.h>
>> static const unsigned int primes[] =
>> {
>> 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41,
>> 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101
>> };
>> static const char charset[] = "abcdefghijklmnopqrstuvwxyz";
>> static_assert(sizeof(primes)/sizeof(primes[0]) ==
>
>> (sizeof(charset)/sizeof(charset[0])-1),
>> "charset and primes mismatch");
>
>
> Looks like overkill. Since charset is defined as a 'char' array in the
> preceding line, you can assume that sizeof(charset[0]) is 1.
In this particular case it is more verbose than needed, but:
1) The constraint to be enforced is about number of /elements/ of the
two arrays (modulo '\0' in the string), not /bytes/, so in this way I
think it is more clear what it is about, even if it happens that element
size of the second array is 1 - I see this as a coincidence that is
orthogonal to the algorithm logic.
2) In this way the code will continue to work with /no change/ if at
some point the character type be changed into something else, typically
wchar_t (I know that wchar_t is not popular in *nix programming, but it
is almost a must in any real world Windows programming)
3) You know that this is all compile-time processing, so even if it is
more verbose it has zero impact on the compiled code.
>
> After all, it does assume that charset[] is initialised from a string,
> so has a "-1" (as pointed out by someone), but it will go wrong if
> initialised from {'a',...'z'};
In the expression as written the -1 will continue to work with wchar_t,
and yes it will not work if the array is brace initialized, but I think
that changing a string into a brace list is not something that is easily
overlooked by any C programmer.
>
> It also does not report an error if the letters are not in order
> (although for this program it doesn't matter, very often it will do).
>
> Neither will it do so if both primes and charset both have too many
> elements, so long as they both have the same number. Nor when they both
> have too few (you additionally need an assert that prime has 26 elements).
>
> Nor when some elements of prime[] are not prime numbers. Or it has
> duplicates. Or characters inside charset are not a-z or are duplicates.
>
> In short, so many assumptions are being made anyway...
The main purpose of this static_assert it to guarantee consistency with
usage of the arrays, i.e. the following calcpf():
> //compute product of primes corresponding to the letters of the input word
> double calcpf(char *str, int len) {
> double pf = 1;
> for(i=0;i<len;i++) {
> pf *= primes[(int)(strchr(charset, str[i]) - charset)];
> }
> return pf;
> }
It is this function that is strictly coupled with the two arrays above,
and, apart of possible overflow of the multiplication, what is required
for this function to avoid UB is to guard the expression
> primes[(int)(strchr(charset, str[i]) - charset)];
This expression has defined behavior if and only if:
1) strchr returns a pointer into charset (hence my remark about the need
for handling this at runtime)
2) charset and primes have the same number of elements[*] (hence the
static_assert)
Yes, there may be many other mistakes that can be made, but at least the
examples you mentioned would cause incorrect results rather than
undefined behavior (and incorrect results are more likely to be caught
during testing than UB, which is the nastiest of beasts). On the other
hand, filling the code with static_asserts would really be overkill, and
not what the expression is meant for.
>
> (TBF, use of charset[] is already overkill, since its entire purpose
> seems to be to convert 'a' to 'z' into 0 to 25, which is trivially done
> by subtracting 'a'.
>
> Since the program seems to rely on a word list downloaded from the
> internet, the chances of that file being 8-bit EBCDIC are infinitesimal.)
>
There can be much more to be said about the complete program (the OP's
memory management mistakes and his/her remark about books being
unhelpful suggest limited knowledge of C) - my 2c were on this piece of
functionality that I thought was worth a comment.
[*] (strictly speaking, even if primes has more elements that charset
there still is defined behavior.)
[toc] | [prev] | [next] | [standalone]
| From | DFS <nospam@dfs.com> |
|---|---|
| Date | 2019-10-26 18:17 -0400 |
| Message-ID | <vC3tF.55417$SW2.31092@fx24.iad> |
| In reply to | #147244 |
On 10/26/2019 10:58 AM, Manfred wrote:
> There can be much more to be said about the complete program
Please, speak up. Won't hurt my feelings.
> (the OP's memory management mistakes
Feel free to show them. I want to get it as right as possible.
> and his/her remark about books being
> unhelpful suggest limited knowledge of C)
Let me show you an example:
Bart posted a modified example of my code. In it he used memset this way:
#define N_LETTERS 26
unsigned char sc[N_LETTERS];
memset(sc, 0, N_LETTERS);
A tutorialspoint.com webpage does it similarly:
char str[50];
memset(str,'$',7);
Should be simple, right?
So I try it in my code, to replace a small loop:
int wsvals[26]={0}; (not a char as in previous examples)
memset(wsvals,0,26);
Doesn't work. The code compiles (tcc Windows) with no warnings, but it
doesn't execute.
Finally on stackoverflow I find this:
"Note that for memset you have to pass the number of bytes, not the
number of elements because this is an old C function:
So I do: memset(wsvals,0,26 * sizeof(int));
And it works.
Most of the descriptions on the web say memset "is used to fill a block
of memory with given/particular value." No mention of the datatype.
Why do I need to also use sizeof() for an int but not a char?
[toc] | [prev] | [next] | [standalone]
| From | Keith Thompson <kst-u@mib.org> |
|---|---|
| Date | 2019-10-26 16:08 -0700 |
| Message-ID | <lnmudn9kay.fsf@kst-u.example.com> |
| In reply to | #147269 |
DFS <nospam@dfs.com> writes:
[...]
> So I try it in my code, to replace a small loop:
>
> int wsvals[26]={0}; (not a char as in previous examples)
> memset(wsvals,0,26);
>
> Doesn't work. The code compiles (tcc Windows) with no warnings, but it
> doesn't execute.
I presume it does execute. It just doesn't do what you wanted it to do.
> Finally on stackoverflow I find this:
> "Note that for memset you have to pass the number of bytes, not the
> number of elements because this is an old C function:
>
> So I do: memset(wsvals,0,26 * sizeof(int));
>
> And it works.
>
> Most of the descriptions on the web say memset "is used to fill a block
> of memory with given/particular value." No mention of the datatype.
>
> Why do I need to also use sizeof() for an int but not a char?
Because sizeof (char) is 1 by definition. Given:
char arr[26];
you could do either
memset(arr, 0, 26);
or
memset(arr, 0, 26*sizeof(char));
Both are equivalent.
But given an array of any type that you want to zero-fill, just apply
sizeof to the entire object:
int wsvals[26];
memset(wsvals, 0, sizeof wsvals);
Note also that in your example, you already initialized the array:
int wsvals[26]={0};
so there's no need to call memset.
--
Keith Thompson (The_Other_Keith) kst-u@mib.org <http://www.ghoti.net/~kst>
Will write code for food.
void Void(void) { Void(); } /* The recursive call of the void */
[toc] | [prev] | [next] | [standalone]
| From | DFS <nospam@dfs.com> |
|---|---|
| Date | 2019-10-26 21:33 -0400 |
| Message-ID | <wu6tF.72303$oA2.48417@fx08.iad> |
| In reply to | #147271 |
On 10/26/2019 7:08 PM, Keith Thompson wrote:
> DFS <nospam@dfs.com> writes:
> [...]
>> So I try it in my code, to replace a small loop:
>>
>> int wsvals[26]={0}; (not a char as in previous examples)
>> memset(wsvals,0,26);
>>
>> Doesn't work. The code compiles (tcc Windows) with no warnings, but it
>> doesn't execute.
>
> I presume it does execute. It just doesn't do what you wanted it to do.
Can't tell what it does. These are the letter counts /after/
memset(vals,0,26), where vals is an int. The first one is correct
because it's the first count done after initialization.
abcdefghijklmnopqrstuvwxyz
21011001000100000010000010 abashedly
11001001000200000010000010 able
11000011000200000010000010 bag
11000001000200000011000010 bat
11001001000300000011000010 bela
10100001000300000012000010 cat
10101002000400110022100010 cephalous
11101002100510220033100010 compatibles
11000012100510220033100010 gab
20112103100511420334100030 hydroferrocyanate
10002003200513430434100030 neperian
10001003200613440544100040 parsley
10001003200713450654100050 players
11002004300713460985300050 subtreasurership
11000004300713460986300050 tab
300010143008154601088410160 unextravagantly
100000044008164701088410160 Spain
100000045008174801098410160 pains
101000055008274801198410160 march
101000065008274801298410160 March
now use
memset(vals, 0, 26*sizeof(int))
or
memset(vals, 0, sizeof vals)
abcdefghijklmnopqrstuvwxyz
21011001000100000010000010 abashedly
11001000000100000000000000 able
11000010000000000000000000 bag
11000000000000000001000000 bat
11001000000100000000000000 bela
10100000000000000001000000 cat
10101001000100110010100000 cephalous
11101000100110110011000000 compatibles
11000010000000000000000000 gab
20112101000001200301000020 hydroferrocyanate
10002000100002010100000000 neperian
10001000000100010110000010 parsley
10001000000100010110000010 players
11002001100000010331200000 subtreasurership
11000000000000000001000000 tab
30001010000102000102110110 unextravagantly
10000000100001010000000000 Spain
10000000100001010010000000 pains
10100001000010000100000000 march
10100001000000000100000000 March
>> Finally on stackoverflow I find this:
>> "Note that for memset you have to pass the number of bytes, not the
>> number of elements because this is an old C function:
>>
>> So I do: memset(wsvals,0,26 * sizeof(int));
>>
>> And it works.
>>
>> Most of the descriptions on the web say memset "is used to fill a block
>> of memory with given/particular value." No mention of the datatype.
>>
>> Why do I need to also use sizeof() for an int but not a char?
>
> Because sizeof (char) is 1 by definition. Given:
> char arr[26];
> you could do either
> memset(arr, 0, 26);
> or
> memset(arr, 0, 26*sizeof(char));
> Both are equivalent.
Why doesn't the compiler recognize the data type of the object being
passed to memset, and handle the sizing for you?
So that memset(arr, v, N) would work for chars and ints.
> But given an array of any type that you want to zero-fill, just apply
> sizeof to the entire object:
> int wsvals[26];
> memset(wsvals, 0, sizeof wsvals);
Perfect. I'll remember to use that from now on.
memset is probably a bit faster than a loop, too.
> Note also that in your example, you already initialized the array:
> int wsvals[26]={0};
> so there's no need to call memset.
I didn't show, but it needs to be reset each loop.
[toc] | [prev] | [next] | [standalone]
| From | Keith Thompson <kst-u@mib.org> |
|---|---|
| Date | 2019-10-26 22:10 -0700 |
| Message-ID | <lnblu2ai4r.fsf@kst-u.example.com> |
| In reply to | #147275 |
DFS <nospam@dfs.com> writes:
> On 10/26/2019 7:08 PM, Keith Thompson wrote:
>> DFS <nospam@dfs.com> writes:
>> [...]
>>> So I try it in my code, to replace a small loop:
>>>
>>> int wsvals[26]={0}; (not a char as in previous examples)
>>> memset(wsvals,0,26);
>>>
>>> Doesn't work. The code compiles (tcc Windows) with no warnings, but it
>>> doesn't execute.
>>
>> I presume it does execute. It just doesn't do what you wanted it to do.
>
> Can't tell what it does. These are the letter counts /after/
> memset(vals,0,26), where vals is an int. The first one is correct
> because it's the first count done after initialization.
I can tell you exactly what it does. It zeros the first 26 *bytes* of
wsvals. If sizeof (int) == 4 on your system, then that means it zeros
the first 6 elements of the array, and the first half of the seventh
(wsvals[6]), not touching the rest of the array.
You didn't tell us that the declaration (with an initializer) and the
memset call are separate, with memset possibly being called more than
once. We can only diagnose the code you show us.
If wsvals is initialized to all zeros at the point of definition (with
the `= {0}` initializer), and then only the first quarter of the array
is zeroed on subsequent iterations, then data will accumulate in the
last 3/4 of the array. I presume the behavior you're seeing is
consistent with that, but I'm not going to take the time to confirm it.
Feel free to do so if you're curious.
[...]
> Why doesn't the compiler recognize the data type of the object being
> passed to memset, and handle the sizing for you?
>
> So that memset(arr, v, N) would work for chars and ints.
Because it can't. memset is a function, not a built-in language
feature. Its first argument is of type void*, which carries no
information about the type or size of the target object.
That also means that you can use memset() to set every element of a char
array to some non-zero value, but you can't do that with an int array,
because it sets every *byte* to the specified value. For example:
char char_array[N];
int int_array[N];
memset(char_array, 0x42, sizeof char_array);
// sets each element to 0x42
memset(int_array, 0x42, sizeof int_array);
// sets each byte to 0x42, which most likely sets
// each element to 0x42424242
0 is the most commonly used value.
[...]
--
Keith Thompson (The_Other_Keith) kst-u@mib.org <http://www.ghoti.net/~kst>
Will write code for food.
void Void(void) { Void(); } /* The recursive call of the void */
[toc] | [prev] | [next] | [standalone]
| From | Ben Bacarisse <ben.usenet@bsb.me.uk> |
|---|---|
| Date | 2019-10-27 01:48 +0100 |
| Message-ID | <87wocrrp22.fsf@bsb.me.uk> |
| In reply to | #147269 |
DFS <nospam@dfs.com> writes:
> On 10/26/2019 10:58 AM, Manfred wrote:
<cut>
>> and his/her remark about books being unhelpful suggest limited knowledge of C)
>
>
> Let me show you an example:
>
> Bart posted a modified example of my code. In it he used memset this way:
>
> #define N_LETTERS 26
> unsigned char sc[N_LETTERS];
> memset(sc, 0, N_LETTERS);
>
>
> A tutorialspoint.com webpage does it similarly:
That's not a book, of course, but I think tutorials were also
mentioned. I agree with you here. There are so many awful online
tutorials that it is rarely a good idea to rely on them.
> char str[50];
> memset(str,'$',7);
>
>
> Should be simple, right?
Yes, it should be. The tutorial is, at best, very misleading.
> So I try it in my code, to replace a small loop:
>
> int wsvals[26]={0}; (not a char as in previous examples)
> memset(wsvals,0,26);
I defence of the (pretty bad) tutorialspoint.com page it describes
memset as a string function (so it's not encouraging its use for int
arrays) and it does give some hints about what memset really does in the
more general case. It says, for example, that the third parameter is
the number of bytes to be set.
> Doesn't work. The code compiles (tcc Windows) with no warnings, but
> it doesn't execute.
You are not showing us the real code. The memset you show here is
harmless as the array is zeroed by the initialisation. I think the
memset is used elsewhere in the code to get back to the initial state of
wsvals.
Every tutorial about memset should show something like
int wsvals[26];
...
memset(wsvals, 0, sizeof wsvals);
There is often no need to repeat either the length or the type of the
array.
> Finally on stackoverflow I find this:
> "Note that for memset you have to pass the number of bytes, not the
> number of elements because this is an old C function:
>
> So I do: memset(wsvals,0,26 * sizeof(int));
but, here, memset(wsvals, 0, sizeof wsvals) works with no change, even
if you switch the type of the array elements to some other integer type.
With dynamically allocated storage, you usually have to do the
multiplication but you can still use a type-agnostic form like this:
ptr = malloc(n_elements * sizeof *ptr);
...
memset(ptr, 0, n_elements * sizeof *ptr);
There are lots of caveats here (C is not a uniform language), but I'll
leave them to others who might want to point then out -- unless you want
a fuller explanation.
> And it works.
>
> Most of the descriptions on the web say memset "is used to fill a
> block of memory with given/particular value." No mention of the
> datatype.
>
> Why do I need to also use sizeof() for an int but not a char?
Short answer: because sizeof(char) == 1. Longer answer: sizeof is
defined to gave the number of char objects that make up the
representation of objects of some type. C, quite reasonably, calls
these "bytes", but on some very odd machines that can be a bit
surprising. On the vast majority of systems, int objects are
represented in memory by 2 or 4 consecutive bytes of storage.
--
Ben.
[toc] | [prev] | [next] | [standalone]
| From | Manfred <noname@invalid.add> |
|---|---|
| Date | 2019-10-27 19:29 +0100 |
| Message-ID | <qp4nn5$t96$1@gioia.aioe.org> |
| In reply to | #147269 |
On 10/27/19 12:17 AM, DFS wrote:
> On 10/26/2019 10:58 AM, Manfred wrote:
>
>
>> There can be much more to be said about the complete program
>
> Please, speak up. Won't hurt my feelings.
No intention to hurt anyone's feelings, my remark was meant as an answer
to Bart, who was commenting with several points - my intention was more
like "I know that static_assert won't fix everything" rather than hurt
feelings.
>
>
>> (the OP's memory management mistakes
>
> Feel free to show them. I want to get it as right as possible.
>
>
>> and his/her remark about books being unhelpful suggest limited
>> knowledge of C)
This part was more "direct", indeed - it could have come out better, I
admit.
Anyway, you initial code showed confusion between strut words* and
struct words** pointers, which is something that you would have known if
you had gone through something like K&R.
One more issue I can point out is how you free()'d memory at the end of
the program:
>
> free(wordrec);
Before explaining my issue with it I have to acknowledge that this
happens just before program exit, so in this case all memory gets
deallocated anyway, but the fact that you put the free() call shows that
your intention is to clean up memory yourself, so here we go. And, more
importantly, if this were a normal function instead of main(), leaking
memory would be a relevant matter instead.
Others have pointed out that you allocated wordrec as an array of
*pointers*, each one of which points to some other malloc()'d chunk of
memory containing a struct words object, each of which in turns contains
another pointer 'word' that points to more malloc()'d memory that holds
the associated string.
I won't repeat that part of this indirection is unnecessary, I will only
point out that if you free(wordrec) you deallocate only the wordrec
array, not all memory that is pointed to by the nested pointers. If you
want to free all memory you should do something like this:
while(0 < wordcnt--)
{
free(wordrec[wordcnt]->word);
free(wordrec[wordcnt]);
}
free(wordrec);
Other issues that pop to the eye:
You fgets() from the file with a 30 bytes buffer, but the longest word
in the dictionary is dichlorodiphenyltrichloroethane which is 31 letters
long, to which '\n' and the null terminator have to be added, so you are
reading lines with an insufficient buffer.
You use argv[1] and argv[2] without checking for argc, so if you run the
program with no arguments you run into UB (most likely access violation).
See below about 'books'
>
>
> Let me show you an example:
>
> Bart posted a modified example of my code. In it he used memset this way:
>
> #define N_LETTERS 26
> unsigned char sc[N_LETTERS];
> memset(sc, 0, N_LETTERS);
>
>
> A tutorialspoint.com webpage does it similarly:
> char str[50];
> memset(str,'$',7);
>
>
> Should be simple, right?
>
> So I try it in my code, to replace a small loop:
>
> int wsvals[26]={0}; (not a char as in previous examples)
> memset(wsvals,0,26);
>
> Doesn't work. The code compiles (tcc Windows) with no warnings, but it
> doesn't execute.
>
> Finally on stackoverflow I find this:
> "Note that for memset you have to pass the number of bytes, not the
> number of elements because this is an old C function:
>
> So I do: memset(wsvals,0,26 * sizeof(int));
>
> And it works.
>
> Most of the descriptions on the web say memset "is used to fill a block
> of memory with given/particular value." No mention of the datatype.
>
> Why do I need to also use sizeof() for an int but not a char?
>
>
>
Others have answered, but talking about knowledge and books, the very
fact that you ask why sizeof() is needed for an int shows limited
knowledge about C basics; beware, there is obviously nothing wrong about
this, and it is perfectly OK to ask, but combined with a phrase about
books being unhelpful it can trigger a remark if the intention is to
"get it as right as possible"
I left 'tutorials' intentionally out of my remark. As Ben said, there is
a lot of awful stuff out there.
But in my opinion if someone wants to get C right then reading a good
book is needed. (Doing it just for fun is a different matter, of course.)
[toc] | [prev] | [next] | [standalone]
| From | Barry Schwarz <schwarzb4aarp@gmail.com> |
|---|---|
| Date | 2019-10-27 13:09 -0700 |
| Message-ID | <13368fae-6d90-497f-bf0e-3862b318df62@googlegroups.com> |
| In reply to | #147269 |
On Saturday, October 26, 2019 at 3:18:15 PM UTC-7, DFS wrote: > Most of the descriptions on the web say memset "is used to fill a block > of memory with given/particular value." No mention of the datatype. Why are you using questionable sources for reference about a standard function. Copies of the standard are readily available (e.g., n1570). It clearly states 7.24.6.1 The memset function Synopsis 1 #include <string.h> void *memset(void *s, int c, size_t n); Description 2 The memset function copies the value of c (converted to an unsigned char) into each of the first n characters of the object pointed to by s. Returns 3 The memset function returns the value of s.
[toc] | [prev] | [standalone]
Page 3 of 3 — ← Prev page 1 2 [3]
Back to top | Article view | comp.lang.c
csiph-web