a dumb strcat question

D

David Frank

How can I write a string function that encloses the input string
in quotes "string" ??
below works for the "123 operation but adding " to it
clobbers the "123


main()
{
char *sfun(char *);
printf("%s",sfun("123"));
}

char *sfun(char *s)
{
static char *quote = "\"";
char *outs;
outs = quote;
strcat(outs,s); // outs = "123
strcat(outs,quote); // outs = nada why?
return (outs);
}
 
J

Joona I Palaste

David Frank said:
How can I write a string function that encloses the input string
in quotes "string" ??
below works for the "123 operation but adding " to it
clobbers the "123

main()
{
char *sfun(char *);
printf("%s",sfun("123"));
}
char *sfun(char *s)
{
static char *quote = "\"";
char *outs;
outs = quote;
strcat(outs,s); // outs = "123

No. This causes undefined behaviour by modifying a literal string.
strcat(outs,quote); // outs = nada why?

Well, if we assume that the above strcat call succeeded (and did
what you thought it did), then outs==quote will still be true,
so this call is effectively strcat(outs, outs). strcatting a string
onto itself is quite an interesting thing to try...
return (outs);
}

Perhaps you could try this?

char *sfun(char *s)
{
char *outs = malloc(strlen(s)+3);
if (outs) {
sprintf(outs, "\"%s\"", s);
}
return outs;
}
 
T

those who know me have no need of my name

in comp.lang.c i read:
How can I write a string function that encloses the input string
in quotes "string" ??

how? you could learn c. since this isn't likely, and for reasons even i
cannot understand, i will therefore provide you with such a function:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/*
`quote' the input string. existing quoting is not escaped.
returns fresh storage, caller is responsible for disposal.
*/
char *sfun(const char *const s)
{
char *new = malloc(strlen(s) + 3);
if (0 != new) sprintf(new, "\"%s\"", s);
return new;
}

example usage:

#include <stdio.h>
#include <stdlib.h>
char *sfun(const char * const s);
int main(void)
{
char *p = "some string", *q = sfun(p);
fputs("original : ", stdout); puts(p);
fputs("processed: ", stdout); puts(q);
free(q);
return 0;
}
 
D

David Frank

Joona I Palaste said:
No. This causes undefined behaviour by modifying a literal string.


Well, if we assume that the above strcat call succeeded (and did
what you thought it did), then outs==quote will still be true,
so this call is effectively strcat(outs, outs). strcatting a string
onto itself is quite an interesting thing to try...


Perhaps you could try this?

char *sfun(char *s)
{
char *outs = malloc(strlen(s)+3);
if (outs) {
sprintf(outs, "\"%s\"", s);
}
return outs;
}

--
/-- Joona Palaste ([email protected]) ------------- Finland --------\
\-- http://www.helsinki.fi/~palaste --------------------- rules! --------/
"Shh! The maestro is decomposing!"
- Gary Larson

The malloc statement above gets a warning (below), but the routine
outputs "123" as requested, the following warning is a constant
bane in ALL my attempts at C programming and is a chief reason
I remain a Fortran programmer.
(kinda makes me <smile> to see it bite experienced C programmers)
THANKS!!


test.c(8) : warning C4047: 'initializing' : 'char *' differs in levels
of indirection from 'int '
Microsoft (R) Incremental Linker Version 6.00.8447
Copyright (C) Microsoft Corp 1992-1998. All rights reserved.

/out:test.exe
test.obj
 
D

David Frank

Joona I Palaste said:
strcatting a string
onto itself is quite an interesting thing to try...

Since its a function, not a subroutine, I dont understand thats
whats happening..

Perhaps the fortran function below I am trying to translate to C
will explain further, (note no MALLOC is required)..



program varying_string_output
write (*,*) enclose('123'),',' ! outputs "123",
write (*,*) enclose('the lazy dog'),',' ! outputs "the lazy dog",
stop

contains
function enclose(s1) result(s2)
character(*) :: s1
character(len_trim(s1)+2) :: s2 ! output length = input length+2
s2 = '"' // trim(s1) // '"' ! enclose "string" in quotes
end function
end program
 
N

nrk

David said:
The malloc statement above gets a warning (below), but the routine
outputs "123" as requested, the following warning is a constant
bane in ALL my attempts at C programming and is a chief reason
I remain a Fortran programmer.
(kinda makes me <smile> to see it bite experienced C programmers)
THANKS!!


test.c(8) : warning C4047: 'initializing' : 'char *' differs in levels
of indirection from 'int '
Microsoft (R) Incremental Linker Version 6.00.8447
Copyright (C) Microsoft Corp 1992-1998. All rights reserved.

/out:test.exe
test.obj
Probably the most obscure warning for a missing function prototype you can
get. What the compiler is trying to tell u[*] here is that you've
forgotten to add "#include <stdlib.h>" (which has the prototype for malloc)
in your code. I know for certain that Joona knows he has to include
stdlib.h to use malloc. Sometimes however, we don't make enough allowance
for a newbie's lack of knowledge :)

-nrk.

[*] - My nod to Joona's masterful troll. There Joona, another Indian
satisfying your stereotype :)
 
J

Joona I Palaste

Since its a function, not a subroutine, I dont understand thats
whats happening..
Perhaps the fortran function below I am trying to translate to C
will explain further, (note no MALLOC is required)..

Sorry, my experience in Fortran is exactly zilch. Some really high
programming guru, please explain the difference to both of us.
 
C

CBFalconer

David said:
How can I write a string function that encloses the input string
in quotes "string" ??

Is there a problem with: printf("\"%s\"", thestring);

(or similar with sprintf to an internal string).
 
C

Christian Bau

"David Frank said:
The malloc statement above gets a warning (below), but the routine
outputs "123" as requested, the following warning is a constant
bane in ALL my attempts at C programming and is a chief reason
I remain a Fortran programmer.

That is probably a good idea until you've figured out why you get a
warning. (Actually, you only get a warning because the compiler you are
using compiles some completely illegal C code while only producing a
warning).
 
B

bd

David said:
The malloc statement above gets a warning (below), but the routine
outputs "123" as requested, the following warning is a constant
bane in ALL my attempts at C programming and is a chief reason
I remain a Fortran programmer.
(kinda makes me <smile> to see it bite experienced C programmers)
THANKS!!


test.c(8) : warning C4047: 'initializing' : 'char *' differs in levels
of indirection from 'int '
Microsoft (R) Incremental Linker Version 6.00.8447
Copyright (C) Microsoft Corp 1992-1998. All rights reserved.

/out:test.exe
test.obj

Are you compiling in C++ mode? That might cause such a warning. Which line
was line 8 in your test program?
 
D

David Frank

bd said:
David Frank wrote:



Were you compiling in C++ mode? That might cause such a warning. Which
line was line 8 in your test program?


statement 8 is like i said, the malloc statement
I dont even know how to invoke C++ mode,
I used the following compile command, and dont even know
a alternative (I very seldom invoke my limited C knowledge)..

CL test.c
 
K

Kevin Goodsell

bd said:
Are you compiling in C++ mode? That might cause such a warning. Which line
was line 8 in your test program?

No, it almost certainly would not give a warning. It would give an error
and halt compilation. That is, all implementations I've heard of would
almost certainly do that. The C++ standard only required a "diagnostic",
of course. But I've never heard of a compiler accepting a constraint
violation with only a warning.

The problem is obviously that malloc is not declared. In C++ and C99,
that would make calling it an error. In C prior to C99, it implicitly
declares the function with return type int.

Arguably, the main issue here is the quality of the compiler. Warning
about an implicit function declaration is pretty standard fare for most
good compilers.

-Kevin
 
S

Simon Biber

Kevin Goodsell said:
But I've never heard of a compiler accepting a constraint
violation with only a warning.

Really?

int main(void)
{
char *p = 0;
unsigned char *q = p; /* CONSTRAINT VIOLATION */
return 0;
}

C:\docs\prog\c>gcc -ansi -pedantic suchar.c
suchar.c: In function `main':
suchar.c:4: warning: pointer targets in initialization differ in signedness

BCC 5.5 appears to require the argument -wucp to specifically
enable this 'warning'. It is not mentioned in the documentation
that it is necessary to specify that argument to implement a
conforming ANSI C compiler.

LCC 3.8, with both the -A (activate all warnings) and -ansic
(disallow the language extensions of lcc-win32) appears not
to generate any diagnostic at all (making it non-conforming).
 
G

glen herrmannsfeldt

David said:
How can I write a string function that encloses the input string
in quotes "string" ??
below works for the "123 operation but adding " to it
clobbers the "123

There are three different ways to write C functions that return
strings, none of them 100% perfect.

1) Return a pointer to a static string
2) Use a user supplied character array
3) Return a pointer supplied by malloc()

Once you decide which of those you want to use, it is easy to write.

-- glen
 
D

David Frank

glen herrmannsfeldt said:
There are three different ways to write C functions that return
strings, none of them 100% perfect.

1) Return a pointer to a static string
2) Use a user supplied character array
3) Return a pointer supplied by malloc()

Once you decide which of those you want to use, it is easy to write.

-- glen

Perhaps the fortran function below I am trying to translate to C
will explain further, (note no MALLOC is required)..

program varying_string_output
write (*,*) enclose('123'),',' ! outputs "123",
write (*,*) enclose('the lazy dog'),',' ! outputs "the lazy dog",
stop

contains
function enclose(s1) result(s2)
character(*) :: s1
character(len_trim(s1)+2) :: s2 ! output length = input length+2
s2 = '"' // trim(s1) // '"' ! enclose "string" in quotes
end function
end program
 
A

Arthur J. O'Dwyer

Perhaps the fortran function below I am trying to translate to C
will explain further, (note no MALLOC is required)..

Well, apparently the Fortran function below *doesn't* help; not
enough, anyway, because you've posted it twice now and I don't
think anyone's really solved your problem. So maybe you should
try to explain your question in one of the languages more commonly
used on this newsgroup, such as C or English. (Heck, German would
probably get the job done, too, but it wouldn't be as welcomed as
English. ;-)
I'm going to try to decode your program anyway, and you can tell
me if I get it right.
program varying_string_output
write (*,*) enclose('123'),',' ! outputs "123",

Since writing a C program to output "123" is trivial, I assume
you're wanting to write a C function that takes a string such as
'123' and encloses it in quotes: '"123"', like that.
write (*,*) enclose('the lazy dog'),',' ! outputs "the lazy dog",
stop

contains
function enclose(s1) result(s2)
character(*) :: s1
character(len_trim(s1)+2) :: s2 ! output length = input length+2
s2 = '"' // trim(s1) // '"' ! enclose "string" in quotes

I don't know what 'trim(s1)' does, but I'll assume that 'trim' is
a no-op in this context.
end function
end program


So three ways of doing this are

/* Fails if the user passes a 'src' longer than MAX_STRING_LENGTH;
* each call overwrites the old string */
const char *enclose(const char *src)
{
static char buffer[MAX_STRING_LENGTH];
if (strlen(src)+3 > sizeof buffer)
return NULL;
sprintf(buffer, "\"%s\"", src);
return buffer;
}

/* Undefined behavior if the user passes an invalid 'dst' */
char *enclose(const char *src, char *dst)
{
sprintf(dst, "\"%s\"", src);
return dst;
}

/* Fails if malloc fails; user must free() the supplied string */
char *enclose(const char *src)
{
char *p = malloc(strlen(src)+3);
if (p != NULL)
sprintf(p, "\"%s\"", src);
return p;
}


Note that in *none* of these cases can you write

printf("%s %s\n", enclose("abc"), enclose("def"));

and have it work correctly. In Case 1, you get unspecified
behavior because both calls to 'enclose' are trying to write
on the same chunk of memory. In Case 2, you just flat out are
supplying the wrong number of arguments. And in Case 3, it works
just fine -- but you have a memory leak because you never 'free()'
the allocated strings. The correct use of each function might be

/* Case 1 */
printf("%s ", enclose("abc")); /* get a semicolon between them */
printf("%s\n", enclose("def"));

/* Case 2 */
char p[4], q[4];
printf("%s %s\n", enclose("abc", p), enclose("def", q));

/* Case 3 */
char *p = enclose("abc");
char *q = enclose("def");
printf("%s %s\n", p, q);
free(p);
free(q);

Which of these methods you use depends on your personal style
and the convenience of each of them for your particular project.

HTH,
-Arthur
 
C

Chris Torek

an existing string]
/* Case 2 */
char p[4], q[4];
printf("%s %s\n", enclose("abc", p), enclose("def", q));

Actually, p and q both need to be at least 6 elements long,
because "\"abc\"" and "\"def\"" both have a strlen() of 5,
and as always, it takes N+1 characters to store a string
whose strlen() is N.
 
C

CBFalconer

Arthur J. O'Dwyer said:
.... snip ...

Note that in *none* of these cases can you write

printf("%s %s\n", enclose("abc"), enclose("def"));

and have it work correctly. In Case 1, you get unspecified
behavior because both calls to 'enclose' are trying to write
on the same chunk of memory. In Case 2, you just flat out are

Wanna bet? I can make that printf work for static allocations,
with some limitations. The secret is a limited set of internal
buffers, used in sequence, with automatic initialization.

/* The limitations */
#define BUFMAX 128
#define BUFCNT 4

#include <stdlib.h>

struct buf {
struct buf *next;
char *ch;
};

char *enclose(const char *s)
{
static struct buf *cp;
struct buf *p;
int i;

if (NULL == cp) {
for (i = 0; i < BUFCNT; i++) {
if (p = malloc(sizeof *p)) {
p->next = cp;
if (p->ch = malloc(BUFMAX)) cp = p;
else {
free(p);
break;
}
}
}
p = cp;
while (p->next) p = p->next;
p->next = cp;
}
cp = cp->next;
/* Use cp->ch to form the 'enclosed' string */
return cp->ch;
} /* untested */

We can avoid malloc, with less flexibility, using static arrays of
char buffers and next pointers and a static index.

This method of using a limited set of internal buffers has many
applications. It concentrates the time consuming and failure
prone operations of forming the buffers at initialization time, so
it is quite suitable for embedded machines. Just call the routine
at least once during startup.
 
A

Alan J. McFarlane

nrk said:
David said:
Joona I Palaste said:
David Frank <[email protected]> scribbled the following:
[...]
test.c(8) : warning C4047: 'initializing' : 'char *' differs in
levels of indirection from 'int '
Microsoft (R) Incremental Linker Version 6.00.8447
Copyright (C) Microsoft Corp 1992-1998. All rights reserved.

/out:test.exe
test.obj
Probably the most obscure warning for a missing function prototype
you can get. What the compiler is trying to tell u[*] here is that
you've forgotten to add "#include <stdlib.h>" (which has the
prototype for malloc) in your code. I know for certain that Joona
knows he has to include stdlib.h to use malloc. Sometimes however,
we don't make enough allowance for a newbie's lack of knowledge :)
David. Like with most compilers, when you use MSVC's cl.exe you should
always supply some command-line options to have it behave 'better'.
Otherwise use the IDE, it should default such options. I always run with
warning level 3 or sometimes 4, and you should also disable language
extensions. You can default these by doing "set CL=/W3 /Za" before running
the compiler. This will normally make it easier to understand what's going
on.

Compiling the above code thus gives much more useful output: noting the lack
of declarations for the three library functions.

C:\>cl /W4 /Za clc6.c
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 12.00.8168 for 80x86
Copyright (C) Microsoft Corp 1984-1998. All rights reserved.

clc6.c
clc6.c(4) : warning C4013: 'malloc' undefined; assuming extern returning int
clc6.c(4) : warning C4013: 'strlen' undefined; assuming extern returning int
clc6.c(4) : warning C4047: 'initializing' : 'char *' differs in levels of
indirection from 'int '
clc6.c(6) : warning C4013: 'sprintf' undefined; assuming extern returning
int
Microsoft (R) Incremental Linker Version 6.00.8168
Copyright (C) Microsoft Corp 1992-1998. All rights reserved.

/out:clc6.exe
clc6.obj
LIBC.lib(crt0.obj) : error LNK2001: unresolved external symbol _main
clc6.exe : fatal error LNK1120: 1 unresolved externals
 
A

Arthur J. O'Dwyer

["enclose" function snipped, but note that it adds 2 more bytes to
an existing string]
/* Case 2 */
char p[4], q[4];
printf("%s %s\n", enclose("abc", p), enclose("def", q));

Actually, p and q both need to be at least 6 elements long,
because "\"abc\"" and "\"def\"" both have a strlen() of 5,
and as always, it takes N+1 characters to store a string
whose strlen() is N.

Yes, of course you're right. I forgot what 'enclose' was
doing, there. :-(

-Arthur
 

Ask a Question

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

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

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,768
Messages
2,569,574
Members
45,048
Latest member
verona

Latest Threads

Top