Getting the middle of a string

  • Thread starter Olivier Bellemare
  • Start date
O

Olivier Bellemare

I've tried to make a function that returns the middle of a string. For
example:
strmid("this is a text",6,4); would return "is a".

Here is my code:
char *strmid(char *texte, int depart, int longueur)
{ char *resultat = " ";
char *temporaire = " ";
int nbr;

nbr = depart + longueur - 1;

strncat(temporaire,texte,nbr);
strrev(temporaire);
strncat(resultat,temporaire,longueur+1);
strrev(resultat);

return resultat;
}


It doesn't work properly, but I really don't understand why. Can anyone
enlighten me? Or, if there's a similar code that works already, can I have
it please?

Thanks,
- A new C programmer
 
B

Ben Pfaff

Olivier Bellemare said:
char *strmid(char *texte, int depart, int longueur)
{ char *resultat = " ";
char *temporaire = " ";
int nbr;

nbr = depart + longueur - 1;

strncat(temporaire,texte,nbr);
strrev(temporaire);
strncat(resultat,temporaire,longueur+1);
strrev(resultat);

return resultat;
}

On the basis of that code, I'd recommend that you buy a book on
beginning C programming. I don't think you're ready for this
newsgroup yet. There are just too many errors in too many
categories.
 
P

Pushkar Pradhan

Olivier said:
I've tried to make a function that returns the middle of a string. For
example:
strmid("this is a text",6,4); would return "is a".

Here is my code:
char *strmid(char *texte, int depart, int longueur)
{ char *resultat = " ";
char *temporaire = " ";
int nbr;

nbr = depart + longueur - 1;

strncat(temporaire,texte,nbr);
strrev(temporaire);
strncat(resultat,temporaire,longueur+1);
strrev(resultat);

return resultat;
}


It doesn't work properly, but I really don't understand why. Can anyone
enlighten me? Or, if there's a similar code that works already, can I have
it please?

Thanks,
- A new C programmer

What do you mean by middle of a string? The example you've provided is a
little unclear.
 
M

Morris Dovey

Olivier said:
I've tried to make a function that returns the middle of a string. For
example:
strmid("this is a text",6,4); would return "is a".

Here is my code:
char *strmid(char *texte, int depart, int longueur)
{ char *resultat = " ";
char *temporaire = " ";
int nbr;

nbr = depart + longueur - 1;

strncat(temporaire,texte,nbr);
strrev(temporaire);
strncat(resultat,temporaire,longueur+1);
strrev(resultat);

return resultat;
}

It doesn't work properly, but I really don't understand why. Can anyone
enlighten me? Or, if there's a similar code that works already, can I have
it please?

Remember that C subscripts start at zero.

How about something like (untested):

#include <string.h>
char *mid(char *texte,size_t depart,size_t longueur)
{ char *resultat;
size_t maximum = strlen(texte) - depart;
if (longeur > maximum) longeur = maximum;
resultat = malloc(longueur + 1);
if (resultat)
{ memcpy(resultat,texte + depart,longueur);
resultat[longueur] = '\0';
}
return resultat;
}

Don't forget to check the return value (NULL if memory couldn't
be allocated for the result); and to free() the allocated storage
when you're done with it.
 
A

A. Sinan Unur

I've tried to make a function that returns the middle of a string. For
example:
strmid("this is a text",6,4); would return "is a".

I am confused ... What are the parameters 6 and 4 supposed to do? "The
middle of a string", to me, means the character that is in the middle of
the string. So, for was string whose length is an even number, this would
not exist. For a string a whose length n is an odd number, this would be
a[n/2].

It is possible you had something else in mind. In which case, you should
probably try to explain your purpose a little better.
Here is my code:
char *strmid(char *texte, int depart, int longueur)

I guess 'depart' in French means something other than 'depart' in
English. Are you trying to write a function to extract a substring
instead of actually locating the middle of a string?

By the way, you should not use the str prefix for functions you write.
Those names are reserved for the standard library.
{ char *resultat = " ";
char *temporaire = " ";

Both resultat and temporaire now point to read only memory locations.
int nbr;

nbr = depart + longueur - 1;

strncat(temporaire,texte,nbr);

And even if temporaire were pointing to a writable location, you could
write at most one character there so, ooops!
strrev(temporaire);
What?

strncat(resultat,temporaire,longueur+1);
strrev(resultat);

Wha - what?
return resultat;
}


It doesn't work properly, but I really don't understand why.

What did you expect it to do and what does it do instead?
if there's a similar code that works already, can I have it please?

The code below makes a ton of assumptions but since you asked:

#include <stdio.h>

char *substr(char *target,
const char *source,
size_t start,
size_t length) {
int i;
for(i = 0; i != length; ++i) {
target = source[start + i];
}
target = 0;
return target;
}

int main(void) {
char a[] = "This is a test";
char b[7];
puts(substr(b, a, 5, 6));
return 0;
}

C:\Home> gcc -Wall -O2 t.c -o t.exe

C:\Home> t
is a t
 
M

Mark McIntyre

I am confused ... What are the parameters 6 and 4 supposed to do? "The
middle of a string", to me, means the character that is in the middle of
the string.

he means a substring, The example makes that exceptionally clear
surely?
I guess 'depart' in French means something other than 'depart' in
English.

Not trying to be rude, but the meaning of his variable names is
utterly irrelevant. And BTW depart means start in french.
By the way, you should not use the str prefix for functions you write.

absolutely.
 
A

Anupam

Olivier Bellemare said:
I've tried to make a function that returns the middle of a string. For
example:
strmid("this is a text",6,4); would return "is a".

Here is my code:
char *strmid(char *texte, int depart, int longueur)
{ char *resultat = " ";
resultat is a pointer to a *read-only* piece of memory containing
blank and '\0'.
char *temporaire = " "; ditto.
int nbr;

nbr = depart + longueur - 1;

strncat(temporaire,texte,nbr);
tch tch How can you append beyond that first character... to space
which hasn't been allocated to you?
strrev(temporaire); Non standard function.
strncat(resultat,temporaire,longueur+1);
Surely you want longeur.Why the extra character? '\0 is appended by
strncat itself.
strrev(resultat);

ditto
return resultat;
}
Ok here goes . First I will have a go at thinking out what I think you
are trying to do :
Lets say the string is : "abcdef"
And you use
strmid("abcdef",3,2);
then you expect two characters starting from the third charcter of the
string...more specifically you expect a pointer to the first character
of a string containing this .. in this case "cd"..right?

1. So what you do is take the first 3+2-1 characters from the string
That gives you "abcd"... The final answer you want is at the end of
this string.
2. So you reverse this to give "dcba".
Now you want the first 2 characters of this .. which you extract to
give "dc".
3. Finally you reverse this string to get your answer which is "cd".

:) Now I must admit that its quite ingeneous .. however.. there are
*some* problems :
1. strrev() is not a standard c function ... so don't rely on it.
2. Do not write to read-only string literals.. you are asking for trouble.
3. Definitely don't write into unallocated memory.
4. This is definitely not the most efficient way of going about it.
If you should still want the code written using the algorithm you have
used, it can definitely be written. Mail me if you truly want this code
which will be inefficient and unelegant.
It doesn't work properly, but I really don't understand why. Can anyone
enlighten me? Or, if there's a similar code that works already, can I have
it please?

Thanks,
- A new C programmer

char *strmid(char *text, int start, int len)
{
char *result;
int cnt;
if( ( result=malloc((len+1)* sizeof *text )) ==NULL)
{
/* Handle memory not allocated errors */
return NULL;
}
/* I'm feeling too lazy . But do handle the cases where
there is no (start+len-1)th character in text */

cnt=0;
while(cnt!=len)
{
result[cnt]=*(text+start-1+cnt);
cnt++;
}
result[cnt]='\0';
return result;
}
 
J

Joe Wright

Pushkar said:
What do you mean by middle of a string? The example you've provided is a
little unclear.

He seems to mean substring. Maybe like this.

/*
Program: substr.c
Author: Joe Wright
Date: 11/17/1998

The substr function in xBase is great.
char * substr(char *string, int start, int count);

05/09/2003
In <news:comp.lang.c> (e-mail address removed) suggests the original
program is less than safe. It was also written long ago when I
was a 59 year old boy. I will attempt to address these concerns.
*/

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

/*
Extract a substring from a character string.

char *substr(char *string, int start, size_t count);

start is the starting position in string.
If positive, it is the offset from the beginning of string.
If negative, it is the offset from the end of string.
If out of range, a NUL string is returned.

count is the number of characters to extract.
If count is == 0, or is greater than the number of characters from
start to the end of string, it is set to the number of remaining
characters and the rest of the string is returned.

Consider string = "Now is the time", 15 characters (plus '\0').
We extract "the" with start == 7 or start == -8 and count == 3.

Now consider that "time" is of interest. start will be 11. The
maximum length of the substring is len (15) minus start (11) or
4 characters. If count is 0 or > 4, make it 4.
*/

#define LEN 256

char *substr(char *string, int start, size_t count) {
static char str[LEN];
str[0] = '\0'; /* The NUL string error return */
if (string != NULL) {
size_t len = strlen(string);
if (start < 0)
start = len + start;
if (start >= 0 && start < len) {
if (count == 0 || count > len - start)
count = len - start;
if (count < LEN) {
strncpy(str, string + start, count);
str[count] = 0;
}
}
}
printf("start == %u, count == %u\n", (unsigned)start,
(unsigned)count);
return str;
}

void usage(void) {
printf("Usage: substr 'cString' nStart nCount\n"
"Note: nStart is rel-0 in C\n");
exit(0);
}

int main(int argc, char *argv[]) {
if (argc < 4) usage();
printf("%s\n", substr(argv[1], atoi(argv[2]), atoi(argv[3])));
return 0;
}
/* End of substr.c */
 
A

A. Sinan Unur

he means a substring, The example makes that exceptionally clear
surely?

It wasn't clear to me when I was first reading the post. After posting, I
remembered that some BASICs have functions left, right and mid for
extracting substrings, so his naming became clearer.
Not trying to be rude, but the meaning of his variable names is
utterly irrelevant.

But sir, it does make a difference to me in terms of comprehending an
undocumeted function.
And BTW depart means start in french.

Thank you.
 
P

Paul Hsieh

(e-mail address removed) says...
I've tried to make a function that returns the middle of a string. For
example:
strmid("this is a text",6,4); would return "is a".

Here is my code:
char *strmid(char *texte, int depart, int longueur)
{ char *resultat = " ";
char *temporaire = " ";
int nbr;

nbr = depart + longueur - 1;

strncat(temporaire,texte,nbr);
strrev(temporaire);
strncat(resultat,temporaire,longueur+1);
strrev(resultat);

return resultat;
}

It doesn't work properly, but I really don't understand why. Can anyone
enlighten me? Or, if there's a similar code that works already, can I have
it please?

C is a very poor language for doing anything useful with strings.
Fundamentally, your problem is that you have not provided seperate space for
the resulting substring. Here's a recoding:

char *strmid (char *resultat, const char *texte, int depart, int longueur) {
memmove (resultat, texte + depart, longueur);
resultat[longueur] = '\0';
return resultat;
}

Which requires that you have made sufficient space in the variable resultat.
The problem is that simply declaring resultat = " " somewhere in your
code is not good enough, since all the space for resultat may be allocated in
non-writable memory. If you want to avoid this issue you can automatically
make writable memory available:

char *strmid (const char *texte, int depart, int longueur) {
char *resultat = (char *) malloc (longueur + 1);
memmove (resultat, texte + depart, longueur);
resultat[longueur] = '\0';
return resultat;
}

But now you have to remember to free the memory with a call to free() once you
are done with it, otherwise you will lose that memory.

Handling "strings" in C for other purposes just continues to have these kinds
of complications that require that you hand hold the implementation details
every step of the way.

An alternative is to use an alternative string library such as "the Better
String Library" (http://bstring.sf.net/) where such things are trivial. In
bstrlib you will find a function like:

bstring resultat = bmidstr (texte, depart, longueur);

which makes a seperate bstring which is a copy of the middle of a previously
defined bstring. Or alternatively:

struct tagbstring resultat;
blk2tbstr (resultat, texte->data + depart, longueur);

Lets you have a bstring defined by reference, so there is no memory management
required.
 
P

Paul Hsieh

#define LEN 256

char *substr(char *string, int start, size_t count) {
static char str[LEN];
[...]
return str;
}

<sarcasm>
Which is real damn useful if you try to do the following:

char a = substr ("This is a string", 6, 4);
char b = substr (a, 2, 1);
printf ("<%s>, <%s>\n", a, b);

</sarcasm>
 
S

Sidney Cadot

Paul said:
[snip...]
Which requires that you have made sufficient space in the variable resultat.
The problem is that simply declaring resultat = " " somewhere in your
code is not good enough, since all the space for resultat may be allocated in
non-writable memory. If you want to avoid this issue you can automatically
make writable memory available:

char *strmid (const char *texte, int depart, int longueur) {
char *resultat = (char *) malloc (longueur + 1);
memmove (resultat, texte + depart, longueur);
resultat[longueur] = '\0';
return resultat;
}

Casting the result of a malloc() is considered bad practice by most
knowledgable C programmers, including the vast majority of the regulars
here.

Best regards,

Sidney
 
C

CBFalconer

Olivier said:
I've tried to make a function that returns the middle of a string.
For example:
strmid("this is a text",6,4); would return "is a".

I would expect it to return "s a ", if anything.
Here is my code:
char *strmid(char *texte, int depart, int longueur)
{ char *resultat = " ";

This is a pointer to a string holding one blank, which cannot be
altered. Seems fairly useless here.
char *temporaire = " ";

This is a pointer to a string holding one blank, which cannot be
altered. Seems fairly useless here.
int nbr;

nbr = depart + longueur - 1;

strncat(temporaire,texte,nbr);
strrev(temporaire);

This function does not exist in standard C.
strncat(resultat,temporaire,longueur+1);
strrev(resultat);

return resultat;
}

You also fail to define strncat via #include <string.h>. The
function name "strmid" is reserved for the implementation, i.e.
you may not use it or anything beginning with "str".
It doesn't work properly, but I really don't understand why.
Can anyone enlighten me? Or, if there's a similar code that
works already, can I have it please?

So let us design a substring extractor, say:

#include <stdlib.h> /* so we can use calloc */

char *substr(const char *s, size_t first, size_t length)
/* Notice the const, because from your usage example you plan to
use it on unalterable strings. The other parameters should be
size_t, because they can be any size available in the system, and
cannot be negative. */
{
char * result;
size_t i;

result = calloc(length+1); /* create space for result */
/* I used calloc to ensure the result is zero terminated, and
length+1 to ensure there is the extra space for that zero
termination */
i = 0;
while (length--) { /* make the copy */
result = s[first + i];
++i;
}
return result;
} /* untested, and not optimum */

Undefined for length==0 and various other evils.

Since your prototype did not supply a place for the substring to
be placed, we have to allocate that space within substr. That
means that whatever calls substr must ultimately free the pointer
returned.
 
J

Joe Wright

Paul said:
#define LEN 256

char *substr(char *string, int start, size_t count) {
static char str[LEN];
[...]
return str;
}

<sarcasm>
Which is real damn useful if you try to do the following:

char a = substr ("This is a string", 6, 4);
char b = substr (a, 2, 1);
printf ("<%s>, <%s>\n", a, b);

</sarcasm>
Ok, but assigning char* to char will stop you before anything else.
 
F

Friedrich Dominicus

<sarcasm>
Which is real damn useful if you try to do the following:

char a = substr ("This is a string", 6, 4);
char b = substr (a, 2, 1);
printf ("<%s>, <%s>\n", a, b);

</sarcasm>
not worse than strtok ;-)

Happy C hacking
Friedrich
 
M

Mark McIntyre

But sir, it does make a difference to me in terms of comprehending an
undocumeted function.

Top tip: Never rely on the variable names as documentation, especially
in code you are not familiar with. It is absolutely guaranteed to bite
you in the a*se when you least need ir. And it will always totally
fsck you over when working with multilingual programmers....
 
P

Peter Shaggy Haywood

Groovy hepcat Olivier Bellemare was jivin' on Sat, 06 Dec 2003
03:25:58 GMT in comp.lang.c.
Getting the middle of a string's a cool scene! Dig it!
I've tried to make a function that returns the middle of a string. For
example:
strmid("this is a text",6,4); would return "is a".

Here is my code:
char *strmid(char *texte, int depart, int longueur)

Avoid function names beginning with "str". They are reserved
identifiers. (To be more precise, all identifiers with external
linkage beginning with "str" followed by a lower case letter are
reserved.)
{ char *resultat = " ";
char *temporaire = " ";
int nbr;

nbr = depart + longueur - 1;

strncat(temporaire,texte,nbr);

Uh oh! You've just caused undefined behaviour. First of all,
temporaire points to a string literal, which may be in memory marked
read only. You are attempting to modify this string literal. This can
cause a crash. And secondly, even if you can modify the string literal
without problems, you have another problem. Your string literal is
only 2 bytes long (one byte for the space and one byte for the
terminating null character). But you are attempting to add more bytes
to the end of it. Result: you are writing into some random memory
location. This also produces undefined behaviour.
On top of that, your string literal contains a space, and you are
attempting to append a string to the end of this string literal. So,
even if the operation succeeded, you'd end up with a space at the
start of the resulting string, which isn't in the original string. I'm
sure this is not desired.
strrev(temporaire);

There's no such function in standard C, and I don't see a
declaration of this in your code, let alone a definition. (And it's a
reserved identifier anyhow. See above.)
strncat(resultat,temporaire,longueur+1);

And once again you are attempting to modify a string literal and
write beyond the end of it. But here you have yet another problem.
Both temporaire and resultat point at a string literal with the same
content. These two string literals are allowed to be folded into one.
In that case, you're writing a string to the end of itself. This is a
big problem.
But that's not all. strncat() doesn't always append a null character
to the end of the sequence, so it may not be a string. (Remember, a
string ends with a null character.)
strrev(resultat);

See above.
return resultat;

Note: if you return (the address of the first element of) an array
with automatic duration, you will have another problem. Automatic
variables no longer exist after the function returns. String literals
have static duration, however. But, as I've already shown, string
literals cause other problems.
}

It doesn't work properly, but I really don't understand why. Can anyone
enlighten me? Or, if there's a similar code that works already, can I have
it please?

Sure, here you go. I've included functions that get the rightmost
and leftmost parts of a string too, in case you need them at some time
in the future.

#include <assert.h>
#include <stdio.h>
#include <string.h>

/* copies 'len' characters from offset 'off' of string 'src' to 'dst'
returns dst */
char *substr(char *dst, const char *src, int off, int len)
{
assert(NULL != dst);
assert(NULL != src);
assert(0 <= len);
assert(0 <= off);

sprintf(dst, "%.*s", len, src + off);
return dst;
}

/* copies rightmost 'len' characters from 'src' to 'dst'
returns dst */
char *rightstr(char *dst, const char *src, int len)
{
const char *p;
int sl;

assert(NULL != dst);
assert(NULL != src);
assert(0 <= len);

if(len >= (sl = strlen(src)))
p = src;
else
p = src + sl - len;

sprintf(dst, "%.*s", len, p);
return dst;
}

/* copies leftmost 'len' characters from 'src' to 'dst'
returns dst */
char *leftstr(char *dst, const char *src, int len)
{
assert(NULL != dst);
assert(NULL != src);
assert(0 <= len);

sprintf(dst, "%.*s", len, src);
return dst;
}

--

Dig the even newer still, yet more improved, sig!

http://alphalink.com.au/~phaywood/
"Ain't I'm a dog?" - Ronny Self, Ain't I'm a Dog, written by G. Sherry & W. Walker.
I know it's not "technically correct" English; but since when was rock & roll "technically correct"?
 

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,122
Messages
2,570,717
Members
47,283
Latest member
VonnieEwan

Latest Threads

Top