kps@teddy.UUCP (07/10/85)
I found a way to initialize an array of characters without using a loop.
Here is the method I used:
char blanks[SIZE]; /* declare array of SIZE elements */
blanks[0] = ' '; /* initialize 1st element */
strncpy(blanks + 1, blanks, SIZE - 1); /* initialize entire array */
^^^ ^^^ ^^^
| | |
destination source how many characters to copy
The trick is to use strncpy in an almost recursive way.
Well, I hope you found this useful.
stew@harvard.ARPA (Stew Rubenstein) (07/11/85)
In article <899@teddy.UUCP> kps@teddy.UUCP (Kesavan P. Srinivasan) writes: >I found a way to initialize an array of characters without using a loop. >Here is the method I used: > > char blanks[SIZE]; /* declare array of SIZE elements */ > > blanks[0] = ' '; /* initialize 1st element */ > > strncpy(blanks + 1, blanks, SIZE - 1); /* initialize entire array */ > ^^^ ^^^ ^^^ > | | | > destination source how many characters to copy > >The trick is to use strncpy in an almost recursive way. >Well, I hope you found this useful. This is not portable. There is no guarantee that strncpy() copies one char at a time in forward order. If it is implemented using the VAX MOVC3 instruction, for example, the overlap of the source and destination strings does NOT affect the result! Stew
gangal@petsd.UUCP (Dept 3271) (07/11/85)
In article <899@teddy.UUCP> kps@teddy.UUCP (Kesavan P. Srinivasan) writes: >I found a way to initialize an array of characters without using a loop. >Here is the method I used: > > blanks[0] = ' '; /* initialize 1st element */ > strncpy(blanks + 1, blanks, SIZE - 1); /* initialize entire array */ 1) This probably uses a loop (in strncpy) 2) I don't know exactly what the standard C library does, but many string copy routines (in micro-code or higher level) check for overlapping strings and would process your request in reverse to avoid just the recursion you want. (For instance, you may have a string in there to which you want to prepend a character.) bob
ark@alice.UUCP (Andrew Koenig) (07/11/85)
> I found a way to initialize an array of characters without using a loop. > Here is the method I used: > char blanks[SIZE]; /* declare array of SIZE elements */ > blanks[0] = ' '; /* initialize 1st element */ > strncpy(blanks + 1, blanks, SIZE - 1); /* initialize entire array */ > ^^^ ^^^ ^^^ > | | | > destination source how many characters to copy Don't. There is no guarantee that strncpy copies one character at a time.
mgh@mtunh.UUCP (Marcus Hand) (07/11/85)
> Reply-To: kps@teddy.UUCP (Kesavan P. Srinivasan) > Keywords: strncpy > Summary: initializing strings (arrays of characters) > > I found a way to initialize an array of characters without using a loop. > Here is the method I used: > > char blanks[SIZE]; /* declare array of SIZE elements */ > > blanks[0] = ' '; /* initialize 1st element */ > > strncpy(blanks + 1, blanks, SIZE - 1); /* initialize entire array */ > ^^^ ^^^ ^^^ > | | | > destination source how many characters to copy > > The trick is to use strncpy in an almost recursive way. > Well, I hope you found this useful. Sorry to dissapoint you, but 1. strncpy() is implemented using a loop (this side effect wouldn't work if it wasn't); 2. it only works if strncpy is implemented by starting with the first character to be moved and not the last (you can move up and down a string in either direction). I.e. it's implementation dependent; 3. its not recursive or even analogous to recursion -- it just keeps copying the last character it moved; 4. whats wrong with memset() (memory(3)) -- I don't know whether its any more efficient, but its certainly clearer to the reader what you are trying to achieve, and safer because its not implementation dependant: rtn = memset (buffer, ' ', buflen); Hope this helps you. -- Marcus Hand (mtunh!mgh)
ron@brl-tgr.ARPA (Ron Natalie <ron>) (07/12/85)
> I found a way to initialize an array of characters without using a loop. > Here is the method I used: > > strncpy(blanks + 1, blanks, SIZE - 1); /* initialize entire array */ > ^^^ ^^^ ^^^ > The trick is to use strncpy in an almost recursive way. We call this "almost recursion" iteration, and all it does is hide the loop in the strncpy function. > Well, I hope you found this useful. No, not really. -Ron
chris@umcp-cs.UUCP (Chris Torek) (07/12/85)
> I found a way to initialize an array of characters without using a loop. > Here is the method I used: > > char blanks[SIZE]; /* declare array of SIZE elements */ > blanks[0] = ' '; /* initialize 1st element */ > strncpy(blanks + 1, blanks, SIZE - 1); /* initialize entire array */ Beware, that won't work on Vax systems that use movc3 for string copies (probably Sys VR2V2.2.2.2... [sorry :-)] and 4.3 both). -- In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 4251) UUCP: seismo!umcp-cs!chris CSNet: chris@umcp-cs ARPA: chris@maryland
guy@sun.uucp (Guy Harris) (07/12/85)
> I found a way to initialize an array of characters without using a loop. ... > strncpy(blanks + 1, blanks, SIZE - 1); /* initialize entire array */ Ummm... there *is* a loop there; it just happens to be hidden in the "strncpy" routine. In some C libraries on some machines, this uses a faster sequence to copy the data than the fastest C loop. On other machines, "strncpy" is just the obvious C loop (and you pay the overhead of a subroutine call). On other machines, "strncpy" might not work with overlapped strings... The System V C library has a routine called "memset" which can be used to set a block of bytes to a specific value. Modulo the subroutine call overhead, this is probably the most efficent way of initializing the array (the "strncpy" has to fetch byte N to move it to byte N+1; the "memset" can keep that byte in a register). Guy Harris
bright@dataio.UUCP (Walter Bright) (07/12/85)
In article <899@teddy.UUCP> kps@teddy.UUCP (Kesavan P. Srinivasan) writes: >I found a way to initialize an array of characters without using a loop. > char blanks[SIZE]; /* declare array of SIZE elements */ > > blanks[0] = ' '; /* initialize 1st element */ > > strncpy(blanks + 1, blanks, SIZE - 1); /* initialize entire array */ > >The trick is to use strncpy in an almost recursive way. This will fail if strncpy() copies starting from the end of the source string, rather than from the beginning. You are depending on an undefined side effect of your implementation of strncpy(). Try using memset(): memset(blanks,' ',SIZE-1);
kps@teddy.UUCP (07/12/85)
char blanks[SIZE]; blanks[0] = ' '; strncpy(blanks + 1, blanks, SIZE - 1); /* initialize entire array */ Here's what people said about my method: From panda!talcott!harvard!stew >This is not portable. There is no guarantee that strncpy() copies >one char at a time in forward order. If it is implemented using the >VAX MOVC3 instruction, for example, the overlap of the source and >destination strings does NOT affect the result! From panda!genrad!decvax!harpo!whuxlm!whuxl!houxm!ihnp4!mhuxn!mhuxr!ulysses!allegra!alice!ark >Don't. There is no guarantee that strncpy copies one character at a time. From panda!talcott!harvard!seismo!umcp-cs!chris >Beware, that won't work on Vax systems that use movc3 for string copies >(probably Sys VR2V2.2.2.2... [sorry :-)] and 4.3 both). From panda!genrad!decvax!harpo!whuxlm!whuxl!houxm!mtuxo!mtunh!mtung!mtunf!ariel!vax135!petsd!gangal >2) I don't know exactly what the standard C library does, but many > string copy routines (in micro-code or higher level) check > for overlapping strings and would process your request in reverse > to avoid just the recursion you want. (For instance, you may > have a string in there to which you want to prepend a character.) From panda!genrad!decvax!harpo!whuxlm!whuxl!houxm!mtuxo!mtunh!mgh > 2. it only works if strncpy is implemented by starting with the > first character to be moved and not the last (you can move > up and down a string in either direction). I.e. it's > implementation dependent; Well, as you can probably see, I've been bludgeoned to death with the fact that my method is implementation dependent and that it won't work all the time. I stand connected, er, I mean corrected. Thanks for a humbling experience, B.K.
smk@axiom.UUCP (Steven M. Kramer) (07/12/85)
> From: kps@teddy.UUCP > Subject: C programming hint > > The trick is to use strncpy in an almost recursive way. The problem in using strncpy for a ripple effect is that you are inferring a feature of the implementation of strncpy. For those systems that implement it using a machine instruction or otherwise semantically differently than you are used to, this will not work. It certainly is not portable. -- --steve kramer {allegra,genrad,ihnp4,utzoo,philabs,uw-beaver}!linus!axiom!smk (UUCP) linus!axiom!smk@mitre-bedford (MIL)
brent@cadovax.UUCP (Brent Rector) (07/12/85)
In article <899@teddy.UUCP> kps@teddy.UUCP (Kesavan P. Srinivasan) writes: >I found a way to initialize an array of characters without using a loop. >Here is the method I used: > > char blanks[SIZE]; /* declare array of SIZE elements */ > > blanks[0] = ' '; /* initialize 1st element */ > > strncpy(blanks + 1, blanks, SIZE - 1); /* initialize entire array */ > ^^^ ^^^ ^^^ > | | | > destination source how many characters to copy > It seems to me that all you have done is to move the loop into the strncpy function at the cost of additional procedure call. Also while I expect the above will generally work I can think of a couple of bizarre ways to implement strncpy that would cause the above to fail. In general I think overlapped moves produce machine dependent results. -- -------------------------------------------------------------- Brent E. Rector - CONTEL CADO, Torrance, CA { decvax, hplabs, ihnp4, ucbvax, sdcrdcf }!trwrb!cadovax!brent { onecom, philabs, scgvaxd, ttidca, ucla-cs }!cadovax!brent cadovax!brent@ucla-locus.ARPA
bo@enea.UUCP (Bo Steinholtz) (07/12/85)
In article <899@teddy.UUCP> kps@teddy.UUCP (Kesavan P. Srinivasan) writes: >I found a way to initialize an array of characters without using a loop. >Here is the method I used: > > char blanks[SIZE]; /* declare array of SIZE elements */ > > blanks[0] = ' '; /* initialize 1st element */ > > strncpy(blanks + 1, blanks, SIZE - 1); /* initialize entire array */ > ^^^ ^^^ ^^^ > | | | > destination source how many characters to copy Ah, how the heart of an old assembler language programmer rejoices! For another description of this trick, see e.g. the description of the MVC machine instruction in "IBM System/360 Principles of Operation" from the sixties, where it is pointed out that it may be employed to initialize an array in one machine instruction. However, the most authoritative (?) source on C, Harbison/Steele: "C: A Reference Manual", Prentice-Hall 1984, states in the definition of strncpy that: "The results are unpredictable if the two string arguments overlap in memory." Thus, if strncpy is used, the trick is nonportable!
ed@zinfandel.UUCP (Ed Hirgelt) (07/13/85)
I may be mistaken, but this hint also has a problem in not null terminating the string. strncpy stops at the first null character or when the count is exceeded. Since the initial version of the string has no null, one is never added to the string. This may be what the poster intended, but he should never use that string with any of the other string utilities (like strcmp, etc.) -- Ed Hirgelt Zehntel Automation Systems {ihnp4 ucbvax}!zehntel!ed 2625 Shadelands Drive zehntel!ed@Berkeley.ARPA Walnut Creek, Ca 94598
root@bu-cs.UUCP (Barry Shein) (07/13/85)
I remember teaching that strncpy hack...except it was: mvi str,c' ' mvc str+1(length-1),str hey, if you're gonna make it machine-dependant !MAKE IT MACHINE DEPENDANT! (where's my green card...) -Barry Shein, Boston University
ags@pucc-h (Dave Seaman) (07/13/85)
In article <476@mtunh.UUCP> mgh@mtunh.UUCP (Marcus Hand) writes (Concerning "almost recursive" use of strncpy): > Sorry to dissapoint you, but... > > 3. its not recursive or even analogous to recursion -- it just > keeps copying the last character it moved; The operation blanks[0] = ' ' blanks[i] = blanks[i-1] for i = 1,2,...,SIZE-1 is recursive in the mathematical sense, just as the familiar definition of the factorial function, fact(0) = 1 fact(n) = n * fact(n-1) for n > 0 is recursive. The fact that it is possible to fill an array with blanks or to compute the factorial function without resorting to functions or procedures that call themselves does not mean the underlying definitions are not recursive. Both operations also have nonrecursive definitions: blanks[i] = ' ' for i = 1,2,...,SIZE-1 fact(n) = GAMMA(n+1) for n = 0,1,2, ... ------------------------------------------------------------------------- >> char blanks[SIZE]; /* declare array of SIZE elements */ >> >> blanks[0] = ' '; /* initialize 1st element */ >> >> strncpy(blanks + 1, blanks, SIZE - 1); /* initialize entire array */ >> ^^^ ^^^ ^^^ >> | | | >> destination source how many characters to copy >> >> The trick is to use strncpy in an almost recursive way. >> Well, I hope you found this useful. -- Dave Seaman ..!pur-ee!pucc-h:ags
gam@amdahl.UUCP (G A Moffett) (07/14/85)
In article <899@teddy.UUCP> kps@teddy.UUCP (Kesavan P. Srinivasan) writes: >I found a way to initialize an array of characters without using a loop. >Here is the method I used: > > char blanks[SIZE]; /* declare array of SIZE elements */ > > blanks[0] = ' '; /* initialize 1st element */ > > strncpy(blanks + 1, blanks, SIZE - 1); /* initialize entire array */ This is machine-dependent so don't expect this to be portable. Generally speaking, you shouldn't use the string library functions on overlapping strings. -- Gordon A. Moffett ...!{ihnp4,cbosgd,hplabs}!amdahl!gam
gwyn@BRL.ARPA (VLD/VMB) (07/14/85)
Warning! The behavior of strncpy() on overlapping strings is undefined. Many implementations of strncpy() use a "block move" machine instruction, which may or may not work the way you expect when the source and destination overlap.
hamilton@uiucuxc.Uiuc.ARPA (07/15/85)
re: clever string fill it's bad enough that his nifty idea is "wrong", but it ain't new either. i'm sure i've seen that trick used in ibm 1401 autocoder...
gupta@asgb.UUCP (Yogesh K Gupta) (07/15/85)
> I found a way to initialize an array of characters without using a loop. > Here is the method I used: > > char blanks[SIZE]; /* declare array of SIZE elements */ > > blanks[0] = ' '; /* initialize 1st element */ > > strncpy(blanks + 1, blanks, SIZE - 1); /* initialize entire array */ > ^^^ ^^^ ^^^ > | | | > destination source how many characters to copy > > The trick is to use strncpy in an almost recursive way. > Well, I hope you found this useful. Unfortunately, strncpy uses the "loop" that you are trying to avoid. It also makes a redundant (in this case) check for the null character each time through the loop that should be avoided. -- Yogesh Gupta Advanced Systems Group, {sdcrdcf, sdcsvax}!bmcg!asgb!gupta Burroughs Corp., Boulder, CO. -------------------------------------------------------------------- All opinions contained in this message are my own and do not reflect those of my employer or the plant on my desk.
mah@asgb.UUCP (Mark Hamilton) (07/15/85)
> > I found a way to initialize an array of characters without using a loop. > > Here is the method I used: > > > > char blanks[SIZE]; /* declare array of SIZE elements */ > > > > blanks[0] = ' '; /* initialize 1st element */ > > > > strncpy(blanks + 1, blanks, SIZE - 1); /* initialize entire array */ > > ^^^ ^^^ ^^^ > > | | | > > destination source how many characters to copy > > > > The trick is to use strncpy in an almost recursive way. > > Well, I hope you found this useful. > > Unfortunately, strncpy uses the "loop" that you are trying to avoid. It > also makes a redundant (in this case) check for the null character each time > through the loop that should be avoided. One would hope that the compiler (or optimizer) would realize what's going on here, and do something a little more clever than looping. Especially since this is a strncpy, so the check for the null character isn't done. I must admit that I am new to Unix C, but on VMS (and I beleive TOPS20, for whoever uses that) C, the compiler will turn this into a MOVC instruction (or a BLT on the '20). These are both the accepted method for filling a region. Mark Hamilton -- The opinions expessed above are -- or maybe they aren't... Mark Hamilton - Burroughs Advanced Systems Group Boulder, CO 80301 ihnp4!sdcsvax!bmcg!asgb!mah
stew@harvard.ARPA (Stew Rubenstein) (07/17/85)
In article <730@asgb.UUCP> seismo!hao!asgb!mah (Mark Hamilton) writes: >> > I found a way to initialize an array of characters without using a loop. >> > Here is the method I used: >> > strncpy(blanks + 1, blanks, SIZE - 1); /* initialize entire array */ >> >> Unfortunately, strncpy uses the "loop" that you are trying to avoid. It >> also makes a redundant (in this case) check for the null character each time >> through the loop that should be avoided. > >One would hope that the compiler (or optimizer) would realize what's >going on here, and do something a little more clever than looping. >Especially since this is a strncpy, so the check for the null character >isn't done. I must admit that I am new to Unix C, but on VMS (and I >beleive TOPS20, for whoever uses that) C, the compiler will turn this >into a MOVC instruction (or a BLT on the '20). These are both the accepted >method for filling a region. > >Mark Hamilton You are dreaming if you think that the compiler will turn a function call into a single inline instruction. This is an admirable dream, but a dream nonetheless. This gets compiled (by VMS VAX-11 C Version 2.0) into a subroutine call. There's no way to assure the compiler that this strncpy is going to be pulled from the standard run-time library. Suppose you wanted to replace the standard strncpy (or more likely some other standard library function, like malloc) with your own for some reason (debugging? better error handling?) Now won't you be annoyed if the compiler optimizes this function call away? Anyone know of any efforts to standardize an indication to the compiler that it is or is not OK to compile standard library functions in-line? Stew {seismo,ut-sally}!harvard!rubenstein
johnston@uiucdcsb.Uiuc.ARPA (07/18/85)
/* Written 2:04 pm Jul 10, 1985 by kps@teddy.UUCP in uiucdcsb:net.lang.c */
/* ---------- "C programming hint" ---------- */
I found a way to initialize an array of characters without using a loop.
Here is the method I used:
char blanks[SIZE]; /* declare array of SIZE elements */
blanks[0] = ' '; /* initialize 1st element */
strncpy(blanks + 1, blanks, SIZE - 1); /* initialize entire array */
^^^ ^^^ ^^^
| | |
destination source how many characters to copy
The trick is to use strncpy in an almost recursive way.
Well, I hope you found this useful.
/* End of text from uiucdcsb:net.lang.c */
lcc.niket@UCLA-LOCUS.ARPA (Niket K. Patwardhan) (07/19/85)
I scanned the C standards draft a while ago and remembered there was something about builtins. Well, I went back and checked, and found there isn't any declaration as such, but it does say (Page 68, Introduction of Library section) that "One implication of this restriction <....external identifiers starting with _ are reserved ....> is that implementations may provide special semantics for names starting with underscore. For example, _builtin_abs could be used to <.....define an inline abs>." It also warns that any function defined in a header file could be a macro, and that if you wanted your own function you should use the #undef directive to nullify any such macro definition before using your function. Thus an implementor says #define abs _builtin_abs in his header file, and users would get the builtin abs normally. If they wanted to use their own abs, they would #undef abs before using it.
lum@osu-eddie.UUCP (Lum Johnson) (07/19/85)
In article <913@teddy.UUCP> kps@teddy.UUCP writes: > > char blanks[SIZE]; > blanks[0] = ' '; > strncpy(blanks + 1, blanks, SIZE - 1); /* initialize entire array */ > > ... I've been bludgeoned to death with the fact that my method is > implementation dependent and that it won't work all the time. This actually works in assembly language for the PDP-10. movei t1," " ; put <SPACE> in reg movem t1,blanks ; deposit char in buffer move t1,[blanks,,blanks+1] ; control register for blt blt t1,blanks+size ; propagate char over buffer The BLT iterates the copy-previous-char operation (specified in t1), incrementing both halves of the control register (t1) until blanks+size is reached. Lum Johnson ..!cbosgd!osu-eddie!lum or lum@osu-eddie.uucp
joemu@nsc-pdc.UUCP (Joe Mueller) (07/19/85)
> > I found a way to initialize an array of characters without using a loop. > > Here is the method I used: > > > > char blanks[SIZE]; /* declare array of SIZE elements */ > > > > blanks[0] = ' '; /* initialize 1st element */ > > > > strncpy(blanks + 1, blanks, SIZE - 1); /* initialize entire array */ > > ^^^ ^^^ ^^^ > > | | | > > destination source how many characters to copy > > > > The trick is to use strncpy in an almost recursive way. > > Well, I hope you found this useful. > > Unfortunately, strncpy uses the "loop" that you are trying to avoid. It > also makes a redundant (in this case) check for the null character each time > through the loop that should be avoided. > > I would hope that the compiler (or optimizer) would realize what's > going on here, and do something a little more clever than looping. > especially since this is a strncpy, so the check for the null character > isn't done. I must admit that I am new to Unix C, but on VMS (and I > beleive TOPS20, for whoever uses that) C, the compiler will turn this > in to a MOVC instruction (or a BLT on the '20). These are both the accepted > method for filling a region. The most effecient way to initialize an array (or anything else) to anything but zeros is to use the initializer construct. If you need it to be zeros, any global will default to zero fill. This will only work for globals in most current compilers but the new ansi standard will (I believe) allow initialization of automatic aggregates as long as the initializer consists of constant expressions and doesn't make any subroutine calls or use variables. The following lines would initialize your blanks array as long as it has global scope (not in a function): char blanks[SIZE] = { ' ', ' ', ' ', ' ', ' ' }; /* 5 blanks */ char blanks[SIZE] = " "; /* 5 blanks */ This assumes a SIZE of 5, but you can do it for any SIZE; You can even skip your array dimention like this: char blanks[] = " "; /* 5 blanks */ If you want to know what I meant by the comments about the standard, let me illustrate: foo() { int bar[3] = { 3, 4, 5}; /* legal */ int baz[3] = { random(), open("foobar", O_RDONLY), bar[1]}; /* illegal */ }
joemu@nsc-pdc.UUCP (Joe Mueller) (07/19/85)
> Anyone know of any efforts to standardize an indication to the compiler > that it is or is not OK to compile standard library functions in-line? > > Stew > {seismo,ut-sally}!harvard!rubenstein The committee discussed the question and decided that it should be done within the realm of "# pragma" lines. This means that any compiler may offer this feature but it will not be something that will be standardized. The # pragma line was added to the standard to give implementors an easy way to turn switches on or off in the compiler without adding new keywords. The line could be something like: # pragma inline strncpy, sin, cos, absf The # pragma directive is discussed in section C.8.5 of the draft. It doesn't say much other than it causes implementation defined things to occur. By the way, if anyone wants a copy of the draft, I believe it's now available for informal public comment through CEBEMA for about $20. If there's enough interrest, I'll try to find the address to send your money to.
guy@sun.uucp (Guy Harris) (07/23/85)
> The most effecient way to initialize an array (or anything else) to anything > but zeros is to use the initializer construct. Only if you are initializing the array (or whatever) at initial execution time for a non-"auto" array, or at procedure entry time for an "auto" array. If, for example, you want to initialize it each time through a loop, this won't work. Guy Harris
peter@baylor.UUCP (Peter da Silva) (07/25/85)
> In article <913@teddy.UUCP> kps@teddy.UUCP writes: > > > > char blanks[SIZE]; > > blanks[0] = ' '; > > strncpy(blanks + 1, blanks, SIZE - 1); /* initialize entire array */ > > > > ... I've been bludgeoned to death with the fact that my method is > > implementation dependent and that it won't work all the time. > > This actually works in assembly language for the PDP-10. > And of course it's the STANDARD method of initialising an array in FORTH: : fill over c! dup 1+ cmove ; -- Peter da Silva (the mad Australian) UUCP: ...!shell!neuro1!{hyd-ptd,baylor,datafac}!peter MCI: PDASILVA; CIS: 70216,1076
tim@callan.UUCP (Tim Smith) (07/30/85)
> char blanks[SIZE]; /* declare array of SIZE elements */ > > blanks[0] = ' '; /* initialize 1st element */ > > strncpy(blanks + 1, blanks, SIZE - 1); /* initialize entire array */ Danger Will Robinson! Danger Will Robinson! Non-portable contruct. Unsafe assumptions about implementation of strncpy. Danger Will Robinson! If strncpy is done in assembly for efficiency, and the machine has a block tranfer instruction, and the author of strncpy used it, and the machine is smart about copying strings, then the above will fail, because the machine will recognize that the source and destinations overlap, with the destination above the source, so it will copy the string from the back. -- Tim Smith ihnp4!{cithep,wlbr!callan}!tim