is this correct

D

Darklight

Question taken from a book
Write a function that accepts two strings. Use the malloc()
function to allocate enough memory to hold two strings after
they have been concatenated(linked). Return a pointer to this
new string.

/* STRCAT1.C PROGRAM TO LINK TWO STRINGS TOGETHER */
#include<stdio.h>
#include<string.h>
#include<stdlib.h>

char *join(char *, char *);

int main(void)
{
char str[ ] = {"hello"};
char str1[ ] = {" world!"};
char *c;

c = join(str, str1);
printf("%s\n",c);

return 0;
}

char *join(char *a, char *b)
{
char *link;
link = (char *)malloc(15 * sizeof(char));
/* or use: link = (char*) malloc(15); */
link = strcat(a, b);

return link;
}
 
M

Martin Dickopp

Darklight said:
Question taken from a book
Write a function that accepts two strings. Use the malloc()
function to allocate enough memory to hold two strings after
they have been concatenated(linked). Return a pointer to this
new string.

[...]


char *join(char *a, char *b)
{
char *link;
link = (char *)malloc(15 * sizeof(char));
/* or use: link = (char*) malloc(15); */

The cast is unnecessary and should be dropped.

This call to `malloc' always allocates 15 bytes. That is not enough to
hold the concatenation of any two strings.

Also, check if `malloc' returns a null pointer, which indicates that the
memory could not be allocated.
link = strcat(a, b);

This is not how `strcat' works. It appends the string pointed to by the
second argument to the string pointed to by the first argument, and
returns the first argument. The way you use it, it tries to append `b'
to `a' and returns `a', overwriting the previous value of `link'.
return link;
}

Here is how such a function could be written:


char *join (const char *const a, const char *const b)
{
/* Length of first string. */
const size_t len_a = strlen (a);

/* Length of second string. */
const size_t len_b = strlen (b);

/* Allocate enough memory for both strings
plus terminating null character. */
char *const link = malloc (len_a + len_b + 1);


if (link != NULL)
{
/* Copy first string to new memory. */
strcpy (link, a);

/* Copy second string to new memory: link + len_a is the address
of the end (the terminating null character) of the copy of
the first string. */
strcpy (link + len_a, b);
}

return link;
}


Martin
 
D

Darklight

Thanks for that i forgot about the const key word
i am yet to understand built in functions but i will
get there in the end.
Thanks again
 
E

Emmanuel Delahaye

In 'comp.lang.c' said:
Question taken from a book
Write a function that accepts two strings. Use the malloc()
function to allocate enough memory to hold two strings after
they have been concatenated(linked). Return a pointer to this
new string.

/* STRCAT1.C PROGRAM TO LINK TWO STRINGS TOGETHER */
#include<stdio.h>
#include<string.h>
#include<stdlib.h>

char *join(char *, char *);

int main(void)
{
char str[ ] = {"hello"};
char str1[ ] = {" world!"};

A complicated way of writing:

char str[] = "hello";
char str1[] = " world!";
char *c;

c = join(str, str1);

the returned pointer being created by malloc(), it may be NULL:

if (c != NULL)
{
printf("%s\n",c);

the string being allocated, it must be freed:

free (c);
c = NULL; /* debug helper */
}
return 0;
}

char *join(char *a, char *b)

The function should accept constant strings too.

char *join (char const *a, char const *b)
{
char *link;
link = (char *)malloc(15 * sizeof(char));

- The cast is useless.
- sizeof (char) is 1 by definition.
- What the heck is that 15?
- If you are using dynamic allocation, it's time to do it smartly. strlen()
can help to compute the amount of necessary bytes to hold the destination
string. Just add one for the final 0...
/* or use: link = (char*) malloc(15); */
link = strcat(a, b);

No. Read your C-book again. the destination string must be 'link', and it
must be valid.
 
C

CBFalconer

Darklight said:
Question taken from a book
Write a function that accepts two strings. Use the malloc()
function to allocate enough memory to hold two strings after
they have been concatenated(linked). Return a pointer to this
new string.

You made a credible effort, and have gotten various good answers,
but I don't think the intent of the book question is to exercise
you on the use of standard library components, but rather to
exercise you on manipulations. So the following deliberately
limits itself to the malloc function, and generates the equivalent
to the strlen function because it is used multiple times.

#include <stdio.h> /* to make puts function accessible */
#include <stdlib.h> /* to make the malloc function accessible */

/* Similar to the strlen function. Study how it works */
size_t lenstr(const char *s)
{
const char *p;

p = s;
while (*p) p++;
return p - s;
} /* lenstr */

/* ---------------- */

char *join(const char *a, const char *b)
{
char *ans;
char *p;

/* Be sure you understand why there is a +1 here */
ans = malloc(lenstr(a) + lenstr(b) + 1);
if (ans) {
p = ans;
while (*a) *p++ = *a++; /* understand this line */
while (*b) *p++ = *b++;
*p = '\0'; /* and the reason for this line */
}
return ans;
} /* join */

/* ---------------- */

/* Test it */
int main(int argc, char **argv)
{
char *link;

if (argc != 3) puts("Usage: join arg1 arg2");
else {
link = join(argv[1], argv[2]);
if (NULL == link) puts("No memory available");
else {
puts(link);
free(link);
}
}
return 0;
} /* main - join */
 
A

Adrian de los Santos

Im just learning, (like everybody) so i hope my silly questions dont
bother you.

in this funcion.
char *join (const char *const a, const char *const b)

what puzzle me its the fact of the const keyword.

i suppose you are treating variables a and b as const since the
function does not modify them and this its like a "just to make sure",
right.

but what about the *const a ?

And what:

const char * const a

Means ?

create a constant pointer to a constant named a ?

since a its already a constant why put the constant again ?

i mean, what its the difference with:

char * const a

It will create a pointer to a constant called a, right ?. This way
since "a" its a constant it can't be modified, rigth ?

Thanks for your reply.
 
A

Arthur J. O'Dwyer

Im just learning, (like everybody) so i hope my silly questions dont
bother you.

You should read the c.l.c FAQ, and probably the
alt.comp.lang.learn.c-c++ FAQ, too. The latter you can find
at http://www.contrib.andrew.cmu.edu/~ajo/docs/, and the former
you can find in people's .sigs. (In other words, I'm too lazy to
look it up for you. Also try Google.)
These FAQs contain answers to Frequently Asked Questions, which
are pretty much what you've been asking here.
in this funcion.


what puzzle me its the fact of the const keyword.

i suppose you are treating variables a and b as const since the
function does not modify them and this its like a "just to make sure",
right.

Correct. 'const', used in this way, is purely stylistic, and
Martin is one of few people I know who use it. (Please don't snip
attributions -- we like to know who you're responding to, here.)
but what about the *const a ?

'*' means "<operand> is a pointer to <stuff>."
'const' means "<operand> is constant."
Thus, '* const a' means
"a is constant and is a pointer to <stuff>,"
where said:
And what [does]

const char * const a

[mean]?

"a is constant and is a pointer to a 'char' which is constant."
Or, in the usual English idiom,
"a is a const pointer to const char."
create a constant pointer to a constant named a ?

That's a little ambiguous, but if you group it right, yes. We
are creating a constant pointer, which points to a constant, and
that constant pointer is named 'a'.
char * const a

It will create a pointer to a constant called a, right?

Wrong. Here, 'a' is a constant pointer to 'char'. But the 'char'
to which it points is not const-qualified, so you can still write

*a = 42; /* Okay! */
*a = 43; /* Okay! */
*a = 44; /* Okay! */

But since 'a' is const-qualified, you cannot write

a = b; /* Invalid! */
++a; /* Invalid! */


The Rule of Const is as follows:

'const' modifies the thing on its right, always. In other words,
'const' acts a lot like a unary prefix operator in declarations.
Thus:

int const a; /* a is const-qualified */
int * const a; /* a is const-qualified */
int const *a; /* *a is const-qualified */
char (* const a)[42]; /* a is const-qualified */
char const (*a)[42]; /* (*a)[42] is const-qualified */
char (const * const a)[42]; /* both a and *a are const-qualified */

And there's one special ad-hoc "syntactic sugar" rule in C, which
is that a 'const' all the way on the left modifies the whole
expression as if it were to the right of the 'int' or 'char' or
whatever:

const void *p; /* This line is equivalent to */
void const *p; /* this one: in both cases *p is const-qualified */

HTH,
-Arthur
 
M

Martin Dickopp

Arthur J. O'Dwyer said:
Correct. 'const', used in this way, is purely stylistic, and
Martin is one of few people I know who use it.

Just to clarify - the above was part of a function definition.
I wouldn't have used the underlined qualifiers in a declaration that
isn't also a definition, where they would serve no useful purpose.

Martin
 
C

CBFalconer

Martin said:
Just to clarify - the above was part of a function definition.
I wouldn't have used the underlined qualifiers in a declaration that
isn't also a definition, where they would serve no useful purpose.

I think the underlined const are totally ridiculous. Altering
those parameters affects nothing outside the function, and the
const simply prevents using them for what they are,
pre-initialized local variables. This prevents writing a
statement like:

while (*b) *p++ = *b++;
 
M

Martin Dickopp

CBFalconer said:
I think the underlined const are totally ridiculous.

Well, that's my programming style. Whenever a variable is not supposed
to be modified, I const-qualify it.
Altering those parameters affects nothing outside the function, and
the const simply prevents using them for what they are,
pre-initialized local variables.

Actually, I apply the same rule to local variables and parameters:
I make both const when they're not supposed to be modified.
This prevents writing a statement like:

while (*b) *p++ = *b++;

Yes, the point of const is to prevent statements like this.

Martin
 
P

pete

CBFalconer said:
You made a credible effort, and have gotten various good answers,
but I don't think the intent of the book question is to exercise
you on the use of standard library components, but rather to
exercise you on manipulations. So the following deliberately
limits itself to the malloc function, and generates the equivalent
to the strlen function because it is used multiple times.

#include <stdio.h> /* to make puts function accessible */
#include <stdlib.h> /* to make the malloc function accessible */

/* Similar to the strlen function. Study how it works */
size_t lenstr(const char *s)
{
const char *p;

p = s;
while (*p) p++;
return p - s;
}

It has recently been emphasized to me, that ptrdiff_t,
which is the type of (p - s),
is not completely suitable for string lengths,
as strings may be longer than the maximum magnitude of ptrdiff_t.
 
C

CBFalconer

Martin said:
Well, that's my programming style. Whenever a variable is not supposed
to be modified, I const-qualify it.


Actually, I apply the same rule to local variables and parameters:
I make both const when they're not supposed to be modified.


Yes, the point of const is to prevent statements like this.

When you have no other use for the original b value, why?
 
C

CBFalconer

pete said:
It has recently been emphasized to me, that ptrdiff_t, which
is the type of (p - s), is not completely suitable for string
lengths, as strings may be longer than the maximum magnitude
of ptrdiff_t.

I rather doubt that any such anomaly will have any practical
effect. In effect it would mean that a string was longer than
(SIZE_MAX / 2). I don't thing strlen (or lenstr) are suitable
ways of finding its length. Concatenating two such strings
presents some problems also.
 
M

Martin Dickopp

CBFalconer said:
When you have no other use for the original b value, why?

I might have another use for the original pointer value, for example:

char *const p = malloc (len);
if (p != NULL)
{
/* image 150 lines of code here */
free (p);
}

Even if I don't, I might wonder, when I look at my code a few months
later, if I can rely on finding the original value in some variable or
paramater defined 150 lines further up. For consistency reasons, I apply
the same rule even to very short functions.

That said, I do agree that it looks ridiculous (and, more importantly,
could confuse newbies) in some five line example code snippet. Maybe I
should adopt a different style in clc postings. :)

Martin
 
E

Emmanuel Delahaye

In 'comp.lang.c' said:
Just to clarify - the above was part of a function definition.
I wouldn't have used the underlined qualifiers in a declaration that
isn't also a definition, where they would serve no useful purpose.

Agreed in theory, but the problem is that I know at last two C implementation
(VC++6 at level 4, and DIAB-C) that choke on

void f(int s);

void f(int const s)
{
}

Being a supporter of the 'const' thing, this is the reason why I just copy
the first line of the function an simply add a ';' to make it a separated
prototype.

void f(int const s);

After all, it doesn't harm, and it's simpler to be done.
 
E

Emmanuel Delahaye

In 'comp.lang.c' said:
That said, I do agree that it looks ridiculous (and, more importantly,
could confuse newbies) in some five line example code snippet. Maybe I
should adopt a different style in clc postings. :)

Please don't! I like it!
 
D

Darklight

Emmanuel Delahaye wrote:>> {
- The cast is useless.
- sizeof (char) is 1 by definition.
- What the heck is that 15?
- If you are using dynamic allocation, it's time to do it smartly.
strlen() can help to compute the amount of necessary bytes to hold the
destination string. Just add one for the final 0...

Yes char is 1 byte, so 15 * 1 = 15 bytes.
But in a post earlier by Martin Dickopp
he said it was not large enough to hold the
two strings.

So is this any better. I think it's a better
solution. i think i heve used strcat properly
this time.
I have to refresh on the const keyword.


char *join(char *a, char *b)
{
char *link = malloc(strlen(a) + strlen(b) + 1);
strcpy(link,a);
strcat(link," ");
strcat(link,b);

return link;
}
 
C

CBFalconer

Martin said:
I might have another use for the original pointer value, for example:

char *const p = malloc (len);
if (p != NULL)
{
/* image 150 lines of code here */
free (p);
}

This is a much different case from the incoming parameters
example. I was talking about both parameters and known no other
use.
Even if I don't, I might wonder, when I look at my code a few months
later, if I can rely on finding the original value in some variable
or paramater defined 150 lines further up. For consistency reasons,
I apply the same rule even to very short functions.

Should such a maintenance case occur, I suggest that:

1. The routine is too long.
2. The routine deals with too many entities.
3. Now is the time to add the const to the parameter. If it
raises no flags on trial recompilation the original value hasn't
been touched. If it does, we can restore the original parameter
definition, add a const temporary to save the value at entry, and
use that later. In either case the const goes. Code diddling has
been minimized. Most of the internal referances are to the
original parameter, and are thus clearer.

Remember, I am talking about function parameter values.
 
M

Martin Dickopp

Emmanuel Delahaye said:
Agreed in theory, but the problem is that I know at last two C implementation
(VC++6 at level 4, and DIAB-C) that choke on

void f(int s);

void f(int const s)
{
}

Being a supporter of the 'const' thing, this is the reason why I just copy
the first line of the function an simply add a ';' to make it a separated
prototype.

void f(int const s);

After all, it doesn't harm, and it's simpler to be done.

I had the same problem with a Unix compiler several years ago. Switching
to gcc wasn't an option then, so I used the same solution.

Martin
 
M

Martin Dickopp

Darklight said:
Emmanuel Delahaye wrote:>> {

Yes char is 1 byte, so 15 * 1 = 15 bytes.
But in a post earlier by Martin Dickopp
he said it was not large enough to hold the
two strings.

No, I said it is not large enough to hold the concatenation of /any/ two
strings.

In fact, 15 bytes was enough to hold the concatenation of the two
strings you passed to the function in your example program. But it is an
extremely bad idea to design a function with specific argument values in
mind. Therefore, you should write your `join' function such that it
works correctly for /any/ two strings.
char *join(char *a, char *b)
{
char *link = malloc(strlen(a) + strlen(b) + 1);
strcpy(link,a);
strcat(link," ");
strcat(link,b);

return link;
}

You don't allocate enough memory for `link'. You need the length of `a',
plus the length of `b', plus one for the space character, plus one for
the terminating '\0' character.

You should also check if `malloc' returns a null pointer.

Martin
 

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
474,142
Messages
2,570,818
Members
47,362
Latest member
eitamoro

Latest Threads

Top