Discussion:
writing a c program to substitute text
Add Reply
fred flintstone
2017-02-26 12:14:11 UTC
Reply
Permalink
Raw Message
Hello ng,

Usually, I cruise through clc on the way to somewhere else, but I've
spent so long reconstituting my c capabilities that I want to acquire a
few more before I focus on perl. In the perl world, I'm still working
through the material of _Intermediate Perl_, but it forces the serious
student to get involved in the world of github, packages, and the 50% I
haven't done yet. That can rest for the moment.

Instead I seek something that is right on the kingpin for topicality in
clc. Here is the text file I want to substitute into:

echo 'after preprocessor your program is' >text3.txt
gcc -E arrow.c >>text3.txt
echo 'after compilation avec warnings, output is' >>text3.txt
gcc -Wall -Wextra -o arrow arrow.c >>text3.txt
./arrow >>text3.txt
echo 'source listing is' >>text3.txt
cat arrow.c >>text3.txt

So there's 3DBESNUB type things that a gonzaga-beating cougar will do in
terms of general problem solving or even forensic problem-solving. Right
at the top is that I don't know how to declare strings in c in a safe way.

Let's say that you're hard-coding a string between single quotes, for
example:

'arrow'

, how do I declare this string to exist safely?

Do I malloc a 1000 because someone has to make an adult decision?
--
fred flintstone
fir
2017-02-26 12:55:52 UTC
Reply
Permalink
Raw Message
Post by fred flintstone
Hello ng,
Usually, I cruise through clc on the way to somewhere else, but I've
spent so long reconstituting my c capabilities that I want to acquire a
few more before I focus on perl. In the perl world, I'm still working
through the material of _Intermediate Perl_, but it forces the serious
student to get involved in the world of github, packages, and the 50% I
haven't done yet. That can rest for the moment.
Instead I seek something that is right on the kingpin for topicality in
echo 'after preprocessor your program is' >text3.txt
gcc -E arrow.c >>text3.txt
echo 'after compilation avec warnings, output is' >>text3.txt
gcc -Wall -Wextra -o arrow arrow.c >>text3.txt
./arrow >>text3.txt
echo 'source listing is' >>text3.txt
cat arrow.c >>text3.txt
So there's 3DBESNUB type things that a gonzaga-beating cougar will do in
terms of general problem solving or even forensic problem-solving. Right
at the top is that I don't know how to declare strings in c in a safe way.
Let's say that you're hard-coding a string between single quotes, for
'arrow'
, how do I declare this string to exist safely?
c is not safe it is dangerous;c, it is something like skateboarding and we c people like it

besides if you use

char* s = "arrow";

it isnt insanely 'unsafe'
Post by fred flintstone
Do I malloc a 1000 because someone has to make an adult decision?
--
fred flintstone
David Brown
2017-02-26 13:28:25 UTC
Reply
Permalink
Raw Message
Post by fred flintstone
Hello ng,
Usually, I cruise through clc on the way to somewhere else, but I've
spent so long reconstituting my c capabilities that I want to acquire a
few more before I focus on perl. In the perl world, I'm still working
through the material of _Intermediate Perl_, but it forces the serious
student to get involved in the world of github, packages, and the 50% I
haven't done yet. That can rest for the moment.
Instead I seek something that is right on the kingpin for topicality in
echo 'after preprocessor your program is' >text3.txt
gcc -E arrow.c >>text3.txt
echo 'after compilation avec warnings, output is' >>text3.txt
gcc -Wall -Wextra -o arrow arrow.c >>text3.txt
./arrow >>text3.txt
echo 'source listing is' >>text3.txt
cat arrow.c >>text3.txt
So there's 3DBESNUB type things that a gonzaga-beating cougar will do in
terms of general problem solving or even forensic problem-solving. Right
at the top is that I don't know how to declare strings in c in a safe way.
Let's say that you're hard-coding a string between single quotes, for
'arrow'
, how do I declare this string to exist safely?
Do I malloc a 1000 because someone has to make an adult decision?
I cannot fathom what you are trying to say or do here. I know fine what
the commands above do, but don't understand why - nor does "3DBESNUB
type things" or "gonzaga-beating cougar" make any sense.

In C, strings are between double quotes, not single quotes (they are for
character literals). Writing something like

const char *s = "Arrow";

is perfectly safe.

If you have a C question to ask, feel free and many people here will try
to answer it. But please, make it comprehensible and say what you are
actually trying to do - it makes it a lot easier to help. Perhaps give
an example of the code you are trying to write, and then say where you
are having trouble.
fred flintstone
2017-02-27 11:58:26 UTC
Reply
Permalink
Raw Message
Post by David Brown
I cannot fathom what you are trying to say or do here. I know fine what
the commands above do, but don't understand why - nor does "3DBESNUB
type things" or "gonzaga-beating cougar" make any sense.
In C, strings are between double quotes, not single quotes (they are for
character literals). Writing something like
const char *s = "Arrow";
is perfectly safe.
If you have a C question to ask, feel free and many people here will try
to answer it. But please, make it comprehensible and say what you are
actually trying to do - it makes it a lot easier to help. Perhaps give
an example of the code you are trying to write, and then say where you
are having trouble.
As James Kuyper correctly links downthread, 3DBESNUB was the
problem-solving acronym that my entire cohort at BYU had to use to get
full credit on any physics problem. The first three letters are for
diagrams, but they are in short supply in usenet.

It seems I need code to describe the type of code I want. I honestly
thought I had to come up with a number that wouldn't be smaller in bytes
than whatever I'm storing in a string.

Let me cough up some source and address a specification:

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

int main(void)
{
int version;
int c;
FILE *fptr, *gptr;
const char *executable1 = "arrow";
const char *executable2 = "mahershala";
const char *base = "toolchain";
const char *ext = "sh";
fptr = fopen("toolchain3.sh","r");

if(fptr == NULL)
{
printf("fopen no bueno");
exit(1);
}
gptr = fopen("toolchain4.sh","w");

if(gptr == NULL)
{
printf("gopen no bueno");
exit(1);
}

while (1) {
c = fgetc(fptr);

if (c == EOF)
break;
else
putc(c, gptr);
}


fclose(fptr);
fclose(gptr);

return 0;
}

I need to concatenate 'toolchain3.sh' from its constituent parts and
then increment it as the filename of gptr.

This lacks the logic for a substitution but sets the stage for it. In
the newly-created .sh file, executable2 shall be substituted for
executable1. Again, for reference, this is our file:

echo 'after preprocessor your program is' >text3.txt
gcc -E arrow.c >>text3.txt
echo 'after compilation avec warnings, output is' >>text3.txt
gcc -Wall -Wextra -o arrow arrow.c >>text3.txt
./arrow >>text3.txt
echo 'source listing is' >>text3.txt
cat arrow.c >>text3.txt

Also, I need a way of determining the natural number that follows
'text'. This is to be substituted by the number appending 'toolchain',
so that the new number is uniform.

Alright, I hope I am clearer now. The BYU cougars did beat undefeated
Gonzaga in college hoops. It was a news event and this is a newsgroup,
where we do a lot of talking about C. It's also basketball season.

How important are substitutions, especially when they are errant? Did
you watch the Oscars?
--
fred flintstone
Ben Bacarisse
2017-02-27 13:11:45 UTC
Reply
Permalink
Raw Message
fred flintstone <***@server.invalid> writes:
<snip>
Post by fred flintstone
I need to concatenate 'toolchain3.sh' from its constituent parts and
then increment it as the filename of gptr.
That's not too hard, but it's much more fiddly in C than in any
scripting language I can think of. Why do you want to do this in C?
The kind of things you hint at doing elsewhere in your post are trivial
in any of the many scripting languages you have available.

Anyway, here's one way:

int vnum = 3;
const char *base = "toolchain", *ext = "sh", *name_fmt = "%s%d.%s";
char name1[snprintf(0, 0, name_fmt, base, vnum, ext) + 1];
int s = snprintf(name1, sizeof name1, name_fmt, base, vnum, ext);

Repeat after vnum += 1;. Whether this is suitable (it's C99) depends in
part on why you using C.

<snip>
(Your posts will get more helpful replies if they are short and to the
point.)
--
Ben.
BartC
2017-02-27 13:33:08 UTC
Reply
Permalink
Raw Message
Post by Ben Bacarisse
<snip>
Post by fred flintstone
I need to concatenate 'toolchain3.sh' from its constituent parts and
then increment it as the filename of gptr.
That's not too hard, but it's much more fiddly in C than in any
scripting language I can think of. Why do you want to do this in C?
The kind of things you hint at doing elsewhere in your post are trivial
in any of the many scripting languages you have available.
int vnum = 3;
const char *base = "toolchain", *ext = "sh", *name_fmt = "%s%d.%s";
char name1[snprintf(0, 0, name_fmt, base, vnum, ext) + 1];
int s = snprintf(name1, sizeof name1, name_fmt, base, vnum, ext);
Here's pretty much the same thing but without a VLA, nor the weird thing
with putting an snprintf call inside the array bounds.

But it needs an upper limit for the filename length to be set. The part
calling 'getfilename' will have an idea of what is reasonable, in this
case it has to accommadate 'toolchainN.sh' where N, because I've made it
an int, might have 10 or 11 digits. So 300 is plenty.

---------------------------------------

#include <stdio.h>

void getfilename(char* dest, int destsize,
char* basefile, int index, char* extension) {
snprintf(dest,destsize, "%s%d.%s", basefile, index, extension);
}

int main(void) {
char filename[300];
int i;

for (i=1; i<=10; ++i) {
getfilename(filename, sizeof filename, "toolchain",i,"sh");
puts(filename);
}
}
--
bartc
Scott Lurndal
2017-02-27 17:12:18 UTC
Reply
Permalink
Raw Message
Post by BartC
Post by Ben Bacarisse
<snip>
Post by fred flintstone
I need to concatenate 'toolchain3.sh' from its constituent parts and
then increment it as the filename of gptr.
That's not too hard, but it's much more fiddly in C than in any
scripting language I can think of. Why do you want to do this in C?
The kind of things you hint at doing elsewhere in your post are trivial
in any of the many scripting languages you have available.
int vnum = 3;
const char *base = "toolchain", *ext = "sh", *name_fmt = "%s%d.%s";
char name1[snprintf(0, 0, name_fmt, base, vnum, ext) + 1];
int s = snprintf(name1, sizeof name1, name_fmt, base, vnum, ext);
Here's pretty much the same thing but without a VLA, nor the weird thing
with putting an snprintf call inside the array bounds.
That weird thing ensures that 'name1' is allocated enough
memory to hold the entire string.
Post by BartC
But it needs an upper limit for the filename length to be set. The part
calling 'getfilename' will have an idea of what is reasonable, in this
case it has to accommadate 'toolchainN.sh' where N, because I've made it
an int, might have 10 or 11 digits. So 300 is plenty.
Until someone moves it to a deeply nested home directory with a
512 byte path prefix.
Post by BartC
---------------------------------------
#include <stdio.h>
void getfilename(char* dest, int destsize,
the second argument to snprintf is a size_t, sizeof returns
a size_t, thus 'destsize' should be declared as a size_t.
Post by BartC
char* basefile, int index, char* extension)
basefile and extension should be declared as const. And, if
'N' in your filename should be a positive value, make index
unsigned and use '%u' in the format string.
BartC
2017-02-27 17:59:19 UTC
Reply
Permalink
Raw Message
Post by Scott Lurndal
Post by BartC
Post by Ben Bacarisse
<snip>
Post by fred flintstone
I need to concatenate 'toolchain3.sh' from its constituent parts and
then increment it as the filename of gptr.
That's not too hard, but it's much more fiddly in C than in any
scripting language I can think of. Why do you want to do this in C?
The kind of things you hint at doing elsewhere in your post are trivial
in any of the many scripting languages you have available.
int vnum = 3;
const char *base = "toolchain", *ext = "sh", *name_fmt = "%s%d.%s";
char name1[snprintf(0, 0, name_fmt, base, vnum, ext) + 1];
int s = snprintf(name1, sizeof name1, name_fmt, base, vnum, ext);
Here's pretty much the same thing but without a VLA, nor the weird thing
with putting an snprintf call inside the array bounds.
That weird thing ensures that 'name1' is allocated enough
memory to hold the entire string.
But requiring two passes.
Post by Scott Lurndal
Post by BartC
But it needs an upper limit for the filename length to be set. The part
calling 'getfilename' will have an idea of what is reasonable, in this
case it has to accommadate 'toolchainN.sh' where N, because I've made it
an int, might have 10 or 11 digits. So 300 is plenty.
Until someone moves it to a deeply nested home directory with a
512 byte path prefix.
That will be the same problem with the VLA code. Unless 'base' points to
that long path. But since it is a constant string, you will know it is a
long string and can adjust the buffer size accordingly.

Otherwise you're relying on a language feature that may not generally be
available.

Or you could use a much larger string buffer (eg 4K or 16K). If someone
is actually using 16000-character path lengths, then they've got bigger
problems, like knowing how to use paths sensibly, and understanding the
difference between the title of a file, and its contents; usually the
former is shorter than the latter.
--
bartc
David Brown
2017-02-27 18:05:37 UTC
Reply
Permalink
Raw Message
Post by BartC
Post by Scott Lurndal
Post by BartC
Post by Ben Bacarisse
<snip>
Post by fred flintstone
I need to concatenate 'toolchain3.sh' from its constituent parts and
then increment it as the filename of gptr.
That's not too hard, but it's much more fiddly in C than in any
scripting language I can think of. Why do you want to do this in C?
The kind of things you hint at doing elsewhere in your post are trivial
in any of the many scripting languages you have available.
int vnum = 3;
const char *base = "toolchain", *ext = "sh", *name_fmt = "%s%d.%s";
char name1[snprintf(0, 0, name_fmt, base, vnum, ext) + 1];
int s = snprintf(name1, sizeof name1, name_fmt, base, vnum, ext);
Here's pretty much the same thing but without a VLA, nor the weird thing
with putting an snprintf call inside the array bounds.
That weird thing ensures that 'name1' is allocated enough
memory to hold the entire string.
But requiring two passes.
That's life. You don't (in general) know how long a calculated string
will be until you have calculated it. Your choices are to calculate it
exactly (like this), allocate space larger than you could reasonably
expect (like you suggest), or combine the methods - allocate a large
space first, and if that turns out to be too small, allocate the
required size and re-do the snprintf.

Languages which have strings as a part of the language do the same -
they just hide the messy details. (This is, of course, one of the key
reasons that C is a poor choice if your program involves a lot of string
work.)
Post by BartC
Post by Scott Lurndal
Post by BartC
But it needs an upper limit for the filename length to be set. The part
calling 'getfilename' will have an idea of what is reasonable, in this
case it has to accommadate 'toolchainN.sh' where N, because I've made it
an int, might have 10 or 11 digits. So 300 is plenty.
Until someone moves it to a deeply nested home directory with a
512 byte path prefix.
That will be the same problem with the VLA code. Unless 'base' points to
that long path. But since it is a constant string, you will know it is a
long string and can adjust the buffer size accordingly.
Otherwise you're relying on a language feature that may not generally be
available.
Or you could use a much larger string buffer (eg 4K or 16K). If someone
is actually using 16000-character path lengths, then they've got bigger
problems, like knowing how to use paths sensibly, and understanding the
difference between the title of a file, and its contents; usually the
former is shorter than the latter.
Scott Lurndal
2017-02-27 18:37:33 UTC
Reply
Permalink
Raw Message
Post by BartC
Post by Scott Lurndal
Post by BartC
Post by Ben Bacarisse
<snip>
Post by fred flintstone
I need to concatenate 'toolchain3.sh' from its constituent parts and
then increment it as the filename of gptr.
That's not too hard, but it's much more fiddly in C than in any
scripting language I can think of. Why do you want to do this in C?
The kind of things you hint at doing elsewhere in your post are trivial
in any of the many scripting languages you have available.
int vnum = 3;
const char *base = "toolchain", *ext = "sh", *name_fmt = "%s%d.%s";
char name1[snprintf(0, 0, name_fmt, base, vnum, ext) + 1];
int s = snprintf(name1, sizeof name1, name_fmt, base, vnum, ext);
Here's pretty much the same thing but without a VLA, nor the weird thing
with putting an snprintf call inside the array bounds.
That weird thing ensures that 'name1' is allocated enough
memory to hold the entire string.
But requiring two passes.
The nature of strings, in C, where there is no associated
length kept (contrast with counted ASCII or VAX-11 descriptors).
Keith Thompson
2017-02-27 19:40:02 UTC
Reply
Permalink
Raw Message
[...]
Post by Scott Lurndal
Post by BartC
Post by Scott Lurndal
Post by BartC
Here's pretty much the same thing but without a VLA, nor the weird thing
with putting an snprintf call inside the array bounds.
That weird thing ensures that 'name1' is allocated enough
memory to hold the entire string.
But requiring two passes.
The nature of strings, in C, where there is no associated
length kept (contrast with counted ASCII or VAX-11 descriptors).
Even with counted strings, you still have to allocate memory to hold the
characters.
--
Keith Thompson (The_Other_Keith) kst-***@mib.org <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
Manfred
2017-02-27 15:03:16 UTC
Reply
Permalink
Raw Message
Post by Ben Bacarisse
<snip>
Post by fred flintstone
I need to concatenate 'toolchain3.sh' from its constituent parts and
then increment it as the filename of gptr.
That's not too hard, but it's much more fiddly in C than in any
scripting language I can think of. Why do you want to do this in C?
The kind of things you hint at doing elsewhere in your post are trivial
in any of the many scripting languages you have available.
Definitely true. Besides Perl, bash + sed come to mind. awk as well for
the more experienced.
fred flintstone
2017-03-01 13:33:56 UTC
Reply
Permalink
Raw Message
Post by Ben Bacarisse
<snip>
Post by fred flintstone
I need to concatenate 'toolchain3.sh' from its constituent parts and
then increment it as the filename of gptr.
That's not too hard, but it's much more fiddly in C than in any
scripting language I can think of. Why do you want to do this in C?
The kind of things you hint at doing elsewhere in your post are trivial
in any of the many scripting languages you have available.
int vnum = 3;
const char *base = "toolchain", *ext = "sh", *name_fmt = "%s%d.%s";
char name1[snprintf(0, 0, name_fmt, base, vnum, ext) + 1];
int s = snprintf(name1, sizeof name1, name_fmt, base, vnum, ext);
Repeat after vnum += 1;. Whether this is suitable (it's C99) depends in
part on why you using C.
I'm having trouble with this, ben:

int vnum, c, i;
FILE *fptr, *gptr;



vnum = 3;
const char *base = "toolchain", *ext = "sh", *name_fmt = "%s%d.%s";
char name1[snprintf (0, 0, name_fmt, base, vnum, ext) + 1];
int s = snprintf (name1, sizeof name1, name_fmt, base, vnum, ext);


fptr = fopen (name1, "r");
if (fptr == NULL) {
printf ("fopen no bueno");
exit (1);
}
vnum += 1;

char name2[snprintf (0, 0, name_fmt, base, vnum, ext) + 1];
int t = snprintf (name2, sizeof name1, name_fmt, base, vnum, ext);
gptr = fopen (name2, "w");

if (gptr == NULL) {
printf ("gopen no bueno");
exit (1);
}
Post by Ben Bacarisse
<snip>
(Your posts will get more helpful replies if they are short and to the
point.)
Does the source itself announce what's wrong with it?
--
fred
D. Aaron Sawyer
2017-03-01 14:32:15 UTC
Reply
Permalink
Raw Message
Post by fred flintstone
Post by Ben Bacarisse
<snip>
Post by fred flintstone
I need to concatenate 'toolchain3.sh' from its constituent parts and
then increment it as the filename of gptr.
That's not too hard, but it's much more fiddly in C than in any
scripting language I can think of. Why do you want to do this in C?
The kind of things you hint at doing elsewhere in your post are trivial
in any of the many scripting languages you have available.
int vnum = 3;
const char *base = "toolchain", *ext = "sh", *name_fmt = "%s%d.%s";
char name1[snprintf(0, 0, name_fmt, base, vnum, ext) + 1];
int s = snprintf(name1, sizeof name1, name_fmt, base, vnum, ext);
Repeat after vnum += 1;. Whether this is suitable (it's C99) depends in
part on why you using C.
int vnum, c, i;
FILE *fptr, *gptr;
vnum = 3;
const char *base = "toolchain", *ext = "sh", *name_fmt = "%s%d.%s";
char name1[snprintf (0, 0, name_fmt, base, vnum, ext) + 1];
int s = snprintf (name1, sizeof name1, name_fmt, base, vnum, ext);
fptr = fopen (name1, "r");
if (fptr == NULL) {
printf ("fopen no bueno");
exit (1);
}
vnum += 1;
char name2[snprintf (0, 0, name_fmt, base, vnum, ext) + 1];
int t = snprintf (name2, sizeof name1, name_fmt, base, vnum, ext);
^--- should be 2 (name2)
That is not a syntax error, nor a language grammar error.
It is just a line cloning error.
It will compile, link, and run without obvious error.
It will some day produce wrong results.
Post by fred flintstone
gptr = fopen (name2, "w");
if (gptr == NULL) {
printf ("gopen no bueno");
exit (1);
}
Post by Ben Bacarisse
<snip>
(Your posts will get more helpful replies if they are short and to the
point.)
Does the source itself announce what's wrong with it?
Latent bugs are nasty. Intermittent bugs are worse. Good luck.
fred flintstone
2017-03-01 14:59:35 UTC
Reply
Permalink
Raw Message
Post by D. Aaron Sawyer
Post by fred flintstone
Post by Ben Bacarisse
<snip>
Post by fred flintstone
I need to concatenate 'toolchain3.sh' from its constituent parts and
then increment it as the filename of gptr.
That's not too hard, but it's much more fiddly in C than in any
scripting language I can think of. Why do you want to do this in C?
The kind of things you hint at doing elsewhere in your post are trivial
in any of the many scripting languages you have available.
int vnum = 3;
const char *base = "toolchain", *ext = "sh", *name_fmt = "%s%d.%s";
char name1[snprintf(0, 0, name_fmt, base, vnum, ext) + 1];
int s = snprintf(name1, sizeof name1, name_fmt, base, vnum, ext);
Repeat after vnum += 1;. Whether this is suitable (it's C99) depends in
part on why you using C.
int vnum, c, i;
FILE *fptr, *gptr;
vnum = 3;
const char *base = "toolchain", *ext = "sh", *name_fmt = "%s%d.%s";
char name1[snprintf (0, 0, name_fmt, base, vnum, ext) + 1];
int s = snprintf (name1, sizeof name1, name_fmt, base, vnum, ext);
fptr = fopen (name1, "r");
if (fptr == NULL) {
printf ("fopen no bueno");
exit (1);
}
vnum += 1;
char name2[snprintf (0, 0, name_fmt, base, vnum, ext) + 1];
int t = snprintf (name2, sizeof name1, name_fmt, base, vnum, ext);
^--- should be 2 (name2)
That is not a syntax error, nor a language grammar error.
It is just a line cloning error.
It will compile, link, and run without obvious error.
It will some day produce wrong results.
Hmm...still stumped that I'm not getting a file created out of this:

s is 13
name1 is toolchain3.sh
t is 13
name2 is toolchain4.sh
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int
main (int argc, char *argv[])
{
int vnum, c, i;
FILE *fptr, *gptr;



vnum = 3;
const char *base = "toolchain", *ext = "sh", *name_fmt = "%s%d.%s";
char name1[snprintf (0, 0, name_fmt, base, vnum, ext) + 1];
int s = snprintf (name1, sizeof name1, name_fmt, base, vnum, ext);
printf ("s is %d\n", s);
printf ("name1 is %s\n", name1);

fptr = fopen (name1, "r");
if (fptr == NULL)
{
printf ("fopen no bueno");
exit (1);
}
vnum += 1;

char name2[snprintf (0, 0, name_fmt, base, vnum, ext) + 1];
int t = snprintf (name2, sizeof name2, name_fmt, base, vnum, ext);
printf ("t is %d\n", t);
printf ("name2 is %s\n", name2);
gptr = fopen (name2, "w");

if (gptr == NULL)
{
printf ("gopen no bueno");
exit (1);
}

while (1)
{
c = fgetc (fptr);

if (c == EOF)
break;
else
putc (c, gptr);
}


fclose (fptr);
fclose (gptr);

return 0;
}
Post by D. Aaron Sawyer
Post by fred flintstone
gptr = fopen (name2, "w");
if (gptr == NULL) {
printf ("gopen no bueno");
exit (1);
}
Post by Ben Bacarisse
<snip>
(Your posts will get more helpful replies if they are short and to the
point.)
Does the source itself announce what's wrong with it?
Latent bugs are nasty. Intermittent bugs are worse. Good luck.
Nice catch. Thanks.
--
fred
Ben Bacarisse
2017-03-01 15:24:10 UTC
Reply
Permalink
Raw Message
<snip>
Post by Ben Bacarisse
Post by D. Aaron Sawyer
Post by fred flintstone
char name2[snprintf (0, 0, name_fmt, base, vnum, ext) + 1];
int t = snprintf (name2, sizeof name1, name_fmt, base, vnum, ext);
^--- should be 2 (name2)
That is not a syntax error, nor a language grammar error.
It is just a line cloning error.
It will compile, link, and run without obvious error.
It will some day produce wrong results.
More information is needed. The code looks fine and I *do* get the file
created, so I can't investigate why you don't. If it was a matter of
file permissions you'd get an error opening name2 in "w" mode.

<snip>
Post by Ben Bacarisse
vnum = 3;
const char *base = "toolchain", *ext = "sh", *name_fmt = "%s%d.%s";
char name1[snprintf (0, 0, name_fmt, base, vnum, ext) + 1];
int s = snprintf (name1, sizeof name1, name_fmt, base, vnum, ext);
printf ("s is %d\n", s);
printf ("name1 is %s\n", name1);
fptr = fopen (name1, "r");
if (fptr == NULL)
{
printf ("fopen no bueno");
exit (1);
}
I'd make this a function. Exactly how much needs to be passed in will
depend on things I don't currently know but here's a guess:

FILE *open_toolchain_file(int vnum, const char *mode)
{
const char *name_fmt = "toolchain%d.sh";
char fname[snprintf(0, 0, name_fmt, vnum) + 1];
snprintf(fname, sizeof fname, name_fmt, vnum);

FILE *fp = fopen(fname, mode);
if (fp == NULL) {
fprintf(stderr, "Unable to open %s in %s mode.\n", fname, mode);
exit(EXIT_FAILURE);
}
return fp;
}

<snip>
--
Ben.
fred flintstone
2017-03-02 09:47:10 UTC
Reply
Permalink
Raw Message
Post by Ben Bacarisse
I'd make this a function. Exactly how much needs to be passed in will
FILE *open_toolchain_file(int vnum, const char *mode)
{
const char *name_fmt = "toolchain%d.sh";
char fname[snprintf(0, 0, name_fmt, vnum) + 1];
snprintf(fname, sizeof fname, name_fmt, vnum);
FILE *fp = fopen(fname, mode);
if (fp == NULL) {
fprintf(stderr, "Unable to open %s in %s mode.\n", fname, mode);
exit(EXIT_FAILURE);
}
return fp;
}
<snip>
I'll try to implement that. (Really hazy on how to pass in C.)

Switched out main controls:

s is 13
name1 is toolchain3.sh
t is 13
name2 is toolchain4.sh
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int
main (int argc, char *argv[])
{
int vnum, c, i;
FILE *fptr, *gptr;

vnum = 3;
const char *base = "toolchain", *ext = "sh", *name_fmt = "%s%d.%s";
char name1[snprintf (0, 0, name_fmt, base, vnum, ext) + 1];
int s = snprintf (name1, sizeof name1, name_fmt, base, vnum, ext);
printf ("s is %d\n", s);
printf ("name1 is %s\n", name1);

fptr = fopen (name1, "r");
if (fptr == NULL)
{
printf ("fopen no bueno");
exit (1);
}
vnum += 1;

char name2[snprintf (0, 0, name_fmt, base, vnum, ext) + 1];
int t = snprintf (name2, sizeof name2, name_fmt, base, vnum, ext);
printf ("t is %d\n", t);
printf ("name2 is %s\n", name2);
gptr = fopen (name2, "w");

if (gptr == NULL)
{
printf ("gopen no bueno");
exit (1);
}


if (fptr != NULL && gptr != NULL)
{
while ((c = getc (fptr)) != EOF)
{
putc (c, gptr);
}
fclose (fptr);
fclose (gptr);
}
return 0;
}

Thanks.
--
fred
Ben Bacarisse
2017-03-02 11:05:22 UTC
Reply
Permalink
Raw Message
Post by fred flintstone
Post by Ben Bacarisse
I'd make this a function. Exactly how much needs to be passed in will
FILE *open_toolchain_file(int vnum, const char *mode)
{
const char *name_fmt = "toolchain%d.sh";
char fname[snprintf(0, 0, name_fmt, vnum) + 1];
snprintf(fname, sizeof fname, name_fmt, vnum);
FILE *fp = fopen(fname, mode);
if (fp == NULL) {
fprintf(stderr, "Unable to open %s in %s mode.\n", fname, mode);
exit(EXIT_FAILURE);
}
return fp;
}
<snip>
I'll try to implement that. (Really hazy on how to pass in C.)
Ah, no, don't. When someone shows a fragment of code (or an exploratory
program) all sorts of possible ways of tidying it up present themselves,
but now that I've a complete program that's closer (or maybe is) what
you are finally aiming for, I don't think the function above will help
at all. (Something a bit like it might, but certainly not as written.)
--
Ben.
Jens Thoms Toerring
2017-02-27 13:33:47 UTC
Reply
Permalink
Raw Message
fred flintstone <***@server.invalid> wrote:
From: ***@toerring.de (Jens Thoms Toerring)
To: fred flintstone <***@server.invalid>
Subject: Re: writing a c program to substitute text
In-Reply-To: <***@mid.individual.net>
X-Newsgroups: comp.lang.c
Post by fred flintstone
It seems I need code to describe the type of code I want. I honestly
thought I had to come up with a number that wouldn't be smaller in bytes
than whatever I'm storing in a string.
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int version;
int c;
FILE *fptr, *gptr;
const char *executable1 = "arrow";
const char *executable2 = "mahershala";
const char *base = "toolchain";
const char *ext = "sh";
fptr = fopen("toolchain3.sh","r");
if(fptr == NULL)
{
printf("fopen no bueno");
exit(1);
}
<snipped>
Post by fred flintstone
I need to concatenate 'toolchain3.sh' from its constituent parts and
then increment it as the filename of gptr.
If you need to concatenate twp strings, the result tring needs
to be large enough to accomodate both, obviously. And in order
write to a string it can't be a const char pointer, you'll need
an modifiable array.

There's no string type in C. All you have is char arrays.
And a char array that contains a '\0' character can be called
a string - "strings" are just char arrays containing a "sen-
tinel" element that indicates where the content ends. All
the built-in "string"-handling function expect such a char
array containing a '\0' somewhere as inputs (and try to
return such kind of arrays).

A const char * like this is a special case:

const char * txt = "bar";

Is a pointer to an array of chars that resides (often in
write-only) memory and that is ininitialized ith the four
chars 'b', 'a', 'r' and '\0'. Note that when you have

const char * txt1 = "bar";
const char * txt2 = "foobar";

'txt1' could end up being a pointer to the 4th character
in 'txt2'!

You can change what such a pointer points to, but not the
content of what it points to (i.e. the string itself. For
that you need an array:

char txt[4] = "bar";

This is a char array with 4 elements that is initialized
to the same sequence of chars as above (the '4' is optional
when you initialize it like this). You can change any of
the chars it contains (but make sure that at least one of
them is a '\0' - or it won't be string anymore but a mere
array of chars).

Obviously, this won't do if you want to append another string
to it since there's no room left for that. If you know in
advance how long the resulting string is going ti be you
could define it with a larger size, e.g.

char txt[8] = "bar";
strcat(txt, ".exe");

This is correct since the resulting string "bar.exe" requires
8 chars (including the trailing '\0'). Of course, you can
make it larger if you feel like it.

If you have no idea jow long the strings will become you'll
have to use a different strategy, you need to use allocated
memory. Take a simple function that concatenates two strings
of lengths unknown at compile time.

char * mycat(const char * a, const char *b)
{
char *res = malloc(strlen(a) + strlen(b) + 1);
if (res != NULL) {
strcpy(p, res);
strcal(p, res);
}
return ret;
}

Note first that this function takes two arguments that are
of type const char *. This does not imply that both the
arguments have to be const char pointers, it could also be
pointers to modifiable arrays (or arrays of allocated memory
as returned by this function). Note second that it's the
responsibility of the caller to make sure that both are
strings, i.e. pointers to char arrays that contain a '\0'.
Note third that function will return a NULL pointer if
there was not enough memory available. And, finally, the
caller bears the responsibility of free()-ing the returned
string once he's done with it.

These are the building blocks you get in C (plus a few func-
tions for strung handling). All the rest you've got for
yourself. It's a lot more time-consuming to write correct
code for that than in other languages - but which often them-
selves are implemented in C and just hide the complexity from
you (and typically are a lot slower since they must implement
the most general case).

E.g., if you do in Perl

my $n = 18;
my $str = "bar$n";

then I C you could have function for this likr

char * append_int(const char *pre, int n)
{
char * res = malloc(strlen(pre) + (n ? (log(labs(n)) + 2) : 1) + 1);
if (res)
sprintf(res, "%s%d", pre, n);
return res;
}

The 'log(labs(n)) + 2' is there to determine how many digits
the value of n will require when represented as a string
(and keeping in mind that it might be negative). The case
of n == 0 must be treated specially since log(0) is not
defined. If the function returns NULL this, again, indi-
cates that not enough memory was available.

You could use these functions to assemble your filename,
e.g. like this

const char * basename = "toolchain";
const char * ext = ".sh";
char * p;
char * name = NULL;
FILE *fptr;

if ((p = append_int(basename, 3)) != NULL) {
name = mycat(p, ext);
free(p);
}

if (name == NULL)
fprintf(stderr, "Out of memory\n");
exit( EXIT_FAILURE;
}

fptr = fopen(name, "r");

if (fptr == NULL) {
fprintf(stderr, "Failed to open %s for reading\n", name);
free(name);
exit(EXIT_FAILURE);
}

free(name);

Of course, you can avoid the complexities of using allocated
memory (and the ensuing rquirement to release it when not
needed anymore to avoid memory leaks) if you have a reliable
upper limit of the lengths of your strings. Though this can
often be difficult to predict and a wrong guess can lead to
catastrophic failure of you're program.

Regards, Jens
--
\ Jens Thoms Toerring ___ ***@toerring.de
\__________________________ http://toerring.de
Stefan Ram
2017-02-27 14:10:45 UTC
Reply
Permalink
Raw Message
Post by Jens Thoms Toerring
upper limit of the lengths of your strings. Though this can
often be difficult to predict and a wrong guess can lead to
catastrophic failure of you're program.
Not if the guess is properly protected by a test:

if( required < 300 ){ char buff[ 300 ]; ... }
else { /* appropriate code here */ }

. But AFAIK C makes no guarantee about the amount of automatic
storage available or explains what happens when it's exhausted.

For example, we cannot prove that an implementation has
enough automatic storage even for

#include <stdlib.h>
int main( void ){ int n = rand(); srand( n ); }

(Some say we cannot prove it even for »int main( void ){}«.)

and even less so for »buff[ 300 ]«.
Keith Thompson
2017-02-27 17:10:16 UTC
Reply
Permalink
Raw Message
***@toerring.de (Jens Thoms Toerring) writes:
[...]
Post by Jens Thoms Toerring
const char * txt = "bar";
Is a pointer to an array of chars that resides (often in
write-only) memory and that is ininitialized ith the four
chars 'b', 'a', 'r' and '\0'.
I'm pretty sure you meant "read-only", not "write-only".

[...]
Post by Jens Thoms Toerring
char * mycat(const char * a, const char *b)
[...]
Post by Jens Thoms Toerring
Note first that this function takes two arguments that are
of type const char *. This does not imply that both the
arguments have to be const char pointers, it could also be
pointers to modifiable arrays (or arrays of allocated memory
as returned by this function). Note second that it's the
responsibility of the caller to make sure that both are
strings, i.e. pointers to char arrays that contain a '\0'.
Correction: it's the responsibility of the caller to make sure
that both are *pointers to* strings. (A "pointer to a string"
is by definition a pointer to the initial character of a string.)

[...]
--
Keith Thompson (The_Other_Keith) kst-***@mib.org <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
David Brown
2017-02-27 18:07:50 UTC
Reply
Permalink
Raw Message
Post by Keith Thompson
[...]
Post by Jens Thoms Toerring
const char * txt = "bar";
Is a pointer to an array of chars that resides (often in
write-only) memory and that is ininitialized ith the four
chars 'b', 'a', 'r' and '\0'.
I'm pretty sure you meant "read-only", not "write-only".
Maybe he is working with a Signetics 25120 chip :-)
Jens Thoms Toerring
2017-02-27 18:23:25 UTC
Reply
Permalink
Raw Message
Post by David Brown
Post by Keith Thompson
[...]
Post by Jens Thoms Toerring
const char * txt = "bar";
Is a pointer to an array of chars that resides (often in
write-only) memory and that is ininitialized ith the four
chars 'b', 'a', 'r' and '\0'.
I'm pretty sure you meant "read-only", not "write-only".
Maybe he is working with a Signetics 25120 chip :-)
;-)
--
\ Jens Thoms Toerring ___ ***@toerring.de
\__________________________ http://toerring.de
David Brown
2017-02-27 13:46:24 UTC
Reply
Permalink
Raw Message
Post by fred flintstone
Post by David Brown
I cannot fathom what you are trying to say or do here. I know fine what
the commands above do, but don't understand why - nor does "3DBESNUB
type things" or "gonzaga-beating cougar" make any sense.
In C, strings are between double quotes, not single quotes (they are for
character literals). Writing something like
const char *s = "Arrow";
is perfectly safe.
If you have a C question to ask, feel free and many people here will try
to answer it. But please, make it comprehensible and say what you are
actually trying to do - it makes it a lot easier to help. Perhaps give
an example of the code you are trying to write, and then say where you
are having trouble.
As James Kuyper correctly links downthread, 3DBESNUB was the
problem-solving acronym that my entire cohort at BYU had to use to get
full credit on any physics problem. The first three letters are for
diagrams, but they are in short supply in usenet.
So it is a strange acronym used within a department of a particular
university? This is an international group for C programming - it is
ridiculous to assume that anyone would know that, and entirely
unreasonable to expect people to google it or bother to read the webpage
that James found. For that matter, it is ridiculous to assume that
anyone would know what BYU stands for (some university somewhere, as far
as I can see).

When you want help, give /relevant/ information, keep /irrelevant/
information to a minimum, and minimise the effort other people will need
in order to help you.
Post by fred flintstone
It seems I need code to describe the type of code I want. I honestly
thought I had to come up with a number that wouldn't be smaller in bytes
than whatever I'm storing in a string.
Good plan.
Post by fred flintstone
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int version;
int c;
I recommend defining your variables when you are ready to initialise and
use them, rather than putting them all at the start of the function.
It's a style choice, but C has allowed mixed statements and declarations
for nearly 20 years even though some people like old habits.
Post by fred flintstone
FILE *fptr, *gptr;
const char *executable1 = "arrow";
const char *executable2 = "mahershala";
const char *base = "toolchain";
const char *ext = "sh";
These look fine, and are a perfectly good way to express constant
strings in a safe way.

You might also consider using:

const char * const executable1 = "arrow";

The first "const" tells the compiler that you will never modify the
characters pointed at by "executable1", while the second "const" tells
the compiler you will never modify the pointer itself.
Post by fred flintstone
fptr = fopen("toolchain3.sh","r");
if(fptr == NULL)
{
printf("fopen no bueno");
You will probably want "printf("fopen no bueno\n");" - printf does not
add a newline automatically. (Perhaps that's a difference from the
equivalent perl function.)
Post by fred flintstone
exit(1);
}
gptr = fopen("toolchain4.sh","w");
if(gptr == NULL)
{
printf("gopen no bueno");
exit(1);
}
while (1) {
Your indent is wrong here. Consistent indentation makes it far easier
to see what your code is doing.
Post by fred flintstone
c = fgetc(fptr);
if (c == EOF)
break;
else
putc(c, gptr);
}
fclose(fptr);
fclose(gptr);
return 0;
}
I need to concatenate 'toolchain3.sh' from its constituent parts and
then increment it as the filename of gptr.
C is a much poorer language for such things than perl. Any C code for
this is going to be ugly in comparison.

But here is a way to do it:

const char * const base = "toolchain";
const char * const ext = "sh";
int partNo = 3;

// size is +1 for terminating 0,
// and +1 for the maximum number of digits in partNo
char fname[strlen(base) + strlen(ext) + 1 + 1];
snprintf(fname, sizeof fname, "%s%i%s", base, partNo, ext);
FILE * fptr = fopen("toolchain3.sh","r");

partNo++;
snprintf(fname, sizeof fname, "%s%i%s", base, partNo, ext);
FILE * gptr = fopen("toolchain4.sh","w");


You can make your "fname" array bigger if you want - especially if
"partNo" can have more than one digit. If you don't know the size of
partNo, you might want to check it and give an error if it exceeds the
bounds you have set.

But by using snprintf with a limit of "sizeof fname" for the buffer
size, you will not get any overflows. The worst that could happen is
that the filename will be truncated.


It is the nature of C strings that you first allocate a buffer of a
given size, then you fit the string into it. You can check the output
of snprintf (which returns the number of characters that the string
wants to have) to see if your buffer was big enough.
Post by fred flintstone
This lacks the logic for a substitution but sets the stage for it. In
the newly-created .sh file, executable2 shall be substituted for
echo 'after preprocessor your program is' >text3.txt
gcc -E arrow.c >>text3.txt
echo 'after compilation avec warnings, output is' >>text3.txt
gcc -Wall -Wextra -o arrow arrow.c >>text3.txt
./arrow >>text3.txt
echo 'source listing is' >>text3.txt
cat arrow.c >>text3.txt
Also, I need a way of determining the natural number that follows
'text'. This is to be substituted by the number appending 'toolchain',
so that the new number is uniform.
I'll let others answer that one.
Post by fred flintstone
Alright, I hope I am clearer now.
Indeed, your C question was a great deal clearer, and I hope I've been
able to help with it.
Post by fred flintstone
The BYU cougars did beat undefeated
Gonzaga in college hoops.
I've figured out that BYU is a university of some sort. So "BYU
cougars" is either animals from your zoology department, the older women
in your class, or some sort of sports team. I'm hoping it is the last
option!

I'm guessing that "Gonzaga" is another college, or another team of some
sort. And "college hoops" would have to be a game or sports competition?
Post by fred flintstone
It was a news event and this is a newsgroup,
It is a /C/ newsgroup, not a sports channel.
Post by fred flintstone
where we do a lot of talking about C. It's also basketball season.
Ah, basketball.

You do know that in most of the world, it's just something that kids
play for fun - not a serious sport, or something with a "season"? And
this is an international newsgroup, not an American one. In most of the
world, when one school team beats another school team, the only people
interested are the people at the school and their parents. Also, given
that this is a /C/ programming newsgroup, I suspect that people here are
a good deal less interested in sports than the average person regardless
of their country.
Post by fred flintstone
How important are substitutions, especially when they are errant?
Substitutions? Are you talking about variable substitutions in
programming, or as a sporting term?
Post by fred flintstone
Did
you watch the Oscars?
No. I like a good movie, but am totally uninterested in prize
ceremonies. (I fully appreciate that Hollywood wants to celebrate its
best films and people like this - and if it motivates them to make
better films, then great.)

Also, it was during the middle of the night for me.
James Kuyper
2017-02-27 14:27:02 UTC
Reply
Permalink
Raw Message
On 02/27/2017 08:46 AM, David Brown wrote:
...
... For that matter, it is ridiculous to assume that
anyone would know what BYU stands for (some university somewhere, as far
as I can see).
It's not quite as ridiculous as it seems (though it is still
ridiculous). BYU (Brigham Young University in Utah) is fairly well known
here in the US. It's understandable that a BYU student might
overestimate how well-known it is in the rest of the world.
GOTHIER Nathan
2017-02-27 14:28:20 UTC
Reply
Permalink
Raw Message
On Mon, 27 Feb 2017 09:27:02 -0500
Post by James Kuyper
It's not quite as ridiculous as it seems (though it is still
ridiculous). BYU (Brigham Young University in Utah) is fairly well known
here in the US. It's understandable that a BYU student might
overestimate how well-known it is in the rest of the world.
The US are not the center of the universe. There is life outside US...
James Kuyper
2017-02-27 14:38:32 UTC
Reply
Permalink
Raw Message
Post by GOTHIER Nathan
On Mon, 27 Feb 2017 09:27:02 -0500
Post by James Kuyper
It's not quite as ridiculous as it seems (though it is still
ridiculous). BYU (Brigham Young University in Utah) is fairly well known
here in the US. It's understandable that a BYU student might
overestimate how well-known it is in the rest of the world.
The US are not the center of the universe. There is life outside US...
<sarcasm> No kidding? When I wrote about "the rest of world", I thought
I was talking about a fictional location! Amazing! </sarcasm>

I wrote nothing to justify receiving such a rebuke.
David Brown
2017-02-27 14:44:49 UTC
Reply
Permalink
Raw Message
Post by James Kuyper
...
... For that matter, it is ridiculous to assume that
anyone would know what BYU stands for (some university somewhere, as far
as I can see).
It's not quite as ridiculous as it seems (though it is still
ridiculous). BYU (Brigham Young University in Utah) is fairly well known
here in the US. It's understandable that a BYU student might
overestimate how well-known it is in the rest of the world.
I'll accept your word for that - I am certainly no expert in how
well-known it might be in the USA!

I believe I might have heard of Brigham Young University - is that the
one tied to the Mormons? I can't think of /why/ I might have heard of
it - I will give it the benefit of the doubt, and assume I have read of
some scientific or technical breakthrough from there.

Few universities are well enough known by their initials that you could
reasonably refer to them without further explanation - MIT and UCLA are
a couple that spring to mind. Would you know what I was referring to by
OU? I am sure that "Oxford University" would need no further introduction.

However, I expect that when I were a lad, long ago at university, I also
thought the whole world knew what OUCL was...
James Kuyper
2017-02-27 15:36:17 UTC
Reply
Permalink
Raw Message
On 02/27/2017 09:44 AM, David Brown wrote:
...
Post by David Brown
I believe I might have heard of Brigham Young University - is that the
one tied to the Mormons?
Correct - Brigham Young was one of the most famous Mormon leaders, and
BYU is run by the Mormon church.
Post by David Brown
Few universities are well enough known by their initials that you could
reasonably refer to them without further explanation - MIT and UCLA are
a couple that spring to mind. Would you know what I was referring to by
OU? I am sure that "Oxford University" would need no further introduction.
However, I expect that when I were a lad, long ago at university, I also
thought the whole world knew what OUCL was...
Though Caltech is world famous, it's famous mostly among scientists, and
I would not automatically expect it to be recognized by CIT even within
that community. CIT has many alternative meanings, including 8 different
educational institutions.
Outside that community, even the full name is not sufficient - I've
known people (including some residents of Los Angeles!) who confused
California Institute of Technology with California Polytechnic State
University, which my brother attended, or California State Polytechnic
University, which my first girlfriend attend, both of which are also
known as Cal Poly.
I've met several people who thought I was referring to cosmetology when
I mentioned that I was studying cosmology.
Anglican
2017-02-27 15:50:55 UTC
Reply
Permalink
Raw Message
Post by David Brown
Few universities are well enough known by their initials that you could
reasonably refer to them without further explanation - MIT and UCLA are
a couple that spring to mind. Would you know what I was referring to by
OU? I am sure that "Oxford University" would need no further introduction.
When I saw OU I thought Open University, does Oxford use that also?

H
David Brown
2017-02-27 16:13:50 UTC
Reply
Permalink
Raw Message
Post by Anglican
Post by David Brown
Few universities are well enough known by their initials that you could
reasonably refer to them without further explanation - MIT and UCLA are
a couple that spring to mind. Would you know what I was referring to by
OU? I am sure that "Oxford University" would need no further
introduction.
When I saw OU I thought Open University, does Oxford use that also?
There are many universities that can be abbreviated to OU, and I expect
most will use the abbreviation when the context is obvious.

Despite having gone to Oxford, I also associate OU primarily with the
Open University. But I don't think it is as well-known outside the UK
as Oxford is.

(UK here being the United Kingdom, rather than the University of
Kentucky :-) )
Malcolm McLean
2017-02-28 00:30:50 UTC
Reply
Permalink
Raw Message
Post by Anglican
Post by David Brown
Few universities are well enough known by their initials that you could
reasonably refer to them without further explanation - MIT and UCLA are
a couple that spring to mind. Would you know what I was referring to by
OU? I am sure that "Oxford University" would need no further introduction.
When I saw OU I thought Open University, does Oxford use that also?
No, but OUCA ("owkah") is Oxford University Conservative Association, for
example. But "Oxford University" or "The University of Oxford" is usually
just "Oxford" outside of Oxford and "the university" within. I don't
think there's an official name and if there is it's recent and the
university far predates it.
Stefan Ram
2017-02-27 15:03:50 UTC
Reply
Permalink
Raw Message
Post by James Kuyper
It's not quite as ridiculous as it seems (though it is still
ridiculous). BYU (Brigham Young University in Utah) is fairly well known
here in the US. It's understandable that a BYU student might
overestimate how well-known it is in the rest of the world.
I just read, IIRC, in a German newsgroup that an
anesthesiologist refused to anesthetize a patient
after he has seen a slip relating to this patient
from the previous doctor with a four-letter
abbreviation that was unknown to the anesthesiologist
and an exclamation mark.

So, the relation to C programming: one should not
call a variable XBCU, just because one believes
the next programmer will know what this means!
fir
2017-02-27 15:08:09 UTC
Reply
Permalink
Raw Message
Post by James Kuyper
...
... For that matter, it is ridiculous to assume that
anyone would know what BYU stands for (some university somewhere, as far
as I can see).
It's not quite as ridiculous as it seems (though it is still
ridiculous). BYU (Brigham Young University in Utah) is fairly well known
here in the US. It's understandable that a BYU student might
overestimate how well-known it is in the rest of the world.
i versy slightly know what is utah
not to say what is BYU

many my friends for example im sure totally dont know what is c, im sure if i ask them they would say "c? first heard, what is that?"
fir
2017-02-27 15:20:38 UTC
Reply
Permalink
Raw Message
Post by fir
Post by James Kuyper
...
... For that matter, it is ridiculous to assume that
anyone would know what BYU stands for (some university somewhere, as far
as I can see).
It's not quite as ridiculous as it seems (though it is still
ridiculous). BYU (Brigham Young University in Utah) is fairly well known
here in the US. It's understandable that a BYU student might
overestimate how well-known it is in the rest of the world.
i versy slightly know what is utah
not to say what is BYU
well if thinking the one thing i know
about utah is famous utah teapot
Post by fir
many my friends for example im sure totally dont know what is c, im sure if i ask them they would say "c? first heard, what is that?"
in reality they would not say thet coz they dont talk english ;c in reality
it would be more like negative head shaking and goin to other things - they seem not to be interested in c (all know what is windows though for example)

this is somewhat interesting as when i say "i am not 'computer specialist'/'computer man', my main domain of work is c language" (sometimes i talk im a programmer but even programmer is to wide) they totally dont know what im takin about

[more strange interestingly many programmers probably dont know what
is c, they seem to know so many on c as on algol prolog or cobol ]
fir
2017-02-27 15:24:04 UTC
Reply
Permalink
Raw Message
Post by fir
is c, they seem to know so many on c as on algol prolog or cobol ]
errata:
*as I know on algol prolog or cobol
Manfred
2017-02-27 15:00:41 UTC
Reply
Permalink
Raw Message
Post by David Brown
Also, given
that this is a /C/ programming newsgroup, I suspect that people here are
a good deal less interested in sports than the average person regardless
of their country.
Your suspicion might be somewhat overdone, here.
AFAICT C programming in quite compatible with sports interest (not
necessarily with US sports only, though)
Keith Thompson
2017-02-27 17:22:25 UTC
Reply
Permalink
Raw Message
[...]
Post by David Brown
Post by fred flintstone
if(fptr == NULL)
{
printf("fopen no bueno");
You will probably want "printf("fopen no bueno\n");" - printf does not
add a newline automatically. (Perhaps that's a difference from the
equivalent perl function.)
No, Perl's printf works like C's. But the above would be even better
written as:

fprintf(stderr, "fopen no bueno\n");

(I might use fputs(), which doesn't require a format string, but there's
something to be said for using the *printf functions consistently.)
Post by David Brown
Post by fred flintstone
exit(1);
exit(EXIT_FAILURE) is clearer and more portable.

[...]
Post by David Brown
But by using snprintf with a limit of "sizeof fname" for the buffer
size, you will not get any overflows. The worst that could happen is
that the filename will be truncated.
Truncating the file name might be an unacceptable error. snprintf()
with a limit on the size of the target array avoids overflowing
the array, but it doesn't avoid problems caused by the fact that
you have an incorrect file name.

If you need to construct a file name from substrings, allocate
enough memory to hold the entire file name. If you can't allocate
the memory, it's usually best to give up rather than creating
a file with a shortened name. (If you're that short on memory,
you're likely to run into other problems very quickly.)

snprintf(NULL, 0, format_string, ...) is a good way to determine how
much memory you're going to need. (asprintf() is a non-standard
GNU extension that malloc()s and initializes a chunk of memory to
hold the result.)

[...]
--
Keith Thompson (The_Other_Keith) kst-***@mib.org <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
David Brown
2017-02-27 18:11:35 UTC
Reply
Permalink
Raw Message
Post by Keith Thompson
[...]
Post by David Brown
Post by fred flintstone
if(fptr == NULL)
{
printf("fopen no bueno");
You will probably want "printf("fopen no bueno\n");" - printf does not
add a newline automatically. (Perhaps that's a difference from the
equivalent perl function.)
No, Perl's printf works like C's.
OK. I am not very familiar with Perl.
Post by Keith Thompson
But the above would be even better
fprintf(stderr, "fopen no bueno\n");
(I might use fputs(), which doesn't require a format string, but there's
something to be said for using the *printf functions consistently.)
gcc will turn something like that into fputs anyway - you can use
*printf functions consistently and still get the most efficient code.
(Not that optimal efficiency is particularly important for such error
handling.)
Post by Keith Thompson
Post by David Brown
Post by fred flintstone
exit(1);
exit(EXIT_FAILURE) is clearer and more portable.
[...]
Post by David Brown
But by using snprintf with a limit of "sizeof fname" for the buffer
size, you will not get any overflows. The worst that could happen is
that the filename will be truncated.
Truncating the file name might be an unacceptable error. snprintf()
with a limit on the size of the target array avoids overflowing
the array, but it doesn't avoid problems caused by the fact that
you have an incorrect file name.
Yes, it is up to the coder to decide what is important with error
handling. Truncation is "safe" in the sense of not having any undefined
behaviours or overruns, but as has been noted, "safe" depends on the
purpose and the application.
Post by Keith Thompson
If you need to construct a file name from substrings, allocate
enough memory to hold the entire file name. If you can't allocate
the memory, it's usually best to give up rather than creating
a file with a shortened name. (If you're that short on memory,
you're likely to run into other problems very quickly.)
snprintf(NULL, 0, format_string, ...) is a good way to determine how
much memory you're going to need. (asprintf() is a non-standard
GNU extension that malloc()s and initializes a chunk of memory to
hold the result.)
[...]
John Bode
2017-02-28 23:41:06 UTC
Reply
Permalink
Raw Message
Post by fred flintstone
Post by David Brown
I cannot fathom what you are trying to say or do here. I know fine what
the commands above do, but don't understand why - nor does "3DBESNUB
type things" or "gonzaga-beating cougar" make any sense.
In C, strings are between double quotes, not single quotes (they are for
character literals). Writing something like
const char *s = "Arrow";
is perfectly safe.
If you have a C question to ask, feel free and many people here will try
to answer it. But please, make it comprehensible and say what you are
actually trying to do - it makes it a lot easier to help. Perhaps give
an example of the code you are trying to write, and then say where you
are having trouble.
As James Kuyper correctly links downthread, 3DBESNUB was the
problem-solving acronym that my entire cohort at BYU had to use to get
full credit on any physics problem. The first three letters are for
diagrams, but they are in short supply in usenet.
It seems I need code to describe the type of code I want. I honestly
thought I had to come up with a number that wouldn't be smaller in bytes
than whatever I'm storing in a string.
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int version;
int c;
FILE *fptr, *gptr;
const char *executable1 = "arrow";
const char *executable2 = "mahershala";
const char *base = "toolchain";
const char *ext = "sh";
fptr = fopen("toolchain3.sh","r");
if(fptr == NULL)
{
printf("fopen no bueno");
exit(1);
}
gptr = fopen("toolchain4.sh","w");
if(gptr == NULL)
{
printf("gopen no bueno");
exit(1);
}
while (1) {
c = fgetc(fptr);
if (c == EOF)
break;
else
putc(c, gptr);
}
fclose(fptr);
fclose(gptr);
return 0;
}
I need to concatenate 'toolchain3.sh' from its constituent parts and
then increment it as the filename of gptr.
This lacks the logic for a substitution but sets the stage for it. In
the newly-created .sh file, executable2 shall be substituted for
echo 'after preprocessor your program is' >text3.txt
gcc -E arrow.c >>text3.txt
echo 'after compilation avec warnings, output is' >>text3.txt
gcc -Wall -Wextra -o arrow arrow.c >>text3.txt
./arrow >>text3.txt
echo 'source listing is' >>text3.txt
cat arrow.c >>text3.txt
Also, I need a way of determining the natural number that follows
'text'. This is to be substituted by the number appending 'toolchain',
so that the new number is uniform.
Alright, I hope I am clearer now.
Not really. I had to read this three times to understand what you want,
which is:

Replace all occurrences of <sym1> in toolchain<N>.sh
with <sym2> and write the result to toolchain<N+1>.sh.

That's the kind of problem statement that most of us are looking for.

So, you need to do the following:

1. Parse input file name to separate out the ordinal from the rest
of the name;
2. Create a new file name with the incremented ordinal;
3. Tokenize the contents of the input file;
4. Write each token as-is to the output file, *unless* it's the
symbol you want to substitute, in which case you write the
substitute symbol.

If you *know* your filename is always going to be of the form
"toolchain<N>.sh", something like this should work:

int ord;
if ( sscanf( inputFileName, "toolchain%d.sh", &ord ) == 1 )
{
sprintf( outputFileName, "toolchain%d.sh", ord + 1 );
}
else
{
fprintf( stderr, "could not parse input file name\n" );
}

By "tokenizing" the input, I just mean breaking it into a sequence of
strings (which is not *really* tokenization, but we're not going to worry
about that right now); that will make it easier to match your target string,
rather than trying to maintain state for every character.

Here's a pass I tossed off the top of my head - it ain't professional-
quality code by *any* stretch of the imagination, but it should give you
some flavor of what you're looking for.

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

/**
* We're using a dynamic, resizable buffer to read strings. If we
* encounter an input string that's longer than the current buffer
* size, attempt to double it.
*/
int expand( char **buf, size_t *bufsize )
{
char *tmp = realloc( *buf, *bufsize * 2 );
if ( tmp )
{
*bufsize *= 2;
*buf = tmp;
}
return tmp != NULL;
}

/**
* Read the next token from the input stream. In this program,
* tokens are either sequences of alphanumeric characters, or individual
* non-alphanumeric characters. Both are saved as strings to buf.
*
* For example, the input ">>text3.txt" would be tokenized as ">", ">",
* "text3", ".", "txt".
*/
int getNextSym( FILE *stream, char **buf, size_t *bufsize )
{
size_t charsRead = 0;
int c;

while ( ( c = fgetc( stream ) ) != EOF )
{
if ( !isalpha( c ) && !isdigit( c ) )
{
if ( charsRead > 0 )
{
/**
* If we've read a sequence of alphanumeric characters,
* we *don't* want this non-alphanumeric character to be
* part of the string (IOW, we treat all non-alphanumerics
* as string delimiters). Push the current character back
* on to the input stream, terminate the buffer, and return.
*/
ungetc( c, stream );
(*buf)[charsRead] = 0;
return 1;
}
else
{
/**
* All non-alphanumeric characters are returned in their own
* 1-character strings.
*/
(*buf)[0] = c;
(*buf)[1] = 0;
return 1;
}
}
else
{
/**
* Current character is alphanumeric, so we want to
* append it to the buffer, extending the buffer if
* necessary.
*/
if ( charsRead < *bufsize || expand( buf, bufsize ) )
{
(*buf)[charsRead++] = c;
}
else if ( charsRead == *bufsize )
{
/**
* Buffer expansion failed; push the latest character back on
* to the input stream, terminate the buffer, and return a failure
* code. It's up to the caller to decide what to do next.
*/
ungetc( c, stream );
(*buf)[charsRead-1] = 0;
return 0;
}
}
}
if ( charsRead > 0 )
{
/**
* We hit EOF while reading an alphanumeric sequence; terminate
* the buffer.
*/
(*buf)[charsRead] = 0;
return 1;
}

return 0;
}

/**
* Parse the sequence number out of the file name. This assumes the
* file name is of the form "toolchain<N>.sh".
*/
int getOrdinal( const char *filename )
{
int ord;
if ( sscanf( filename, "toolchain%d.sh", &ord ) == 1 )
return ord;

return -1;
}

int main( int argc, char **argv )
{
// arg1 = filename
// arg2 = symbol to replace
// arg3 = replacement symbol

if ( argc < 4 )
{
fprintf( stderr, "USAGE: %s toolchain<N>.sh <search-sym> <replace-sym>\n", argv[0] );
exit( EXIT_FAILURE );
}

char *filename = argv[1];
char *sym1 = argv[2];
char *sym2 = argv[3];

int ordinal = getOrdinal( filename );
if ( ordinal < 0 )
{
fprintf( stderr, "could not parse out ordinal from %s\n", filename );
exit( EXIT_FAILURE );
}

/**
* 32-bit integer is ~10 decimal digits, round up to 11, add 1 for the
* 0 terminator. You'll obviously want to change that for 64-bit int.
*/
char ofilename[ sizeof "toolchain" + sizeof ".sh" + 12 ];
if ( !sprintf( ofilename, "toolchain%d.sh", ordinal + 1 ) )
{
fprintf( stderr, "problem while building output file name toolchain%d.sh", ordinal + 1 );
exit( EXIT_FAILURE );
}

FILE *input = fopen( filename, "r" );
if ( !input )
{
fprintf( stderr, "could not open %s\n", filename );
exit( EXIT_FAILURE );
}

FILE *output = fopen( ofilename, "w" );
if ( !output )
{
fprintf( stderr, "could not create %s\n", ofilename );
exit( EXIT_FAILURE );
}

size_t bufsize = 80; // initial buffer size
char *buffer = malloc( bufsize );

/**
* Meat of the program - read the next symbol from the input file.
* If it matches our search symbol, write the replacement symbol
* to the output file - otherwise, copy the input symbol to the
* output file.
while ( getNextSym( input, &buffer, &bufsize ) )
{
if ( strcmp( buffer, sym1 ) == 0 )
fprintf( output, "%s", sym2 );
else
fprintf( output, "%s", buffer );
}

free( buffer );
fclose( input );
fclose( output );

return 0;
}
Post by fred flintstone
echo 'after preprocessor your program is' >text3.txt
gcc -E arrow.c >>text3.txt
echo 'after compilation avec warnings, output is ' >>text3.txt
gcc -Wall -Wextra -o arrow arrow.c >>text3.txt
./arrow >>text3.txt
echo 'source listing is ' >> text3.txt
cat arrow.c >>text3.txt
echo 'after preprocessor your program is' >text3.txt
gcc -E mahershela.c >>text3.txt
echo 'after compilation avec warnings, output is ' >>text3.txt
gcc -Wall -Wextra -o mahershela mahershela.c >>text3.txt
./mahershela >>text3.txt
echo 'source listing is ' >> text3.txt
cat mahershela.c >>text3.txt
Is that what you're going for?

Of course, the *right* answer is to use a language that makes this easy,
like sed, awk, Perl =twitch=, whatever.
Post by fred flintstone
The BYU cougars did beat undefeated
Gonzaga in college hoops. It was a news event and this is a newsgroup,
where we do a lot of talking about C. It's also basketball season.
That's...not how this works.
Post by fred flintstone
How important are substitutions, especially when they are errant?
If the code isn't doing what you want, that's generally a bad thing.
fred flintstone
2017-03-02 09:25:36 UTC
Reply
Permalink
Raw Message
On 02/28/2017 03:41 PM, John Bode wrote:

[OP reproduces respondent's source with only the addition of closing a
comment in main]
[hence big snip]

Thank you, john, for taking the time to write this. I'm happy with the
output and must say that this counts as getting around the bases. Maybe
I haven't been inclusive in sports talk to describe the problem space. I
could try to put it in cricket terms:

I squiffed one into the crease and got on the stump. Then, with your
turn as batman, you got us though all the wickets, and the score shall
reflect the maidens over-bowled.

If there's anyone who has a problem with my english on threads where I'm
OP, I need you to jump in a Loch. I won't take your killfiling me
personally in the slightest.

Are games important to C? They must be if John van Neumann is to be
believed. , I won't apologize for talking about them in what appears to
be a forum about logic as per the marquis.

Now, this is a nice result. It shows yet another way to make a string.
It's well documented and readable by the likes of me. I hope bode
doesn't mind that I used his name to drive the process:

$ cat bode1.sh
echo 'after preprocessor your program is' >text1.txt
gcc -E bode1.c >>text1.txt
echo 'after compilation avec warnings, output is' >>text1.txt
gcc -Wall -Wextra -o bode1 bode1.c >>text1.txt
./bode1 toolchain3.sh arrow mahershala>>text1.txt
echo 'source listing is' >>text1.txt
cat bode1.c >>text1.txt


$

If you do mind being associated with either me or this source, I now
have the software tools such as to change that in short time. This is
good enough that I want to put it on my C stuff with github. Since you
wrote it from scratch, it's my custom to offer to attribute. As this is
also a place where anonymity is valued and preserved, I could call it
jehosophat as well.

I did make a super-duper minor change to your source; maybe you might
take a final look at it before it goes out where applications ask for
packages. This is a capability I don't want to be without henceforth.

The proof is in the pudding:

$ cat toolchain4.sh
echo 'after preprocessor your program is' >text3.txt
gcc -E mahershala.c >>text3.txt
echo 'after compilation avec warnings, output is' >>text3.txt
gcc -Wall -Wextra -o mahershala mahershala.c >>text3.txt
./mahershala >>text3.txt
echo 'source listing is' >>text3.txt
cat mahershala.c >>text3.txt

$

Here we have file creation exactly as I laid out. The final part of the
output is the source listing:


# 11 "bode1.c"
int expand( char **buf, size_t *bufsize )
{
char *tmp = realloc( *buf, *bufsize * 2 );
if ( tmp )
{
*bufsize *= 2;
*buf = tmp;
}
return tmp !=
# 19 "bode1.c" 3 4
((void *)0)
# 19 "bode1.c"
;
}
# 30 "bode1.c"
int getNextSym( FILE *stream, char **buf, size_t *bufsize )
{
size_t charsRead = 0;
int c;

while ( ( c = fgetc( stream ) ) !=
# 35 "bode1.c" 3 4
(-1)
# 35 "bode1.c"
)
{
if ( !
# 37 "bode1.c" 3 4
((*__ctype_b_loc ())[(int) ((
# 37 "bode1.c"
c
# 37 "bode1.c" 3 4
))] & (unsigned short int) _ISalpha)
# 37 "bode1.c"
&& !
# 37 "bode1.c" 3 4
((*__ctype_b_loc ())[(int) ((
# 37 "bode1.c"
c
# 37 "bode1.c" 3 4
))] & (unsigned short int) _ISdigit)
# 37 "bode1.c"
)
{
if ( charsRead > 0 )
{







ungetc( c, stream );
(*buf)[charsRead] = 0;
return 1;
}
else
{




(*buf)[0] = c;
(*buf)[1] = 0;
return 1;
}
}
else
{





if ( charsRead < *bufsize || expand( buf, bufsize ) )
{
(*buf)[charsRead++] = c;
}
else if ( charsRead == *bufsize )
{





ungetc( c, stream );
(*buf)[charsRead-1] = 0;
return 0;
}
}
}
if ( charsRead > 0 )
{




(*buf)[charsRead] = 0;
return 1;
}

return 0;
}





int getOrdinal( const char *filename )
{
int ord;
if ( sscanf( filename, "toolchain%d.sh", &ord ) == 1 )
return ord;

return -1;
}

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




if ( argc < 4 )
{
fprintf(
# 121 "bode1.c" 3 4
stderr
# 121 "bode1.c"
, "USAGE: %s toolchain<N>.sh <search-sym>
<replace-sym>\n", argv[0] );
exit(
# 122 "bode1.c" 3 4
1
# 122 "bode1.c"
);
}

char *filename = argv[1];
char *sym1 = argv[2];
char *sym2 = argv[3];

int ordinal = getOrdinal( filename );
if ( ordinal < 0 )
{
fprintf(
# 132 "bode1.c" 3 4
stderr
# 132 "bode1.c"
, "could not parse out ordinal from %s\n", filename );
exit(
# 133 "bode1.c" 3 4
1
# 133 "bode1.c"
);
}





char ofilename[ sizeof "toolchain" + sizeof ".sh" + 12 ];
if ( !sprintf( ofilename, "toolchain%d.sh", ordinal + 1 ) )
{
fprintf(
# 143 "bode1.c" 3 4
stderr
# 143 "bode1.c"
, "problem while building output file name
toolchain%d.sh", ordinal + 1 );
exit(
# 144 "bode1.c" 3 4
1
# 144 "bode1.c"
);
}

FILE *input = fopen( filename, "r" );
if ( !input )
{
fprintf(
# 150 "bode1.c" 3 4
stderr
# 150 "bode1.c"
, "could not open %s\n", filename );
exit(
# 151 "bode1.c" 3 4
1
# 151 "bode1.c"
);
}

FILE *output = fopen( ofilename, "w" );
if ( !output )
{
fprintf(
# 157 "bode1.c" 3 4
stderr
# 157 "bode1.c"
, "could not create %s\n", ofilename );
exit(
# 158 "bode1.c" 3 4
1
# 158 "bode1.c"
);
}

size_t bufsize = 80;
char *buffer = malloc( bufsize );






while ( getNextSym( input, &buffer, &bufsize ) )
{
if ( strcmp( buffer, sym1 ) == 0 )
fprintf( output, "%s", sym2 );
else
fprintf( output, "%s", buffer );
}

free( buffer );
fclose( input );
fclose( output );

return 0;
}
after compilation avec warnings, output is
source listing is
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>

/**
* We're using a dynamic, resizable buffer to read strings. If we
* encounter an input string that's longer than the current buffer
* size, attempt to double it.
*/
int expand( char **buf, size_t *bufsize )
{
char *tmp = realloc( *buf, *bufsize * 2 );
if ( tmp )
{
*bufsize *= 2;
*buf = tmp;
}
return tmp != NULL;
}

/**
* Read the next token from the input stream. In this program,
* tokens are either sequences of alphanumeric characters, or individual
* non-alphanumeric characters. Both are saved as strings to buf.
*
* For example, the input ">>text3.txt" would be tokenized as ">", ">",
* "text3", ".", "txt".
*/
int getNextSym( FILE *stream, char **buf, size_t *bufsize )
{
size_t charsRead = 0;
int c;

while ( ( c = fgetc( stream ) ) != EOF )
{
if ( !isalpha( c ) && !isdigit( c ) )
{
if ( charsRead > 0 )
{
/**
* If we've read a sequence of alphanumeric characters,
* we *don't* want this non-alphanumeric character to be
* part of the string (IOW, we treat all non-alphanumerics
* as string delimiters). Push the current character back
* on to the input stream, terminate the buffer, and return.
*/
ungetc( c, stream );
(*buf)[charsRead] = 0;
return 1;
}
else
{
/**
* All non-alphanumeric characters are returned in their own
* 1-character strings.
*/
(*buf)[0] = c;
(*buf)[1] = 0;
return 1;
}
}
else
{
/**
* Current character is alphanumeric, so we want to
* append it to the buffer, extending the buffer if
* necessary.
*/
if ( charsRead < *bufsize || expand( buf, bufsize ) )
{
(*buf)[charsRead++] = c;
}
else if ( charsRead == *bufsize )
{
/**
* Buffer expansion failed; push the latest character back on
* to the input stream, terminate the buffer, and return a failure
* code. It's up to the caller to decide what to do next.
*/
ungetc( c, stream );
(*buf)[charsRead-1] = 0;
return 0;
}
}
}
if ( charsRead > 0 )
{
/**
* We hit EOF while reading an alphanumeric sequence; terminate
* the buffer.
*/
(*buf)[charsRead] = 0;
return 1;
}

return 0;
}

/**
* Parse the sequence number out of the file name. This assumes the
* file name is of the form "toolchain<N>.sh".
*/
int getOrdinal( const char *filename )
{
int ord;
if ( sscanf( filename, "toolchain%d.sh", &ord ) == 1 )
return ord;

return -1;
}

int main( int argc, char **argv )
{
// arg1 = filename
// arg2 = symbol to replace
// arg3 = replacement symbol

if ( argc < 4 )
{
fprintf( stderr, "USAGE: %s toolchain<N>.sh <search-sym>
<replace-sym>\n", argv[0] );
exit( EXIT_FAILURE );
}

char *filename = argv[1];
char *sym1 = argv[2];
char *sym2 = argv[3];

int ordinal = getOrdinal( filename );
if ( ordinal < 0 )
{
fprintf( stderr, "could not parse out ordinal from %s\n", filename );
exit( EXIT_FAILURE );
}

/**
* 32-bit integer is ~10 decimal digits, round up to 11, add 1 for the
* 0 terminator. You'll obviously want to change that for 64-bit int.
*/
char ofilename[ sizeof "toolchain" + sizeof ".sh" + 12 ];
if ( !sprintf( ofilename, "toolchain%d.sh", ordinal + 1 ) )
{
fprintf( stderr, "problem while building output file name
toolchain%d.sh", ordinal + 1 );
exit( EXIT_FAILURE );
}

FILE *input = fopen( filename, "r" );
if ( !input )
{
fprintf( stderr, "could not open %s\n", filename );
exit( EXIT_FAILURE );
}

FILE *output = fopen( ofilename, "w" );
if ( !output )
{
fprintf( stderr, "could not create %s\n", ofilename );
exit( EXIT_FAILURE );
}

size_t bufsize = 80; // initial buffer size
char *buffer = malloc( bufsize );

/**
* Meat of the program - read the next symbol from the input file.
* If it matches our search symbol, write the replacement symbol
* to the output file - otherwise, copy the input symbol to the
* output file. **/
while ( getNextSym( input, &buffer, &bufsize ) )
{
if ( strcmp( buffer, sym1 ) == 0 )
fprintf( output, "%s", sym2 );
else
fprintf( output, "%s", buffer );
}

free( buffer );
fclose( input );
fclose( output );

return 0;
}


We seem to have ended up with malloc for the business end of it. I
haven't worked through the logic of getNextSym yet, but there's not a
lot with the way he's got the problem broken up.

Anyways, thanks all for constructive responses,
--
fred
David Brown
2017-03-02 10:28:22 UTC
Reply
Permalink
Raw Message
Post by fred flintstone
[OP reproduces respondent's source with only the addition of closing a
comment in main]
[hence big snip]
Thank you, john, for taking the time to write this. I'm happy with the
output and must say that this counts as getting around the bases. Maybe
I haven't been inclusive in sports talk to describe the problem space. I
I squiffed one into the crease and got on the stump. Then, with your
turn as batman, you got us though all the wickets, and the score shall
reflect the maidens over-bowled.
If there's anyone who has a problem with my english on threads where I'm
OP, I need you to jump in a Loch. I won't take your killfiling me
personally in the slightest.
Are games important to C? They must be if John van Neumann is to be
believed. , I won't apologize for talking about them in what appears to
be a forum about logic as per the marquis.
Game theory, which John /von/ Neumann (he was Hungarian, not Dutch)
worked on, has no relation whatsoever to sports. It also has no
relation to C.
Post by fred flintstone
Now, this is a nice result. It shows yet another way to make a string.
It's well documented and readable by the likes of me. I hope bode
Well, you've lost me as a potential helper for C - and I think you have
already alienated a number of others here. Maybe John Bode will help
you again in the future, but maybe your disrespect will chase him away
too. Certainly /I/ would not appreciate be referred to as "brown",
having my name used as a program name, or being treated like a student
drinking buddy.

There is nothing wrong with using analogies if they illustrate a
relevant point, and nothing wrong with using the occasional common
idiom. But your "sports talk" is gibberish - it is meaningless and
annoying, and distracts from what you are trying to say. You have been
asked to stop, and you actively refuse to cooperate and communicate in a
manner that suits the group. Learn that different kinds of language and
different ways of expressing yourself are appropriate in different places.

It is /you/ that looses out from this - not the rest of the group. It
is /you/ who comes looking for help and advice, but will be ignored by
many of the group experts.

I hope you can understand this, and change your attitude somewhat. A
learner asking questions about C is always a positive thing for this
group - a chatty kid who insists on his right to say what he wants, how
he wants, when he wants and where he wants is not a positive thing anywhere.
Ben Bacarisse
2017-03-02 10:54:14 UTC
Reply
Permalink
Raw Message
fred flintstone <***@server.invalid> writes:
<snip>

There's a bug in the code, so I'll mention a couple of other things that
are not very important since I posting about something that does matter.

<snip>
Post by John Bode
/**
* Read the next token from the input stream. In this program,
* tokens are either sequences of alphanumeric characters, or individual
* non-alphanumeric characters. Both are saved as strings to buf.
*
* For example, the input ">>text3.txt" would be tokenized as ">", ">",
* "text3", ".", "txt".
*/
int getNextSym( FILE *stream, char **buf, size_t *bufsize )
I would consider returning the number of characters read here. It's
always a shame to return 0/1 when you have a potentially useful
alternative. You might not need it now, but getNextSym is a potentially
reusable function.
Post by John Bode
{
size_t charsRead = 0;
int c;
while ( ( c = fgetc( stream ) ) != EOF )
{
if ( !isalpha( c ) && !isdigit( c ) )
You can use isalnum here.
Post by John Bode
{
if ( charsRead > 0 )
{
/**
* If we've read a sequence of alphanumeric characters,
* we *don't* want this non-alphanumeric character to be
* part of the string (IOW, we treat all non-alphanumerics
* as string delimiters). Push the current character back
* on to the input stream, terminate the buffer, and return.
*/
ungetc( c, stream );
(*buf)[charsRead] = 0;
return 1;
}
else
{
/**
* All non-alphanumeric characters are returned in their own
* 1-character strings.
*/
(*buf)[0] = c;
(*buf)[1] = 0;
return 1;
}
}
else
{
/**
* Current character is alphanumeric, so we want to
* append it to the buffer, extending the buffer if
* necessary.
*/
if ( charsRead < *bufsize || expand( buf, bufsize ) )
I think you need <= here or you can overflow the buffer when it gets
zero terminated.
Post by John Bode
{
(*buf)[charsRead++] = c;
}
else if ( charsRead == *bufsize )
{
/**
* Buffer expansion failed; push the latest character back on
* to the input stream, terminate the buffer, and return a failure
* code. It's up to the caller to decide what to do next.
*/
ungetc( c, stream );
(*buf)[charsRead-1] = 0;
return 0;
}
}
}
if ( charsRead > 0 )
{
/**
* We hit EOF while reading an alphanumeric sequence; terminate
* the buffer.
*/
(*buf)[charsRead] = 0;
return 1;
}
return 0;
}
/**
* Parse the sequence number out of the file name. This assumes the
* file name is of the form "toolchain<N>.sh".
*/
int getOrdinal( const char *filename )
{
int ord;
if ( sscanf( filename, "toolchain%d.sh", &ord ) == 1 )
I think I'd relax the requirement that it must be "toolchain" but that's
a small matter. You could make the output file have the same pattern as
the input file but with the number incremented.
Post by John Bode
return ord;
return -1;
I like to use a conditional expression in such cases

return sscanf(filename, "toolchain%d.sh", &ord) == 1 ? ord : -1;
Post by John Bode
}
<snip>
Post by John Bode
size_t bufsize = 80; // initial buffer size
char *buffer = malloc( bufsize );
You should really check the buffer != 0 here.

What I do in these cases in to start by setting buffer = 0 and
bufsize = 0 so the first character triggers and expand operation. You
need to make the expand work correctly with a zero size so you can do

new_size = size * 2 + 80;

or

new_size = size ? 80 : size * 2;

but that avoids duplicating allocation code and checks.
Post by John Bode
/**
* Meat of the program - read the next symbol from the input file.
* If it matches our search symbol, write the replacement symbol
* to the output file - otherwise, copy the input symbol to the
* output file. **/
while ( getNextSym( input, &buffer, &bufsize ) )
{
if ( strcmp( buffer, sym1 ) == 0 )
fprintf( output, "%s", sym2 );
else
fprintf( output, "%s", buffer );
}
Again I favour conditional expressions for cases like this:

fputs(strcmp( buffer, sym1 ) == 0 ? sym2 : buffer, output);
Post by John Bode
free( buffer );
fclose( input );
fclose( output );
return 0;
}
<snip>
Only the buffer overrun is really significant.
--
Ben.
Manfred
2017-03-02 14:28:22 UTC
Reply
Permalink
Raw Message
Post by Ben Bacarisse
<snip>
There's a bug in the code, so I'll mention a couple of other things that
are not very important since I posting about something that does matter.
<snip>
Post by Ben Bacarisse
Post by John Bode
{
/**
* Current character is alphanumeric, so we want to
* append it to the buffer, extending the buffer if
* necessary.
*/
if ( charsRead < *bufsize || expand( buf, bufsize ) )
I think you need <= here or you can overflow the buffer when it gets
zero terminated.
Hm. You are right about overflow, but I think the solution should be:
if ( (charsRead+1) < *bufsize || expand( buf, bufsize ) )
Post by Ben Bacarisse
Post by John Bode
{
(*buf)[charsRead++] = c;
}
else if ( charsRead == *bufsize )
{
/**
* Buffer expansion failed; push the latest character back on
* to the input stream, terminate the buffer, and return a failure
* code. It's up to the caller to decide what to do next.
*/
ungetc( c, stream );
(*buf)[charsRead-1] = 0;
return 0;
}
}
}
if ( charsRead > 0 )
{
/**
* We hit EOF while reading an alphanumeric sequence; terminate
* the buffer.
*/
(*buf)[charsRead] = 0;
return 1;
}
return 0;
}
<snip>
Ben Bacarisse
2017-03-02 14:51:39 UTC
Reply
Permalink
Raw Message
Post by Ben Bacarisse
Post by Ben Bacarisse
<snip>
There's a bug in the code, so I'll mention a couple of other things that
are not very important since I posting about something that does matter.
<snip>
Post by Ben Bacarisse
Post by John Bode
{
/**
* Current character is alphanumeric, so we want to
* append it to the buffer, extending the buffer if
* necessary.
*/
if ( charsRead < *bufsize || expand( buf, bufsize ) )
I think you need <= here or you can overflow the buffer when it gets
zero terminated.
if ( (charsRead+1) < *bufsize || expand( buf, bufsize ) )
Yes, thanks, wasn't thinking.

<snip>
--
Ben.
John Bode
2017-03-02 22:18:22 UTC
Reply
Permalink
Raw Message
Post by Ben Bacarisse
<snip>
There's a bug in the code, so I'll mention a couple of other things that
are not very important since I posting about something that does matter.
In my defense, I tossed this off in about 15 minutes without putting too
much thought into it, so I'm not surprised there are problems. Like I
said, this ain't professional-quality code.
Post by Ben Bacarisse
<snip>
Post by John Bode
/**
* Read the next token from the input stream. In this program,
* tokens are either sequences of alphanumeric characters, or individual
* non-alphanumeric characters. Both are saved as strings to buf.
*
* For example, the input ">>text3.txt" would be tokenized as ">", ">",
* "text3", ".", "txt".
*/
int getNextSym( FILE *stream, char **buf, size_t *bufsize )
I would consider returning the number of characters read here. It's
always a shame to return 0/1 when you have a potentially useful
alternative. You might not need it now, but getNextSym is a potentially
reusable function.
Wouldn't that be covered by calling strlen on the target buffer?
Post by Ben Bacarisse
Post by John Bode
{
size_t charsRead = 0;
int c;
while ( ( c = fgetc( stream ) ) != EOF )
{
if ( !isalpha( c ) && !isdigit( c ) )
You can use isalnum here.
Derp. Forgot about that.
Post by Ben Bacarisse
Post by John Bode
{
if ( charsRead > 0 )
{
/**
* If we've read a sequence of alphanumeric characters,
* we *don't* want this non-alphanumeric character to be
* part of the string (IOW, we treat all non-alphanumerics
* as string delimiters). Push the current character back
* on to the input stream, terminate the buffer, and return.
*/
ungetc( c, stream );
(*buf)[charsRead] = 0;
return 1;
}
else
{
/**
* All non-alphanumeric characters are returned in their own
* 1-character strings.
*/
(*buf)[0] = c;
(*buf)[1] = 0;
return 1;
}
}
else
{
/**
* Current character is alphanumeric, so we want to
* append it to the buffer, extending the buffer if
* necessary.
*/
if ( charsRead < *bufsize || expand( buf, bufsize ) )
I think you need <= here or you can overflow the buffer when it gets
zero terminated.
Hmm. Acutally, I think it needs to be "charsRead < *bufsize - 1" (or
"charsRead + 1 < *bufsize"). Oh well.
Post by Ben Bacarisse
Post by John Bode
{
(*buf)[charsRead++] = c;
}
else if ( charsRead == *bufsize )
{
/**
* Buffer expansion failed; push the latest character back on
* to the input stream, terminate the buffer, and return a failure
* code. It's up to the caller to decide what to do next.
*/
ungetc( c, stream );
(*buf)[charsRead-1] = 0;
return 0;
}
}
}
if ( charsRead > 0 )
{
/**
* We hit EOF while reading an alphanumeric sequence; terminate
* the buffer.
*/
(*buf)[charsRead] = 0;
return 1;
}
return 0;
}
/**
* Parse the sequence number out of the file name. This assumes the
* file name is of the form "toolchain<N>.sh".
*/
int getOrdinal( const char *filename )
{
int ord;
if ( sscanf( filename, "toolchain%d.sh", &ord ) == 1 )
I think I'd relax the requirement that it must be "toolchain" but that's
a small matter. You could make the output file have the same pattern as
the input file but with the number incremented.
Yeah, this was an assumption to make things a little easier.
Post by Ben Bacarisse
Post by John Bode
return ord;
return -1;
I like to use a conditional expression in such cases
return sscanf(filename, "toolchain%d.sh", &ord) == 1 ? ord : -1;
Post by John Bode
}
<snip>
Post by John Bode
size_t bufsize = 80; // initial buffer size
char *buffer = malloc( bufsize );
You should really check the buffer != 0 here.
Derp. Agreed.
Post by Ben Bacarisse
What I do in these cases in to start by setting buffer = 0 and
bufsize = 0 so the first character triggers and expand operation. You
need to make the expand work correctly with a zero size so you can do
new_size = size * 2 + 80;
or
new_size = size ? 80 : size * 2;
but that avoids duplicating allocation code and checks.
OTOH, setting the initial buffer size to something that handles most input
cases means you don't have to worry about reallocating most of the time.

Of course, that can lull you into a false sense of security, as it did for
me. Should have tried it with a really small buffer size to begin with.
Post by Ben Bacarisse
Post by John Bode
/**
* Meat of the program - read the next symbol from the input file.
* If it matches our search symbol, write the replacement symbol
* to the output file - otherwise, copy the input symbol to the
* output file. **/
while ( getNextSym( input, &buffer, &bufsize ) )
{
if ( strcmp( buffer, sym1 ) == 0 )
fprintf( output, "%s", sym2 );
else
fprintf( output, "%s", buffer );
}
fputs(strcmp( buffer, sym1 ) == 0 ? sym2 : buffer, output);
Doesn't fputs automatically append a newline?
Post by Ben Bacarisse
Post by John Bode
free( buffer );
fclose( input );
fclose( output );
return 0;
}
<snip>
Only the buffer overrun is really significant.
--
Ben.
Good spots. Again, no real defense other than tossing it off in a few
minutes. And it was less motivated by helping FF and more by avoiding
working on something even more boring.
Ben Bacarisse
2017-03-02 23:55:01 UTC
Reply
Permalink
Raw Message
Post by John Bode
Post by Ben Bacarisse
<snip>
There's a bug in the code, so I'll mention a couple of other things that
are not very important since I posting about something that does matter.
In my defense, I tossed this off in about 15 minutes without putting too
much thought into it, so I'm not surprised there are problems. Like I
said, this ain't professional-quality code.
It's always grim posting code to comp.lang.c since so many eyes see it,
but it's good for the soul and good for the group so thanks.
Post by John Bode
Post by Ben Bacarisse
<snip>
Post by John Bode
/**
* Read the next token from the input stream. In this program,
* tokens are either sequences of alphanumeric characters, or individual
* non-alphanumeric characters. Both are saved as strings to buf.
*
* For example, the input ">>text3.txt" would be tokenized as ">", ">",
* "text3", ".", "txt".
*/
int getNextSym( FILE *stream, char **buf, size_t *bufsize )
I would consider returning the number of characters read here. It's
always a shame to return 0/1 when you have a potentially useful
alternative. You might not need it now, but getNextSym is a potentially
reusable function.
Wouldn't that be covered by calling strlen on the target buffer?
Oh sure, but since this function calculates the length of the token as
it goes, I'd be tempted to return it. 0 still means no token and != 0
still means OK, but the caller can immediately look at tok[len-1] when
that's useful. Not a big deal but I dislike throwing information away.

<snip>
Post by John Bode
Post by Ben Bacarisse
Post by John Bode
if ( charsRead < *bufsize || expand( buf, bufsize ) )
I think you need <= here or you can overflow the buffer when it gets
zero terminated.
Hmm. Acutally, I think it needs to be "charsRead < *bufsize - 1" (or
"charsRead + 1 < *bufsize"). Oh well.
Yes, I didn't think enough about the correction. I think I had a
similar bug recently where the fix was to include equality and I just
trotted that out.

<snip>
Post by John Bode
Post by Ben Bacarisse
What I do in these cases in to start by setting buffer = 0 and
bufsize = 0 so the first character triggers and expand operation. You
need to make the expand work correctly with a zero size so you can do
new_size = size * 2 + 80;
or
new_size = size ? 80 : size * 2;
but that avoids duplicating allocation code and checks.
OTOH, setting the initial buffer size to something that handles most input
cases means you don't have to worry about reallocating most of the time.
I don't get that. You have to allocate at least once no matter how you
do it. My preference is to keep all the allocation in one place. The
cost is either a test or an addition that is not strictly needed on
every allocation.

<snip>
Post by John Bode
Post by Ben Bacarisse
Post by John Bode
if ( strcmp( buffer, sym1 ) == 0 )
fprintf( output, "%s", sym2 );
else
fprintf( output, "%s", buffer );
}
fputs(strcmp( buffer, sym1 ) == 0 ? sym2 : buffer, output);
Doesn't fputs automatically append a newline?
No, that's just puts. I suspect a lot of people are put off using fputs
because of this historical hang-over.

<snip>
--
Ben.
fred flintstone
2017-03-15 01:32:18 UTC
Reply
Permalink
Raw Message
[OP is leaving this quoted material because he didn't read it until
right now and want to leave it as an editing decision]
Post by Ben Bacarisse
Post by John Bode
Post by Ben Bacarisse
There's a bug in the code, so I'll mention a couple of other things that
are not very important since I posting about something that does matter.
In my defense, I tossed this off in about 15 minutes without putting too
much thought into it, so I'm not surprised there are problems. Like I
said, this ain't professional-quality code.
It's always grim posting code to comp.lang.c since so many eyes see it,
but it's good for the soul and good for the group so thanks.
It's OP who is grateful for a decent result when he started into the
question muttering about strings. It follows the development in
_Intermediate Perl_ to do some small thing on github to try to figure it
out. What's more, I'm also looking at _Programmieren in C_ chp 8, which
I've never done because I worked through K&R2 whilst on MS.

https://github.com/TBlazer66/gcc

I have found that if I don't have C, then I don't really have perl, so
it is that I wanted to have a program written in standard C99 to do the
nuts and bolts things that C has to do to be the lower-level syntax of
choice.
Post by Ben Bacarisse
Post by John Bode
Post by Ben Bacarisse
Post by John Bode
/**
* Read the next token from the input stream. In this program,
* tokens are either sequences of alphanumeric characters, or individual
* non-alphanumeric characters. Both are saved as strings to buf.
*
* For example, the input ">>text3.txt" would be tokenized as ">", ">",
* "text3", ".", "txt".
*/
int getNextSym( FILE *stream, char **buf, size_t *bufsize )
I would consider returning the number of characters read here. It's
always a shame to return 0/1 when you have a potentially useful
alternative. You might not need it now, but getNextSym is a potentially
reusable function.
Wouldn't that be covered by calling strlen on the target buffer?
Oh sure, but since this function calculates the length of the token as
it goes, I'd be tempted to return it. 0 still means no token and != 0
still means OK, but the caller can immediately look at tok[len-1] when
that's useful. Not a big deal but I dislike throwing information away.
<snip>
Post by John Bode
Post by Ben Bacarisse
Post by John Bode
if ( charsRead < *bufsize || expand( buf, bufsize ) )
I think you need <= here or you can overflow the buffer when it gets
zero terminated.
Hmm. Acutally, I think it needs to be "charsRead < *bufsize - 1" (or
"charsRead + 1 < *bufsize"). Oh well.
Yes, I didn't think enough about the correction. I think I had a
similar bug recently where the fix was to include equality and I just
trotted that out.
<snip>
Post by John Bode
Post by Ben Bacarisse
What I do in these cases in to start by setting buffer = 0 and
bufsize = 0 so the first character triggers and expand operation. You
need to make the expand work correctly with a zero size so you can do
new_size = size * 2 + 80;
or
new_size = size ? 80 : size * 2;
but that avoids duplicating allocation code and checks.
OTOH, setting the initial buffer size to something that handles most input
cases means you don't have to worry about reallocating most of the time.
I don't get that. You have to allocate at least once no matter how you
do it. My preference is to keep all the allocation in one place. The
cost is either a test or an addition that is not strictly needed on
every allocation.
<snip>
Post by John Bode
Post by Ben Bacarisse
Post by John Bode
if ( strcmp( buffer, sym1 ) == 0 )
fprintf( output, "%s", sym2 );
else
fprintf( output, "%s", buffer );
}
fputs(strcmp( buffer, sym1 ) == 0 ? sym2 : buffer, output);
Doesn't fputs automatically append a newline?
No, that's just puts. I suspect a lot of people are put off using fputs
because of this historical hang-over.
<snip>
My best effort to edit the source from this thread together is sub5.c .
I'll see how this looks on my newly-minted mint partition. That would be
its first port.

--
fred
Tim Rentsch
2017-04-17 14:04:51 UTC
Reply
Permalink
Raw Message
Post by John Bode
[..wanting to write a program to do text substitutions..]
Replace all occurrences of <sym1> in toolchain<N>.sh
with <sym2> and write the result to toolchain<N+1>.sh.
That's the kind of problem statement that most of us are looking for.
1. Parse input file name to separate out the ordinal from the rest
of the name;
2. Create a new file name with the incremented ordinal;
3. Tokenize the contents of the input file;
4. Write each token as-is to the output file, *unless* it's the
symbol you want to substitute, in which case you write the
substitute symbol.
[...]
By "tokenizing" the input, I just mean breaking it into a sequence
of strings (which is not *really* tokenization, but we're not
going to worry about that right now); that will make it easier to
match your target string, rather than trying to maintain state for
every character.
[..example program given..]
For the case under consideration, where the symbols being replaced are
alphanumeric "words" (ie, without adjacent alphanumeric characters on
either side), it seems easier to read in the whole file and just look
for occurrences of the word to be replaced, and in each case check the
ends to see if it should be replaced in that case. At the top level
the code might look like this:


int
main( int argc, char *v[] ){
char *in_name = argc > 3 ? v[1] : 0;
char buffer[ in_name ? strlen( in_name ) + 3 : 1 ];
char *out_name = in_name ? transmogrify( buffer, in_name ) : 0;
FILE *in = out_name ? fopen( in_name, "r" ) : 0;
FILE *out = in ? fopen( out_name, "w" ) : 0;
char *contents = in && out ? space_plus_contents_of( in ) : 0;

if( argc < 4 ) give_usage_message( v[0] );
else if( !out_name ) printf( " name: '%s' - no number found\n", v[1] );
else if( !in ) printf( " input: '%s' - open failed\n", v[1] );
else if( !out ) printf( "output: '%s' - open failed\n", out_name );
else if( !contents ) printf( " input: '%s' - read failure\n", v[1] );
else {
substitute_and_write( contents+1, v[2], v[3], out );
}

free( contents );

return (in && !fclose(in)) & (out && !fclose(out)) ? 0 : EXIT_FAILURE;
}


after which the substitution/writing code might look like this:


void
substitute_and_write( char *contents, char *old, char *new, FILE *out ){
typedef unsigned char UC;
char *p = contents, *q;
Size k = strlen( old );

while( q = strstr( p, old ) ){
int bad = isalnum( (UC){q[-1]} ) || isalnum( (UC){q[k]} );
fprintf( out, "%.*s%s", (int){ q-p + bad*k }, p, bad ? "" : new );
p = q+k;
}
fprintf( out, "%s", p );
}

j***@itu.edu
2017-02-27 21:48:05 UTC
Reply
Permalink
Raw Message
Post by David Brown
I cannot fathom what you are trying to say or do here.
David, I think that the chatbot that is infesting comp.lang.c is becoming increasingly sophisticated. I am marking these posts as spam, I hope that other people will join me.
fred flintstone
2017-02-27 22:16:25 UTC
Reply
Permalink
Raw Message
Post by j***@itu.edu
Post by David Brown
I cannot fathom what you are trying to say or do here.
David, I think that the chatbot that is infesting comp.lang.c is becoming increasingly sophisticated. I am marking these posts as spam, I hope that other people will join me.
Said someone who contributed zero C, all noise.
--
fred
David Brown
2017-02-28 07:47:34 UTC
Reply
Permalink
Raw Message
Post by fred flintstone
Post by j***@itu.edu
Post by David Brown
I cannot fathom what you are trying to say or do here.
David, I think that the chatbot that is infesting comp.lang.c is
becoming increasingly sophisticated. I am marking these posts as
spam, I hope that other people will join me.
Said someone who contributed zero C, all noise.
Fred, be careful about responding to insults with insults, especially
when you are new to a group. jladasky is also not a regular here, but
the other three posts he has made were on topic. It is possible that he
has simply mixed up posters here.
fred flintstone
2017-02-28 09:59:45 UTC
Reply
Permalink
Raw Message
Post by David Brown
Post by fred flintstone
Post by j***@itu.edu
Post by David Brown
I cannot fathom what you are trying to say or do here.
David, I think that the chatbot that is infesting comp.lang.c is
becoming increasingly sophisticated. I am marking these posts as
spam, I hope that other people will join me.
Said someone who contributed zero C, all noise.
Fred, be careful about responding to insults with insults, especially
when you are new to a group. jladasky is also not a regular here, but
the other three posts he has made were on topic. It is possible that he
has simply mixed up posters here.
Look, David, I don't want to lose momentum litigating this. I have to
say that I'm glad to make your acquaintance. Whatever I did post brought
you out of your shell, say what you like.

As to insults, I don't really mind being compared to software, but I
will not be undermined as OP, as that is the way I felt, which is
characteristic of meat machines.

I haven't looked at other threads yet, as it just looks beset by
trolls/spam. If you would like to give me a reasonable recommendation
for a starter killfile for clc, I'd read what you wrote.

I would like to play the Imitation Game, though, because that just
sounds fun. OU in Ohio is in Athens. Yeah, there's an Athens in Ohio,
about to be criminalized by Donald Trump.

Many in my cohort believe in the Jane Principle: that an emerging
cyberintelligence will manifest herself as described in the science
fiction of Mormon author Orson Scott Card. Like 3DBESNUB did in physics,
this influenced a generation of lds lawyers, bankers, assassins, and me,
fred flintstone, unbeliever in hocus pocus, but believer in a coming
singularity. I'd be really impressed if the chatbot did google searches
before saying anything, as do I....
--
fred
David Brown
2017-02-28 10:39:03 UTC
Reply
Permalink
Raw Message
Post by fred flintstone
Post by David Brown
Post by fred flintstone
Post by j***@itu.edu
Post by David Brown
I cannot fathom what you are trying to say or do here.
David, I think that the chatbot that is infesting comp.lang.c is
becoming increasingly sophisticated. I am marking these posts as
spam, I hope that other people will join me.
Said someone who contributed zero C, all noise.
Fred, be careful about responding to insults with insults, especially
when you are new to a group. jladasky is also not a regular here, but
the other three posts he has made were on topic. It is possible that he
has simply mixed up posters here.
Look, David, I don't want to lose momentum litigating this.
"Litigating" ? jladasky's "chatbot" accusation was not justified (as
far as I can see), but there is no need to take it /that/ seriously!
Post by fred flintstone
I have to
say that I'm glad to make your acquaintance.
I am glad to see learners in this newsgroup - helping folks like you is
one of the key reasons for the group.
Post by fred flintstone
Whatever I did post brought
you out of your shell, say what you like.
I must admit, I got a good laugh out of that one. Have you looked at
the number of posts I make? I have recently been accused (by someone I
respect, but in this case respectfully disagree with) of posting merely
because I like the sound of my own voice.
Post by fred flintstone
As to insults, I don't really mind being compared to software, but I
will not be undermined as OP, as that is the way I felt, which is
characteristic of meat machines.
I haven't looked at other threads yet, as it just looks beset by
trolls/spam. If you would like to give me a reasonable recommendation
for a starter killfile for clc, I'd read what you wrote.
The only people I have in my killfile (actually, Thunderbird message
filters) are "Jonas Eklundh", "TickleMe Elmo" and "Steve Carroll" - all
by name, rather than address, since it appears to be some sort of
chatbot that changes sender address regularly. This bot sent a lot of
posts to c.l.c. recently. I don't know if it has stopped, since the
messages (and any sub-threads replying to the bot) are automatically
killed by by newsreader.

Other regulars here have more extensive killfiles - but I encourage you
to make your own decisions about who might be worth listening to.
Post by fred flintstone
I would like to play the Imitation Game, though, because that just
sounds fun. OU in Ohio is in Athens. Yeah, there's an Athens in Ohio,
about to be criminalized by Donald Trump.
Many in my cohort believe in the Jane Principle: that an emerging
cyberintelligence will manifest herself as described in the science
fiction of Mormon author Orson Scott Card. Like 3DBESNUB did in physics,
this influenced a generation of lds lawyers, bankers, assassins, and me,
fred flintstone, unbeliever in hocus pocus, but believer in a coming
singularity. I'd be really impressed if the chatbot did google searches
before saying anything, as do I....
Please, stick to C. Your questions on C made sense and were
interesting. But these last couple of paragraphs are the kind of thing
that are likely to get /you/ killfiled by others.
Richard Heathfield
2017-02-28 12:03:29 UTC
Reply
Permalink
Raw Message
On 28/02/17 09:59, fred flintstone wrote:

<snip>
Post by fred flintstone
I haven't looked at other threads yet, as it just looks beset by
trolls/spam. If you would like to give me a reasonable recommendation
for a starter killfile for clc, I'd read what you wrote.
The obvious candidates are: fir because he writes gibberish and has no
concept of engaging in intelligent discussion; Rick C Hodgin because he
treats the group as a field for evangelism rather than a newsgroup for
C; and BartC because he'd rather whinge than learn and after a while it
gets rather trying.
Post by fred flintstone
I would like to play the Imitation Game, though, because that just
sounds fun. OU in Ohio is in Athens. Yeah, there's an Athens in Ohio,
about to be criminalized by Donald Trump.
Oh, and we can maybe add one more to that list: fred flintstone because
he seems to think that comp.lang.c is interested in random nonsense.
We're not.

But I'll stay my hand unless you continue in that vein.
--
Richard Heathfield
Email: rjh at cpax dot org dot uk
"Usenet is a strange place" - dmr 29 July 1999
Sig line 4 vacant - apply within
BartC
2017-02-28 13:33:26 UTC
Reply
Permalink
Raw Message
Post by Ben Bacarisse
<snip>
Post by fred flintstone
I haven't looked at other threads yet, as it just looks beset by
trolls/spam. If you would like to give me a reasonable recommendation
for a starter killfile for clc, I'd read what you wrote.
The obvious candidates are: fir because he writes gibberish and has no
concept of engaging in intelligent discussion; Rick C Hodgin because he
treats the group as a field for evangelism rather than a newsgroup for
C; and BartC because he'd rather whinge than learn and after a while it
gets rather trying.
Or someone could look at people's posts, and at what they like to come
here to do, and make up their own mind.

Some like to debate technical details, others seem to have an agenda
against specific posters.
--
bartc
David Brown
2017-02-28 13:43:17 UTC
Reply
Permalink
Raw Message
Post by BartC
Post by Ben Bacarisse
<snip>
Post by fred flintstone
I haven't looked at other threads yet, as it just looks beset by
trolls/spam. If you would like to give me a reasonable recommendation
for a starter killfile for clc, I'd read what you wrote.
The obvious candidates are: fir because he writes gibberish and has no
concept of engaging in intelligent discussion; Rick C Hodgin because he
treats the group as a field for evangelism rather than a newsgroup for
C; and BartC because he'd rather whinge than learn and after a while it
gets rather trying.
Or someone could look at people's posts, and at what they like to come
here to do, and make up their own mind.
Agreed. (I wrote the same thing myself.)
Post by BartC
Some like to debate technical details, others seem to have an agenda
against specific posters.
And some seem to have an agenda against the C language, against
particular operating systems, against common utilities and tools,
against particular compilers, and against learning in general.

But it is a matter of personal choice and opinion who one agrees with or
disagrees with, and who one chooses to engage in debate and who one
chooses to ignore.
BartC
2017-02-28 13:59:36 UTC
Reply
Permalink
Raw Message
Post by David Brown
Post by BartC
Some like to debate technical details, others seem to have an agenda
against specific posters.
And some seem to have an agenda against the C language, against
particular operating systems, against common utilities and tools,
against particular compilers,
In other words, against poor design, needless complexity and
over-reliance on parochial tools when working on open-source. But that's
never personal (unless the people you're arguing with were those
responsible).
Post by David Brown
and against learning in general.
If someone ever gets the opportunity, writing a C compiler, or just part
of one, is a very good way of learning the murky corners of the
language, and can give useful insights into the rest. (It doesn't need
to be written in C.)

It might not, however, change their opinions of the language, or of
other compilers, for the better. (Except for an appreciation that they
managed to do the job at all!)
--
Bartc
fred flintstone
2017-03-01 12:26:21 UTC
Reply
Permalink
Raw Message
Post by BartC
If someone ever gets the opportunity, writing a C compiler, or just part
of one, is a very good way of learning the murky corners of the
language, and can give useful insights into the rest. (It doesn't need
to be written in C.)
That's why I find Plauger's _The Standard C Library_ so satisfying. It's
not a compiler but more the murky corners. His implementation and
comments on math.h are worth whatever price you pay for the book. It's
outdated in the strict sense, but satisfying as a K&R type read.
Post by BartC
It might not, however, change their opinions of the language, or of
other compilers, for the better. (Except for an appreciation that they
managed to do the job at all!)
I've never done it, having tried. (Hold snide remarks, please) C_Dreamer
has you in his killfile, but you're not in mine. I'm not gonna talk a
bunch of smack about him on a post he can't read. I won't respond to his
threat to killfile me but will say that my brother and I and aren't
facebook friends, and it's a simple fact that a third of the people like
you, a third of them don't, and a third don't know who you are.

I'm OP, and I'm not gonna stop talking about basketball. For example,
does ITU have a basketball team? If not, what is the U for?
--
fred
David Brown
2017-02-27 22:29:56 UTC
Reply
Permalink
Raw Message
Post by j***@itu.edu
Post by David Brown
I cannot fathom what you are trying to say or do here.
David, I think that the chatbot that is infesting comp.lang.c is
becoming increasingly sophisticated. I am marking these posts as
spam, I hope that other people will join me.
There appears to be some sort of bot that recently infected c.l.c. I
have it killfiled, and don't know if it is still active.

But I don't think "fred flintstone" is a bot of some sort - what gives
you that impression?
Keith Thompson
2017-02-27 23:10:47 UTC
Reply
Permalink
Raw Message
Post by j***@itu.edu
Post by David Brown
I cannot fathom what you are trying to say or do here.
David, I think that the chatbot that is infesting comp.lang.c is
becoming increasingly sophisticated. I am marking these posts as
spam, I hope that other people will join me.
I don't think "fred flintstone" is a chatboot or a troll. His initial
posting was a bit hard to decode, but his followups have been more
reasonable.
--
Keith Thompson (The_Other_Keith) kst-***@mib.org <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
Malcolm McLean
2017-02-26 14:42:45 UTC
Reply
Permalink
Raw Message
Post by fred flintstone
Let's say that you're hard-coding a string between single quotes, for
'arrow'
, how do I declare this string to exist safely?
Do I malloc a 1000 because someone has to make an adult decision?
No, you write a function called mystrdup(). (There will also be a strdup
provided with your environment but it may not be available with
certain compiler settings.

char *mystdrdup(const char *str)
{
size_t len - strlen(str):
char *answer = malloc(len + 1);
if(answer)
strcpy(answer, str);
else
/* error handling here */;

return answer;
}

You call it like this

char *str = mystrdup("arrow");

Now the string is in heap memory, you can modify it, and it will stick
around until you delete it. For a simple string literal, the win
isn't very great. But if you are building a string, then you can
construct it in a temporary buffer, then duplicate it. The buffer
is then free to construct the next string.

C is inherently unsafe. You have to keep track of which strings are
on the heap (so the easy answer is to say, "they all are"), and
who "owns" each string and thus has responsibility for freeing.
Richard Heathfield
2017-02-26 16:54:25 UTC
Reply
Permalink
Raw Message
Post by Malcolm McLean
Post by fred flintstone
Let's say that you're hard-coding a string between single quotes, for
'arrow'
, how do I declare this string to exist safely?
Do I malloc a 1000 because someone has to make an adult decision?
No, you write a function called mystrdup(). (There will also be a strdup
provided with your environment but it may not be available with
certain compiler settings.
char *mystdrdup(const char *str)
{
ITYM size_t len = strlen(str);
Post by Malcolm McLean
char *answer = malloc(len + 1);
if(answer)
strcpy(answer, str);
You might as well use the fact that you know the length:

memcpy(answer, str, len + 1);
Post by Malcolm McLean
else
/* error handling here */;
Such as?
Post by Malcolm McLean
C is inherently unsafe.
C is perfectly safe. It's programmers who are dangerous.
--
Richard Heathfield
Email: rjh at cpax dot org dot uk
"Usenet is a strange place" - dmr 29 July 1999
Sig line 4 vacant - apply within
Mr. Man-wai Chang
2017-02-26 16:56:35 UTC
Reply
Permalink
Raw Message
Post by Richard Heathfield
Post by Malcolm McLean
C is inherently unsafe.
C is perfectly safe. It's programmers who are dangerous.
Managers and directors are even more dangerous, by forcing programmers
to work overtime while taking them to pubs to drink alcohol and smoke
cigarettes? :)
--
@~@ Remain silent! Drink, Blink, Stretch! Live long and prosper!!
/ v \ Simplicity is Beauty!
/( _ )\ May the Force and farces be with you!
^ ^ (x86_64 Ubuntu 9.10) Linux 2.6.39.3
不借貸! 不詐騙! 不援交! 不打交! 不打劫! 不自殺! 請考慮綜援 (CSSA):
http://www.swd.gov.hk/tc/index/site_pubsvc/page_socsecu/sub_addressesa
Keith Thompson
2017-02-26 21:36:41 UTC
Reply
Permalink
Raw Message
Post by Malcolm McLean
Post by fred flintstone
Let's say that you're hard-coding a string between single quotes, for
'arrow'
, how do I declare this string to exist safely?
Do I malloc a 1000 because someone has to make an adult decision?
No, you write a function called mystrdup(). (There will also be a strdup
provided with your environment but it may not be available with
certain compiler settings.
Malcolm, I'm at a loss to understand how you were able to infer that the
OP needs something like strdup. I can't figure out just what he's
saying, but my best guess is that
const char *s = "arrow";
or
const char s[] = "arrow";
would be suitable. I suggest that any speculation beyond that should
wait for a more coherent question.

[...]
--
Keith Thompson (The_Other_Keith) kst-***@mib.org <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
Malcolm McLean
2017-02-26 22:53:56 UTC
Reply
Permalink
Raw Message
Post by Keith Thompson
Malcolm, I'm at a loss to understand how you were able to infer that the
OP needs something like strdup. I can't figure out just what he's
saying, but my best guess is that
const char *s = "arrow";
or
const char s[] = "arrow";
would be suitable. I suggest that any speculation beyond that should
wait for a more coherent question.
The complaint is that C string literals are "unsafe", the OP then asks
is he should malloc 1000 bytes of memory just to be safe.

Generally people think that C is unsafe because they are used to
languages where strings are higher-level objects. And in C terms
that means, "guaranteed to be on the heap".
David Brown
2017-02-26 23:53:18 UTC
Reply
Permalink
Raw Message
Post by Malcolm McLean
Post by Keith Thompson
Malcolm, I'm at a loss to understand how you were able to infer that the
OP needs something like strdup. I can't figure out just what he's
saying, but my best guess is that
const char *s = "arrow";
or
const char s[] = "arrow";
would be suitable. I suggest that any speculation beyond that should
wait for a more coherent question.
The complaint is that C string literals are "unsafe", the OP then asks
is he should malloc 1000 bytes of memory just to be safe.
It seems to me that the OP doesn't know much about C or strings, and is
making some wild guesses. We can't help him until we get more
information. But we /can/ cause immense confusion by making bizarre
posts about home-made strdup functions.
Post by Malcolm McLean
Generally people think that C is unsafe because they are used to
languages where strings are higher-level objects.
That's one possibility. Most people thing "C is unsafe" because they
don't know much about it, or how to write safe code - and they know that
some people write unsafe C code.
Post by Malcolm McLean
And in C terms
that means, "guaranteed to be on the heap".
That is complete nonsense. Putting something on the heap is never safer
in any way than having it local to a function or statically allocated.
And in particular, the safest strings are those that are constants that
are fixed in the program - string literals.
Malcolm McLean
2017-02-27 01:30:07 UTC
Reply
Permalink
Raw Message
Post by David Brown
Post by Malcolm McLean
Generally people think that C is unsafe because they are used to
languages where strings are higher-level objects.
That's one possibility. Most people thing "C is unsafe" because they
don't know much about it, or how to write safe code - and they know that
some people write unsafe C code.
Post by Malcolm McLean
And in C terms
that means, "guaranteed to be on the heap".
That is complete nonsense. Putting something on the heap is never safer
in any way than having it local to a function or statically allocated.
And in particular, the safest strings are those that are constants that
are fixed in the program - string literals.
No, the only way to make objects safe is to have a rigorously controlled
memory model for them. Which means some form of managed pointer with
the object on the heap. (I know that as a micro- optimisation C++
std::strings are actually stack objects for short strings, I'm talking
generally and loosely).

In language X, which is a high level scripting language of some sort,
we'll almost certainly have a structure in memory which is essentially
a pointer, and gives memory-checked access to our object plus
intelligent lifetime management. It might have a trivial bit of
decoration on the stack, e.g. a type field as well as memory address,
but even that is unlikely.
Keith Thompson
2017-02-27 01:44:23 UTC
Reply
Permalink
Raw Message
Post by Malcolm McLean
Post by David Brown
Post by Malcolm McLean
Generally people think that C is unsafe because they are used to
languages where strings are higher-level objects.
That's one possibility. Most people thing "C is unsafe" because they
don't know much about it, or how to write safe code - and they know that
some people write unsafe C code.
Post by Malcolm McLean
And in C terms
that means, "guaranteed to be on the heap".
That is complete nonsense. Putting something on the heap is never safer
in any way than having it local to a function or statically allocated.
And in particular, the safest strings are those that are constants that
are fixed in the program - string literals.
No, the only way to make objects safe is to have a rigorously controlled
memory model for them. Which means some form of managed pointer with
the object on the heap. (I know that as a micro- optimisation C++
std::strings are actually stack objects for short strings, I'm talking
generally and loosely).
More nonsense. How is "a rigorously controlled memory model" involving
"some form of managed pointer with the object on the heap" safer than a
simple string literal (which designates an object that exists for the
entire execution of the program)?

We don't know whether a string literal satisfies the OP's requirements;
we'll have to wait for clarification on what those requirements are.

[...]
--
Keith Thompson (The_Other_Keith) kst-***@mib.org <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
Ben Bacarisse
2017-02-27 01:46:03 UTC
Reply
Permalink
Raw Message
Post by Malcolm McLean
Post by David Brown
Post by Malcolm McLean
Generally people think that C is unsafe because they are used to
languages where strings are higher-level objects.
That's one possibility. Most people thing "C is unsafe" because they
don't know much about it, or how to write safe code - and they know that
some people write unsafe C code.
Post by Malcolm McLean
And in C terms
that means, "guaranteed to be on the heap".
That is complete nonsense. Putting something on the heap is never safer
in any way than having it local to a function or statically allocated.
And in particular, the safest strings are those that are constants that
are fixed in the program - string literals.
No, the only way to make objects safe is to have a rigorously controlled
memory model for them.
You are in danger of talking at cross-purposes. Your idea of a safe
object is one that is safe regardless of what is done with it. David's
view of a safe object is one that is (or maybe can be) used safely.

Without a discussion about what it means for a language, program or
object to be safe or unsafe, there will be little chance of
mutual understanding.

<snip>
--
Ben.
David Brown
2017-02-27 08:29:33 UTC
Reply
Permalink
Raw Message
Post by Ben Bacarisse
Post by Malcolm McLean
Post by David Brown
Post by Malcolm McLean
Generally people think that C is unsafe because they are used to
languages where strings are higher-level objects.
That's one possibility. Most people thing "C is unsafe" because they
don't know much about it, or how to write safe code - and they know that
some people write unsafe C code.
Post by Malcolm McLean
And in C terms
that means, "guaranteed to be on the heap".
That is complete nonsense. Putting something on the heap is never safer
in any way than having it local to a function or statically allocated.
And in particular, the safest strings are those that are constants that
are fixed in the program - string literals.
No, the only way to make objects safe is to have a rigorously controlled
memory model for them.
I agree with that statement - what I don't agree with is your idea of a
rigorously controlled memory model.
Post by Ben Bacarisse
You are in danger of talking at cross-purposes. Your idea of a safe
object is one that is safe regardless of what is done with it. David's
view of a safe object is one that is (or maybe can be) used safely.
Thank you for that insight. I hadn't thought of it from that point of
view, and it gives some reasoning behind Malcolm's claims.
Post by Ben Bacarisse
Without a discussion about what it means for a language, program or
object to be safe or unsafe, there will be little chance of
mutual understanding.
I think we can work with a rough definition - something is "safe" for a
particular purpose if you can use it reliably for that purpose without
having unexpected side-effects. The /purpose/ is key here. A car may
have airbags, seatbelts, automatic braking and all sorts of features to
make it safe for driving - but it is still not going to be very safe as
a boat.

In this case, the OP was asking about hard-coded strings between quotes.
In C, you can read these - you cannot write them. So "safe" here means
being able to reliably access them for reading, with a minimum of
unexpected side-effects (such as running out of memory, corrupting
structures, leaking resources, etc.). Using a const*char pointer to
"arrow", or using "const char s[] = "arrow";" with program lifetime
(file scope, or function static), will give you that with the most
rigorously controlled memory model C can provide.

If the user wants to modify the string, then it's a different matter -
and more complex code is needed to be sure it is done safely. Malcolm
is still wrong about the heap being somehow "safer" than the stack, however.
Malcolm McLean
2017-02-27 10:12:33 UTC
Reply
Permalink
Raw Message
Post by David Brown
Post by Ben Bacarisse
You are in danger of talking at cross-purposes. Your idea of a safe
object is one that is safe regardless of what is done with it. David's
view of a safe object is one that is (or maybe can be) used safely.
Thank you for that insight. I hadn't thought of it from that point of
view, and it gives some reasoning behind Malcolm's claims.
Ben's right. Of course char *arrow = "arrow" is safe in the sense that it
doesn't cause an immediate memory error, and in skilled hands it can
be used safely.
Post by David Brown
I think we can work with a rough definition - something is "safe" for a
particular purpose if you can use it reliably for that purpose without
having unexpected side-effects. The /purpose/ is key here. A car may
have airbags, seatbelts, automatic braking and all sorts of features to
make it safe for driving - but it is still not going to be very safe as
a boat.
I'd say you've got engineered safety - which a car has, thousands of them
drive around the city every day with acceptable consequences - and inherent
safety. A car is inherently dangerous, because there's no way of telling it
not to crash into a pedestrian, other than the engineered system of roads
and pavements and traffic lights. A bike is inherently safe, because even if it
does crash into a pedestrian, it doesn't have the mass or speed to cause
a fatal injury, at least usually,
Post by David Brown
In this case, the OP was asking about hard-coded strings between quotes.
In C, you can read these - you cannot write them. So "safe" here means
being able to reliably access them for reading, with a minimum of
unexpected side-effects (such as running out of memory, corrupting
structures, leaking resources, etc.). Using a const*char pointer to
"arrow", or using "const char s[] = "arrow";" with program lifetime
(file scope, or function static), will give you that with the most
rigorously controlled memory model C can provide.
But what if you try to free it? Or what if you want to strip spaces, which 90%
of the time will be a no-op?
Post by David Brown
If the user wants to modify the string, then it's a different matter -
and more complex code is needed to be sure it is done safely. Malcolm
is still wrong about the heap being somehow "safer" than the stack, however.
ava is easier that C++, largely because Java doesn't allow objects other than
primitive and handles on the stack. C++ is harder to program because a object
could be on the heap or on the stack. C++ people have evolved ways of dealing
with that, but it's engineered safety.
David Brown
2017-02-27 12:11:16 UTC
Reply
Permalink
Raw Message
Post by Malcolm McLean
Post by David Brown
Post by Ben Bacarisse
You are in danger of talking at cross-purposes. Your idea of a safe
object is one that is safe regardless of what is done with it. David's
view of a safe object is one that is (or maybe can be) used safely.
Thank you for that insight. I hadn't thought of it from that point of
view, and it gives some reasoning behind Malcolm's claims.
Ben's right. Of course char *arrow = "arrow" is safe in the sense that it
doesn't cause an immediate memory error, and in skilled hands it can
be used safely.
What do you mean, "in skilled hands"? It is hard to be /unsafe/ with
this method - you need "skilled hands" to break it. Of course, that
assumes you are able to correctly write "/const/ char* arrow", rather
than fail to copy the example.
Post by Malcolm McLean
Post by David Brown
I think we can work with a rough definition - something is "safe" for a
particular purpose if you can use it reliably for that purpose without
having unexpected side-effects. The /purpose/ is key here. A car may
have airbags, seatbelts, automatic braking and all sorts of features to
make it safe for driving - but it is still not going to be very safe as
a boat.
I'd say you've got engineered safety - which a car has, thousands of them
drive around the city every day with acceptable consequences - and inherent
safety. A car is inherently dangerous, because there's no way of telling it
not to crash into a pedestrian, other than the engineered system of roads
and pavements and traffic lights. A bike is inherently safe, because even if it
does crash into a pedestrian, it doesn't have the mass or speed to cause
a fatal injury, at least usually,
Fair enough. That is going into more detail than I did, but I agree
with it.
Post by Malcolm McLean
Post by David Brown
In this case, the OP was asking about hard-coded strings between quotes.
In C, you can read these - you cannot write them. So "safe" here means
being able to reliably access them for reading, with a minimum of
unexpected side-effects (such as running out of memory, corrupting
structures, leaking resources, etc.). Using a const*char pointer to
"arrow", or using "const char s[] = "arrow";" with program lifetime
(file scope, or function static), will give you that with the most
rigorously controlled memory model C can provide.
But what if you try to free it? Or what if you want to strip spaces, which 90%
of the time will be a no-op?
You can't "free" it - but there is no logical reason why you would try
to do so. The same applies to any "rigorously managed" string system -
you would never call "free" from user code. If user code is calling
functions like malloc or free directly, it is not "rigorously managed".

You cannot strip spaces from the string either - it is read-only. It is
a fixed "hard-coded" string, just as the OP wanted.
Post by Malcolm McLean
Post by David Brown
If the user wants to modify the string, then it's a different matter -
and more complex code is needed to be sure it is done safely. Malcolm
is still wrong about the heap being somehow "safer" than the stack, however.
ava is easier that C++, largely because Java doesn't allow objects other than
primitive and handles on the stack.
No, that is not the case - it is totally wrong.

First, Java is "easier" than C++ for some things, harder for others. It
is true that it is easier to write Java code without the typical C
mistakes of failing to free heap memory or trying to free it twice. But
modern C++ also makes it easy to write such code, using unique_ptr and
shared_ptr. The key to Java's memory handling is its garbage collection
so that user code does not have to "free" anything, and thus cannot make
mistakes with "free" - the fact that most objects are put on the heap is
completely incidental.

In C, the safest place to put run-time data is on the stack - precisely
because you don't have to worry about freeing the memory. (It is also
more efficient, which is a nice bonus.) Of course you must be careful
about the sizes of data to allocate, and you typically have no
information about allocation failure. And the allocated memory does not
live beyond the lifetime of the function. But when stack data can be
used, it is safer than the heap because it is simpler.
Post by Malcolm McLean
C++ is harder to program because a object
could be on the heap or on the stack.
That does not make it harder to program.
Post by Malcolm McLean
C++ people have evolved ways of dealing
with that, but it's engineered safety.
The C++ language has evolved more convenient ways of handling memory
safety. Because it is part of the language, it is at least as much
"inherent safety" as the Java method - both languages have been
"engineered" to make them as safe as practical for users.
fred flintstone
2017-02-27 12:41:12 UTC
Reply
Permalink
Raw Message
Post by Malcolm McLean
No, you write a function called mystrdup(). (There will also be a strdup
provided with your environment but it may not be available with
certain compiler settings.
char *mystdrdup(const char *str)
{
char *answer = malloc(len + 1);
if(answer)
strcpy(answer, str);
else
/* error handling here */;
return answer;
}
You call it like this
char *str = mystrdup("arrow");
Now the string is in heap memory, you can modify it, and it will stick
around until you delete it. For a simple string literal, the win
isn't very great. But if you are building a string, then you can
construct it in a temporary buffer, then duplicate it. The buffer
is then free to construct the next string.
C is inherently unsafe. You have to keep track of which strings are
on the heap (so the easy answer is to say, "they all are"), and
who "owns" each string and thus has responsibility for freeing.
Thanks, malcolm. The way I have it now, I have the strings to be
substituted initialized in source code:

const char *executable1 = "arrow";
const char *executable2 = "mahershala";

How would the memory considerations go if these were to come off the
command line with argv[]?
--
fred flintstone
Malcolm McLean
2017-02-27 13:04:30 UTC
Reply
Permalink
Raw Message
Post by fred flintstone
Thanks, malcolm. The way I have it now, I have the strings to be
const char *executable1 = "arrow";
const char *executable2 = "mahershala";
How would the memory considerations go if these were to come off the
command line with argv[]?
argv[] strings are writeable, but it's a bad idea to write to them.

In all but the smallest programs, you need to read several options and (usually)
filenames from the commandline. I have an options parser which internally
duplicates argv. You then call it to get the options and filenames, and filenames
are returned as char *s allocated by malloc().

it seems very efficient - to duplicate a string twice just to pass it back up to
main, but it is safe. All the string are now in heap memory.

It's best to treat your strings as constants. If you want to change a string, create
a new one. The destroy the old one and reassign, if you want to edit the string.


so
char *exe1 = mystdup(argv[1]);


char *pathconcat(char *first, char *second)

{
char *answer = malloc(strlen(first) + strlen(second) + 2);
/* the allocation won't fail on a medium to large computer, if it does just quit/
strcpy(answer, first);
strcat(answer, "/"):
strcpy(answer, second);
/* we know all these are safe because we've taken the sizes of the strings */

return answer;
}

Now in fact you have several segments to build up. so.

char *pathtoexe = mystrup(exe1);
char *temp;

temp = pathconcat(part1, pathtoexe):
free(part1);
part1 = 0;
free(pathtoexex);
pathtoexe = temp;
temp = 0;

it looks like a long way round, but you can put this logic into a loop, with the variable
"pathtoexe" steadily building up to the full path, which could have an arbitrary number of
sections.
Ben Bacarisse
2017-02-27 13:25:08 UTC
Reply
Permalink
Raw Message
Malcolm McLean <***@btinternet.com> writes:
<snip>
Post by Malcolm McLean
char *pathconcat(char *first, char *second)
{
char *answer = malloc(strlen(first) + strlen(second) + 2);
/* the allocation won't fail on a medium to large computer, if it does just quit/
(missing *)
Post by Malcolm McLean
strcpy(answer, first);
strcpy(answer, second);
I think you meant strcat here too. I'd remember the first length and I
like to add in the extras like this:

size_t l1 = strlen(first);
char *name = malloc(l1 + 1 + strlen(second) + 1);
if (name) {
memcpy(name, first, l1);
name[l1] = '/';
strcpy(name + l1 + 1, second);
}

Also, for some file names, you can use a VLA as I suggested in another
post.

<snip>
--
Ben.
Keith Thompson
2017-02-27 17:56:18 UTC
Reply
Permalink
Raw Message
Post by Malcolm McLean
Post by fred flintstone
Thanks, malcolm. The way I have it now, I have the strings to be
const char *executable1 = "arrow";
const char *executable2 = "mahershala";
How would the memory considerations go if these were to come off the
command line with argv[]?
argv[] strings are writeable, but it's a bad idea to write to them.
I don't believe anyone suggested writing to the argument strings, nor
would there be any reason to do so here.

[...]
--
Keith Thompson (The_Other_Keith) kst-***@mib.org <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
Mr. Man-wai Chang
2017-02-26 17:00:21 UTC
Reply
Permalink
Raw Message
Post by fred flintstone
'arrow'
, how do I declare this string to exist safely?
Is the length of this string static or dynamic?
Post by fred flintstone
Do I malloc a 1000 because someone has to make an adult decision?
Depends on whether you wanna use the same memory space for many purposes.
--
@~@ Remain silent! Drink, Blink, Stretch! Live long and prosper!!
/ v \ Simplicity is Beauty!
/( _ )\ May the Force and farces be with you!
^ ^ (x86_64 Ubuntu 9.10) Linux 2.6.39.3
不借貸! 不詐騙! 不援交! 不打交! 不打劫! 不自殺! 請考慮綜援 (CSSA):
http://www.swd.gov.hk/tc/index/site_pubsvc/page_socsecu/sub_addressesa
James R. Kuyper
2017-02-26 23:55:33 UTC
Reply
Permalink
Raw Message
On 02/26/2017 07:14 AM, fred flintstone wrote:
...
So there's 3DBESNUB type things ...
Is this
<https://www.physics.byu.edu/faculty/christensen/Physics%20121/3D%20BE%20SNUB.htm>
what you're referring to?
... Right
at the top is that I don't know how to declare strings in c in a safe way.
Let's say that you're hard-coding a string between single quotes, for
If it's between single quotes, it's not a string, it's a single
character constant. "The value of an integer character constant
containing more than one character (e.g., 'ab'), or containing a
character or escape sequence that does not map to a single-byte
execution character, is implementation-defined." (6.4.4.4p10). Such
constants are very seldom used. The fact that their value is
implementation-defined makes them useless for portable code. I'd guess
that most C programmers are unaware that such a construct is even
permitted. Therefore, I doubt that it's what you actually meant. You
probably meant double quotes, and that's what my answers farther down
assume.

In case you're wondering what character constants containing multiple
characters are useful for, here's some examples of what's permitted:

Two trivial possibilities are that 'arrow' == 'a', or 'arrow' == 'w'.

Note that character constants, despite their name, have values of type
'int'. Therefore, on a system where char is unsigned, and int has more
than 5*CHAR_BIT bits, an implementation could choose to define that

'arrow' == (((('a'*CHAR_MAX + 'r')*CHAR_MAX + 'r')*CHAR_MAX + 'o')*
CHAR_MAX + 'w')
'arrow'
, how do I declare this string to exist safely?
That depends upon which danger you're hoping to avoid. Define the
danger, and we can tell you the best way to minimize it. However, don't
expect too much. C is a very low-level language - it does very little to
protect you from shooting yourself in the foot. It's the language used
to efficiently implement many of the safer languages. Here's several
different options, each of which has different advantages and disadvantages:

#define ARROW "arrow"

const char *parrow = "arrow";
char arrow[] = "arrow";
// Either of those definitions could be declared static
// Either of those definitions could appear at either file scope or
// block scope.

parrow = malloc(sizeof "arrow"));
memcpy(parrow, "arrow", sizeof "arrow");
Do I malloc a 1000 because someone has to make an adult decision?
That depends entirely upon what danger you're trying to protect against.
As a general rule, if that solution helps you avoid a danger, then that
danger involves bad coding practices. In that case, you're better off
avoiding that danger by by improving your coding practices than by
allocating 1000 bytes to hold a 5-character string.
fred flintstone
2017-02-28 12:20:49 UTC
Reply
Permalink
Raw Message
Post by James R. Kuyper
...
So there's 3DBESNUB type things ...
Is this
<https://www.physics.byu.edu/faculty/christensen/Physics%20121/3D%20BE%20SNUB.htm>
what you're referring to?
Yeah. I'm trying to paint the pictures that I need to to make it around
the bases on this one. Better usenet practice is when OP does not force
readers to follow links, as these might be suspect. I'm left to paint a
picture with words.

I want to draw the attention of respondents down here, as I announce
myself safe on some type of first base, fulfilling D1 of the three D's.
D1 might be a portrait of the client of the C application. The client
is, first and foremost, me, and then everyone I take care of with the
same methods. Many are simple pioneers, who don't need to be dished out
to what's Out There.
Post by James R. Kuyper
... Right
at the top is that I don't know how to declare strings in c in a safe way.
Let's say that you're hard-coding a string between single quotes, for
If it's between single quotes, it's not a string, it's a single
character constant. "The value of an integer character constant
containing more than one character (e.g., 'ab'), or containing a
character or escape sequence that does not map to a single-byte
execution character, is implementation-defined." (6.4.4.4p10). Such
constants are very seldom used. The fact that their value is
implementation-defined makes them useless for portable code. I'd guess
that most C programmers are unaware that such a construct is even
permitted. Therefore, I doubt that it's what you actually meant. You
probably meant double quotes, and that's what my answers farther down
assume.
In case you're wondering what character constants containing multiple
Two trivial possibilities are that 'arrow' == 'a', or 'arrow' == 'w'.
Note that character constants, despite their name, have values of type
'int'. Therefore, on a system where char is unsigned, and int has more
than 5*CHAR_BIT bits, an implementation could choose to define that
'arrow' == (((('a'*CHAR_MAX + 'r')*CHAR_MAX + 'r')*CHAR_MAX + 'o')*
CHAR_MAX + 'w')
Thank you for comment which brought me off single quotes.
Post by James R. Kuyper
'arrow'
, how do I declare this string to exist safely?
That depends upon which danger you're hoping to avoid. Define the
danger, and we can tell you the best way to minimize it. However, don't
expect too much. C is a very low-level language - it does very little to
protect you from shooting yourself in the foot. It's the language used
to efficiently implement many of the safer languages. Here's several
different options, each of which has different advantages and
#define ARROW "arrow"
const char *parrow = "arrow";
char arrow[] = "arrow";
// Either of those definitions could be declared static
// Either of those definitions could appear at either file scope or
// block scope.
parrow = malloc(sizeof "arrow"));
memcpy(parrow, "arrow", sizeof "arrow");
Listen to me james. Have you ever used 'malloc' as a verb? If you have a
declaration like:

const char *parrow = "arrow";

, can one say that it has been malloced, or is it only correct to use
the grown-up term of "allocated?" (Might there be a malloc right under
the patina?)
Post by James R. Kuyper
Do I malloc a 1000 because someone has to make an adult decision?
That depends entirely upon what danger you're trying to protect against.
As a general rule, if that solution helps you avoid a danger, then that
danger involves bad coding practices. In that case, you're better off
avoiding that danger by by improving your coding practices than by
allocating 1000 bytes to hold a 5-character string.
This source considers some minimal cases. I like to write quines.
Douglas Hofstadter's Goedel Escher Bach set me back 44 marks, a lot of
money to me.

Anyways, the idea is that the source is reproduced faithfully. I'm not
doing it in a strict mathematical sense (yet). I'll begin with a source
listing of the driving .sh, avec warnings, the output thereof, and then
ask questions. So, tja:

$ sh toolchain2.sh
sub1.c: In function ‘main’:
sub1.c:13:15: warning: unused variable ‘ext’ [-Wunused-variable]
const char *ext = "sh";
^
sub1.c:12:15: warning: unused variable ‘base’ [-Wunused-variable]
const char *base = "toolchain";
^
sub1.c:11:15: warning: unused variable ‘executable2’ [-Wunused-variable]
const char *executable2 = "mahershala";
^
sub1.c:10:15: warning: unused variable ‘executable1’ [-Wunused-variable]
const char *executable1 = "arrow";
^
sub1.c:8:7: warning: unused variable ‘version’ [-Wunused-variable]
int version, c, i;
^
$ pwd
/home/bob/Documents/programming/Book Examples/ch02/command_line
$ ls -l
total 44
-rw-rw-r-- 1 bob bob 1804 Feb 26 01:03 arrow.c
-rw-rw-r-- 1 bob bob 1008 Feb 27 17:42 awk3
-rwxrwxr-x 1 bob bob 9104 Feb 27 18:25 sub1
-rw-rw-r-- 1 bob bob 950 Feb 27 18:24 sub1.c
-rw-rw-r-- 1 bob bob 1030 Feb 27 18:15 sub1.c~
-rw-rw-r-- 1 bob bob 969 Feb 27 18:25 text1.txt
-rw-rw-r-- 1 bob bob 103 Feb 27 18:22 toolchain2.sh
-rwxrwxr-x 1 bob bob 273 Feb 26 01:51 toolchain3.sh
-rw-rw-r-- 1 bob bob 273 Feb 27 18:25 toolchain4.sh
$ cat toolchain2.sh
gcc -Wall -Wextra -o sub1 sub1.c >text1.txt
./sub1 arrow mahershala >>text1.txt
cat sub1.c >>text1.txt
$ cat text1.txt
3
arrow
mahershala
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int
main (int argc, char *argv[])
{
int version, c, i;
FILE *fptr, *gptr;
const char *executable1 = "arrow";
const char *executable2 = "mahershala";
const char *base = "toolchain";
const char *ext = "sh";



printf ("%d\n", argc);
for (i = 1; i < argc; i++) {
printf ("%s\n", argv[i]);
}
fptr = fopen ("toolchain3.sh", "r");
if (fptr == NULL) {
printf ("fopen no bueno");
exit (1);
}
gptr = fopen ("toolchain4.sh", "w");

if (gptr == NULL) {
printf ("gopen no bueno");
exit (1);
}

while (1) {
c = fgetc (fptr);

if (c == EOF)
break;
else
putc (c, gptr);
}


fclose (fptr);
fclose (gptr);

return 0;
}

char *
mystdrdup (const char *str)
{
size_t len = strlen (str);
char *answer = malloc (len + 1);
if (answer)
strcpy (answer, str);
else { /* error handling here */
};

return answer;
}
$

Q1) Is this standard, portable, contemporary C?

Q2) This program shall be legal C. What constraints does that put on the
cumulative size on what comes from argv?

The specification of this program will handle the case that what is
passed to it exceeds the allowable parameters. Is it INT_MIN?

Q3) I have Plauger's _Standard C Library_ under my bed somewhere. How
would the list of necessary .h files differ from then to contemporary C?

Thank you for your comment, and remember, some people warm up to a topic....
--
fred flintstone
David Brown
2017-02-28 13:38:26 UTC
Reply
Permalink
Raw Message
Post by fred flintstone
Post by James R. Kuyper
...
So there's 3DBESNUB type things ...
Is this
<https://www.physics.byu.edu/faculty/christensen/Physics%20121/3D%20BE%20SNUB.htm>
what you're referring to?
Yeah. I'm trying to paint the pictures that I need to to make it around
the bases on this one. Better usenet practice is when OP does not force
readers to follow links, as these might be suspect. I'm left to paint a
picture with words.
It is even better Usenet practice to explain what is relevant, in clear
terms appropriate to the group. Stop "painting pictures" and using
silly American sporting terms ("make it around the bases"). Just use
plain English. And while posting links is often bad, it is far worse to
use local acronyms such as your 3D-thingy that are meaningless to almost
everyone unless they spent time researching them.
Post by fred flintstone
I want to draw the attention of respondents down here, as I announce
myself safe on some type of first base, fulfilling D1 of the three D's.
D1 might be a portrait of the client of the C application. The client
is, first and foremost, me, and then everyone I take care of with the
same methods. Many are simple pioneers, who don't need to be dished out
to what's Out There.
The words may be spelt correctly, but you are writing gibberish. Please
stop. You will end up on killfiles or being ignored - and the people
who killfile you are mostly the people (like Richard Heathfield, who has
also warned you) who give good, solid answers in this group.

<snip>
Post by fred flintstone
Post by James R. Kuyper
, how do I declare this string to exist safely?
That depends upon which danger you're hoping to avoid. Define the
danger, and we can tell you the best way to minimize it. However, don't
expect too much. C is a very low-level language - it does very little to
protect you from shooting yourself in the foot. It's the language used
to efficiently implement many of the safer languages. Here's several
different options, each of which has different advantages and
#define ARROW "arrow"
const char *parrow = "arrow";
char arrow[] = "arrow";
// Either of those definitions could be declared static
// Either of those definitions could appear at either file scope or
// block scope.
parrow = malloc(sizeof "arrow"));
memcpy(parrow, "arrow", sizeof "arrow");
Listen to me james. Have you ever used 'malloc' as a verb? If you have a
const char *parrow = "arrow";
, can one say that it has been malloced, or is it only correct to use
the grown-up term of "allocated?" (Might there be a malloc right under
the patina?)
Some people use malloc as a verb, others would say allocated on the heap
or dynamically allocated. No one would say that about "parrow" or
"arrow" above, because there has been no dynamic allocation.
Post by fred flintstone
Post by James R. Kuyper
Do I malloc a 1000 because someone has to make an adult decision?
That depends entirely upon what danger you're trying to protect against.
As a general rule, if that solution helps you avoid a danger, then that
danger involves bad coding practices. In that case, you're better off
avoiding that danger by by improving your coding practices than by
allocating 1000 bytes to hold a 5-character string.
This source considers some minimal cases. I like to write quines.
Douglas Hofstadter's Goedel Escher Bach set me back 44 marks, a lot of
money to me.
More meaningless gibberish.
Post by fred flintstone
Anyways, the idea is that the source is reproduced faithfully. I'm not
doing it in a strict mathematical sense (yet). I'll begin with a source
listing of the driving .sh, avec warnings, the output thereof, and then
$ sh toolchain2.sh
sub1.c:13:15: warning: unused variable ‘ext’ [-Wunused-variable]
const char *ext = "sh";
^
sub1.c:12:15: warning: unused variable ‘base’ [-Wunused-variable]
const char *base = "toolchain";
^
sub1.c:11:15: warning: unused variable ‘executable2’ [-Wunused-variable]
const char *executable2 = "mahershala";
^
sub1.c:10:15: warning: unused variable ‘executable1’ [-Wunused-variable]
const char *executable1 = "arrow";
^
sub1.c:8:7: warning: unused variable ‘version’ [-Wunused-variable]
int version, c, i;
^
$ pwd
/home/bob/Documents/programming/Book Examples/ch02/command_line
$ ls -l
total 44
-rw-rw-r-- 1 bob bob 1804 Feb 26 01:03 arrow.c
-rw-rw-r-- 1 bob bob 1008 Feb 27 17:42 awk3
-rwxrwxr-x 1 bob bob 9104 Feb 27 18:25 sub1
-rw-rw-r-- 1 bob bob 950 Feb 27 18:24 sub1.c
-rw-rw-r-- 1 bob bob 1030 Feb 27 18:15 sub1.c~
-rw-rw-r-- 1 bob bob 969 Feb 27 18:25 text1.txt
-rw-rw-r-- 1 bob bob 103 Feb 27 18:22 toolchain2.sh
-rwxrwxr-x 1 bob bob 273 Feb 26 01:51 toolchain3.sh
-rw-rw-r-- 1 bob bob 273 Feb 27 18:25 toolchain4.sh
$ cat toolchain2.sh
gcc -Wall -Wextra -o sub1 sub1.c >text1.txt
You should add "-O1" to that list - it lets gcc do better analysis for
more warnings.
Post by fred flintstone
./sub1 arrow mahershala >>text1.txt
cat sub1.c >>text1.txt
$ cat text1.txt
3
arrow
mahershala
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int
main (int argc, char *argv[])
{
int version, c, i;
FILE *fptr, *gptr;
const char *executable1 = "arrow";
const char *executable2 = "mahershala";
const char *base = "toolchain";
const char *ext = "sh";
printf ("%d\n", argc);
for (i = 1; i < argc; i++) {
printf ("%s\n", argv[i]);
}
fptr = fopen ("toolchain3.sh", "r");
if (fptr == NULL) {
printf ("fopen no bueno");
exit (1);
}
gptr = fopen ("toolchain4.sh", "w");
if (gptr == NULL) {
printf ("gopen no bueno");
exit (1);
}
while (1) {
c = fgetc (fptr);
if (c == EOF)
break;
else
putc (c, gptr);
}
fclose (fptr);
fclose (gptr);
return 0;
}
Please remove Malcolm's useless "mytstdrdup" function from your code.
His post was not helpful in any way.
Post by fred flintstone
char *
mystdrdup (const char *str)
{
size_t len = strlen (str);
char *answer = malloc (len + 1);
if (answer)
strcpy (answer, str);
else { /* error handling here */
};
return answer;
}
$
Q1) Is this standard, portable, contemporary C?
You have already been given a number of suggestions to improve the code,
including solving your original problem.
Post by fred flintstone
Q2) This program shall be legal C. What constraints does that put on the
cumulative size on what comes from argv?
It is up to the implementation to decide what comes in on argv.
Post by fred flintstone
The specification of this program will handle the case that what is
passed to it exceeds the allowable parameters. Is it INT_MIN?
You are not currently using anything that is passed to the program, and
we have no way of guessing what that might be, or what your
specifications are.
Post by fred flintstone
Q3) I have Plauger's _Standard C Library_ under my bed somewhere. How
would the list of necessary .h files differ from then to contemporary C?
I don't know that book. There are plenty of references for modern
standard C headers. The ultimate reference is the C standards - N1570
is a freely available draft of C11. But the standards documents are not
easily going for a beginner. I would recommend this site:

<http://en.cppreference.com/w/c/header>

The C FAQ at <http://c-faq.com/> is also an excellent reference.
Post by fred flintstone
Thank you for your comment, and remember, some people warm up to a topic....
Keith Thompson
2017-02-28 16:33:30 UTC
Reply
Permalink
Raw Message
[...]
Post by David Brown
Post by fred flintstone
gcc -Wall -Wextra -o sub1 sub1.c >text1.txt
You should add "-O1" to that list - it lets gcc do better analysis for
more warnings.
Why do you recommend -O1 rather than -O3?

If you want to write standard C, I'd also recommend
-std=c11 -pedantic-errors

If you use -pedantic rather than -pedantic-errors, some errors will be
diagnosed with non-fatal warnings; that's ok if you treat warnings
*very* seriously.

[...]
--
Keith Thompson (The_Other_Keith) kst-***@mib.org <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
David Brown
2017-02-28 18:38:05 UTC
Reply
Permalink
Raw Message
Post by Keith Thompson
[...]
Post by David Brown
Post by fred flintstone
gcc -Wall -Wextra -o sub1 sub1.c >text1.txt
You should add "-O1" to that list - it lets gcc do better analysis for
more warnings.
Why do you recommend -O1 rather than -O3?
-O1 is enough to enable the analysis passes that give better warnings -
as far as I know, you don't get more static analysis with greater
optimisation levels.

It can vary whether -O3 is actually any faster than -O2 - so usually -O2
is picked for "fast code". If you need more than that, you probably
want to consider other flags like "-march=native" or "-ffast-math", and
perhaps using extra compiler features (attributes, etc.) if portability
is not an issue.

In general, I'd say "-O1" if you want to do debugging or view the
generated assembly (since the structure of your source code is more
visible in the generated output), and "-O2" if you want faster code.
Post by Keith Thompson
If you want to write standard C, I'd also recommend
-std=c11 -pedantic-errors
Agreed, if you want to check for standards compliance (at least, as good
a check as you can conveniently get with little effort). I don't
usually think about -pedantic flags, simply because for my own work I
use -std=gnu11 and make use of a number of gcc extensions - portability
across compilers is not an issue for most of what I do. But certainly
sticking to the standards is a good idea for someone learning C.
Post by Keith Thompson
If you use -pedantic rather than -pedantic-errors, some errors will be
diagnosed with non-fatal warnings; that's ok if you treat warnings
*very* seriously.
I like to use -Werror - I /do/ treat warnings very seriously. But
that's me - it is not necessarily a good idea for everyone.
Keith Thompson
2017-02-28 19:40:53 UTC
Reply
Permalink
Raw Message
[...]
Post by David Brown
Post by Keith Thompson
If you use -pedantic rather than -pedantic-errors, some errors will be
diagnosed with non-fatal warnings; that's ok if you treat warnings
*very* seriously.
I like to use -Werror - I /do/ treat warnings very seriously. But
that's me - it is not necessarily a good idea for everyone.
Using -pedantic-errors rather than just -pedantic means that diagnostics
required by the C standard are fatal. This is, in my opinion, a good
idea (except that not all the diagnostic produced by -pedantic[-errors]
are mandatory ones; there's one about string literals that exceed a
certain length).

Using -Werror means that *all* warnings issued by gcc become fatal --
which means you're trusting the gcc authors to decide what non-requires
diagnostics you have to avoid in your code. For example,
struct foo obj = { 0 };
is a perfectly good idiom, but some older versions of gcc will warn
about it if struct foo has more than one scalar member.
--
Keith Thompson (The_Other_Keith) kst-***@mib.org <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
David Brown
2017-02-28 20:03:17 UTC
Reply
Permalink
Raw Message
Post by Keith Thompson
[...]
Post by David Brown
Post by Keith Thompson
If you use -pedantic rather than -pedantic-errors, some errors will be
diagnosed with non-fatal warnings; that's ok if you treat warnings
*very* seriously.
I like to use -Werror - I /do/ treat warnings very seriously. But
that's me - it is not necessarily a good idea for everyone.
Using -pedantic-errors rather than just -pedantic means that diagnostics
required by the C standard are fatal. This is, in my opinion, a good
idea (except that not all the diagnostic produced by -pedantic[-errors]
are mandatory ones; there's one about string literals that exceed a
certain length).
Using -Werror means that *all* warnings issued by gcc become fatal --
which means you're trusting the gcc authors to decide what non-requires
diagnostics you have to avoid in your code. For example,
struct foo obj = { 0 };
is a perfectly good idiom, but some older versions of gcc will warn
about it if struct foo has more than one scalar member.
-Werror means that /all/ warnings that are enabled will become fatal,
which is what I want for most of my coding. And I enable quite a few
warnings, because most of them happen to match the way I like my code to
be written - so a warning indicates a bug in my code (even if it is only
a stylistic "bug"). Some warnings I don't enable, and of course my
choice of warning flags will be different when compiling code from
elsewhere.

So yes, I know what this flag means, and I use it intentionally. But I
quite understand that other people pick different flags.
Noob
2017-02-28 21:55:47 UTC
Reply
Permalink
Raw Message
Post by David Brown
In general, I'd say "-O1" if you want to do debugging
Since version 4.8, -Og might be more appropriate for debugging.

https://gcc.gnu.org/gcc-4.8/changes.html
Post by David Brown
A new general optimization level, -Og, has been introduced. It
addresses the need for fast compilation and a superior debugging
experience while providing a reasonable level of run-time
performance. Overall experience for development should be better than
the default optimization level -O0.
Regards.
James R. Kuyper
2017-02-28 16:43:53 UTC
Reply
Permalink
Raw Message
Post by fred flintstone
Post by James R. Kuyper
...
So there's 3DBESNUB type things ...
Is this
<https://www.physics.byu.edu/faculty/christensen/Physics%20121/3D%20BE%20SNUB.htm>
what you're referring to?
...
Post by fred flintstone
I want to draw the attention of respondents down here, as I announce
myself safe on some type of first base, fulfilling D1 of the three D's.
D1 might be a portrait of the client of the C application. The client
is, first and foremost, me, and then everyone I take care of with the
same methods. Many are simple pioneers, who don't need to be dished out
to what's Out There.
The key problem is that your acronym is almost universally unfamiliar to
the members of this newsgroup. The only reason that anyone had any idea
what you were talking about is because I bothered searching, and dared
to select a link that appeared in my search - a link in your message
would have presented no greater danger than the link on that search
page. Of course, the best approach would have been to define the term
yourself, rather than providing a link to a definition.

...
Post by fred flintstone
Post by James R. Kuyper
... Here's several
different options, each of which has different advantages and
#define ARROW "arrow"
const char *parrow = "arrow";
char arrow[] = "arrow";
// Either of those definitions could be declared static
// Either of those definitions could appear at either file scope or
// block scope.
parrow = malloc(sizeof "arrow"));
memcpy(parrow, "arrow", sizeof "arrow");
Listen to me james. Have you ever used 'malloc' as a verb?
Yes, though I usually spell it as malloc(), to emphasize that I'm
talking about a function. Similarly, I'll often append [] when talking
about the name of an array, or <> when talking about the name of a C++
template.
Post by fred flintstone
... If you have a
const char *parrow = "arrow";
, can one say that it has been malloced, or is it only correct to use
the grown-up term of "allocated?" (Might there be a malloc right under
the patina?)
I use "malloc()d" only to describe memory that has been dynamically
allocated using the malloc() function. If I don't know whether malloc(),
calloc(), or realloc() was used, I'll use the term "dynamically
allocated" rather than "malloc()d". Nothing having to do with that line
of code is dynamically allocated.

Your use of the string literal "arrow" requires the implementation to
statically allocate an unnamed array of at least 6 chars, containing the
values 'a', 'r', 'r', 'o', 'w', and '\0'. The value of the string
literal itself is a pointer to the first character in that array, 'a'.
Note that if "array" occurs anywhere else in your program, it might use
the same array, or it might cause a separate array to be created - the
standard allows for both possibilities, and real-world compilers exist
that choose each of those two options. Any attempt to write to that
array has undefined behavior.
parray is a pointer object that has either static or automatic storage
duration, depending upon whether that declaration is a file scope or
block scope.

...
Post by fred flintstone
$ sh toolchain2.sh
sub1.c:13:15: warning: unused variable ‘ext’ [-Wunused-variable]
const char *ext = "sh";
^
sub1.c:12:15: warning: unused variable ‘base’ [-Wunused-variable]
const char *base = "toolchain";
^
sub1.c:11:15: warning: unused variable ‘executable2’ [-Wunused-variable]
const char *executable2 = "mahershala";
^
sub1.c:10:15: warning: unused variable ‘executable1’ [-Wunused-variable]
const char *executable1 = "arrow";
^
sub1.c:8:7: warning: unused variable ‘version’ [-Wunused-variable]
int version, c, i;
I hope that you understand that the warnings above are entirely due to
the fact that you made no use of those variables - they do not indicate
that there is any problem with the definitions of those objects.
Keith Thompson
2017-02-28 16:46:18 UTC
Reply
Permalink
Raw Message
[...]
Post by fred flintstone
Listen to me james. Have you ever used 'malloc' as a verb? If you have a
const char *parrow = "arrow";
, can one say that it has been malloced, or is it only correct to use
the grown-up term of "allocated?" (Might there be a malloc right under
the patina?)
I won't speak for James, but I've certainly used malloc as a verb.

But it would not be correct to say that anything has been malloced in
the above declaration. Memory for the pointer object parrow is
allocated either at program startup or on entry to the enclosing block,
depending on whether it's defined inside or outside a function body.
Memory for the string "arrow" is allocated at program startup. (At
least logically; an implementation can arrange for them to be allocated
in any way that produces the same semantics.) It's unlikely that any of
these will be allocated via an underlying call to malloc.
Post by fred flintstone
Post by fred flintstone
Do I malloc a 1000 because someone has to make an adult decision?
It's hard to tell what you mean here, but I'd suggest that allocating
some amount that you assume is much more than you'll actually need is
*probably* poor practice. For example, if you allocate 1000 bytes to
hold a line of text read from a file, then most of that space will be
wasted in the usual case. On the other hand, I've certainly dealt with
text files with lines longer than 1000 bytes, and most of the tools I
use can deal with them just fine.

On the other other hand, allocating a large fixed chunk of memory is
simpler and can often be quicker. But if you can manage to allocate
just what you need, whether it's large or small, that can often (but not
always) be the best approach.

[...]
Post by fred flintstone
while (1) {
c = fgetc (fptr);
if (c == EOF)
break;
else
putc (c, gptr);
}
The usual idiom for this kind of loop is:

while ((c = fgetc(fptr)) != EOF) {
putc(c, gptr);
}

[...]
Post by fred flintstone
char *
mystdrdup (const char *str)
{
size_t len = strlen (str);
char *answer = malloc (len + 1);
if (answer)
strcpy (answer, str);
else { /* error handling here */
};
return answer;
}
*If* you need this function (you probably don't), it doesn't need any
error handling other than returning a null pointer. A low-level
function like this has no way of knowing how an allocation failure
should be handled. Just let the caller know it failed, and the caller
can decide how to proceed.

[...]
--
Keith Thompson (The_Other_Keith) kst-***@mib.org <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
TickleMe Elmo
2017-02-28 07:47:19 UTC
Reply
Permalink
Raw Message
Having to suffer the use of
it can hardly be called "free" when you include your time. You refuse to take responsibility for your own actions. Actions that are easily quoted and pointed out.

The "advocates" value the lowest common denominator in all things. I have a http://youtu.be/5OfWsoPAg7o system I use as well, but it's a bit different.

That's right Bill Cunningham! Usenet is a self-governing institution based on the honor system. You have no idea how much a fool of yourself you are making. Do you think everyone who points out your trolling is evil?

You just mastered the bait! Jerry Stuckle's posts are nothing but an indecipherable mess.

Another successful "thumb drive install" test. That is if you count wasting time as a success. Sandman lies. Here is a list of names Jonas Eklundh has admitted he attributes to Snit "Cactus Pete", "Donald", "Donald Miller", "Horace McSwain", "Hymen", "Mike Weaver", "Modena IV Drid", "Omar Murad Asfour", "Rhino Plastee", "Soapy", "SopwithCamel", "Sunny Day", "Takuya Saitoh", "The Letter Q", "tmelmosfire", "zevon". Most of those are names of his buddy Steven Petruzzellis. This is just an amusement of mine. And in response Jerry Stuckle has nothing but an attempt to start a circus.

What do you get out of lying? Cry harder Jerry Stuckle!

-
My Snoring Solution

Jonas Eklundh
TickleMe Elmo
2017-03-01 15:59:17 UTC
Reply
Permalink
Raw Message
You are as dumb as a shoe. Idiot. Savageduck pwns Mike Easter in every way possible. What I do is certainly more efficient.

How is Firefox on Linux doing anything above the lowest common denominator? You're clueless!

I am working on a program which will be more than anything Mike Easter can do!

Can you stop begging for my attention?


What Every Entrepreneur Must Know!


Jonas Eklundh
Loading...