toUpper and pointer to a string

G

gaga

my function should accept a pointer to a string as its argument. and
it should convert each charater to an uppercase letter. I know what i
need to do, its just my syntax is all out of whack.

void strUpper (char *myStr) {
int i;

strcpy (*myStr);

for(i=0; myStr; i++) {
myStr = toupper(myStr);
}
}

help?

:)
 
J

Jerry Coffin

my function should accept a pointer to a string as its argument. and
it should convert each charater to an uppercase letter. I know what i
need to do, its just my syntax is all out of whack.

void strUpper (char *myStr) {

It's probably not related to the problem you're seeing, but this name
(and any other starting with 'str') is reserved for use by the
implementation.
int i;

strcpy (*myStr);

This is probably your biggest problem. If you're going to call strcpy,
you need to supply two arguments. Fortunately, you don't seem to need to
use strcpy at all, so you can just delete this entirely.
for(i=0; myStr; i++) {
myStr = toupper(myStr);


This will usually work, but can give undefined behavior. You normally
want something like:
myStr = toupper((unsigned char)myStr);
 
J

Justin.SpahrSummers

for(i=0; myStr; i++) {
myStr = toupper(myStr);


This will usually work, but can give undefined behavior. You normally
want something like:
myStr = toupper((unsigned char)myStr);


I don't really understand this statement. toupper() is a function
taking an int parameter. How would a cast change anything, much less
one to unsigned char?
 
D

Daniel Kay

gaga said:
my function should accept a pointer to a string as its argument. and
it should convert each charater to an uppercase letter. I know what i
need to do, its just my syntax is all out of whack.

void strUpper (char *myStr) {
int i;

strcpy (*myStr);

for(i=0; myStr; i++) {
myStr = toupper(myStr);
}
}

help?


Hello,

this is the way I would write this function:

void strUpper(char *str)
{
while (*str) {
*str = toupper(*(str++));
}
}

Cya,
Daniel Kay
 
N

Neelesh Bodas

my function should accept a pointer to a string as its argument. and
it should convert each charater to an uppercase letter. I know what i
need to do, its just my syntax is all out of whack.

void strUpper (char *myStr) {
int i;

strcpy (*myStr);

char myCopy[100]; //sufficiently large
strcpy(myCopy, myStr);
for(i=0; myStr; i++) {
myStr = toupper(myStr);


myCopy = toupper(myStr);
}

}

help?

Few other points to note
1. If you are not changing the myStr argument, change the prototype to
void strUpper (const char *myStr)
2. Better, use std::string class and std::transform. Something like
this:

void strUpper (string s)
{
string t;
transform(s.begin(), s.end(), back_inserter(t), (int(*)
(int))toupper);
}


-N
 
D

Daniel Kay

Neelesh said:
my function should accept a pointer to a string as its argument. and
it should convert each charater to an uppercase letter. I know what i
need to do, its just my syntax is all out of whack.

void strUpper (char *myStr) {
int i;

strcpy (*myStr);

char myCopy[100]; //sufficiently large
strcpy(myCopy, myStr);

Always a bad idea...
for(i=0; myStr; i++) {
myStr = toupper(myStr);


myCopy = toupper(myStr);
}

}

help?

Few other points to note
1. If you are not changing the myStr argument, change the prototype to
void strUpper (const char *myStr)
2. Better, use std::string class and std::transform. Something like
this:

void strUpper (string s)
{
string t;
transform(s.begin(), s.end(), back_inserter(t), (int(*)
(int))toupper);
}


This function will not change anything, unless the function retrieves a
pointer or even better a reference to a std::string.
 
N

Neelesh Bodas

char myCopy[100]; //sufficiently large
strcpy(myCopy, myStr);

Always a bad idea...

Completely Agreed. but I think there is always a need of writing this
kind of code. For example, the strUpper you suggested (or the OP tried
to write) cannot be used in the following case:

int main()
{
strToUpper("helloworld");
}

Worse, there is nothing that stops you from writing such a code (The
non-const nature of parameter doesn't hints at it though). In such a
case, probably creating a local variable to copy the argument is the
only option.
This function will not change anything, unless the function retrieves a
pointer or even better a reference to a std::string.

Ok, one can have
string strUpper (const string& s); //returns the local variable t by
value
or
void strUpper(string& s); //no need of local variable, transform the
argument

The central idea was to suggest that std::string is much safer to use
than char*.


-Neelesh
 
N

Neelesh Bodas

Worse, there is nothing that stops you from writing such a code (The
non-const nature of parameter doesn't hints at it though).

typo. meant "does hint at it though"

-N
 
D

Daniel Kay

Neelesh said:
Neelesh said:
my function should accept a pointer to a string as its argument. and
it should convert each charater to an uppercase letter. I know what i
need to do, its just my syntax is all out of whack.
void strUpper (char *myStr) {
int i;
strcpy (*myStr);
char myCopy[100]; //sufficiently large
strcpy(myCopy, myStr);
Always a bad idea...

Completely Agreed. but I think there is always a need of writing this
kind of code. For example, the strUpper you suggested (or the OP tried
to write) cannot be used in the following case:

int main()
{
strToUpper("helloworld");
}

Worse, there is nothing that stops you from writing such a code (The
non-const nature of parameter doesn't hints at it though). In such a
case, probably creating a local variable to copy the argument is the
only option.

If somebody would force me to write a function in C (what I try to avoid
in any way), which will not modify the input string, I would start with
the following declaration:

void strToUpper(const char* in, char* out);

The user can decide to modify the original string:

char str1[] = "hello";
strToUpper(str1, str1);


Or the user can copy the result into a new string:

char str1[] = "hello";
char str2[sizeof(str1)] = { 0 };
strToUpper(str1, str2);

I hope this is true, since I didn't compile it... :)
Ok, one can have
string strUpper (const string& s); //returns the local variable t by
value
or
void strUpper(string& s); //no need of local variable, transform the
argument

The central idea was to suggest that std::string is much safer to use
than char*.

Ok, just wanted to make sure that uses copy/paste with that function and
wonders why the string isn't changed like the original poster intended
to do.
 
D

Daniel Kay

Neelesh said:
typo. meant "does hint at it though"

Still you can't call a function which declares a char* argument with a
const char* value. The only way to do this is by using evil casts. But
in that case it's the callers fault if bad things happen.
 
J

Jerry Coffin

for(i=0; myStr; i++) {
myStr = toupper(myStr);


This will usually work, but can give undefined behavior. You normally
want something like:
myStr = toupper((unsigned char)myStr);


I don't really understand this statement. toupper() is a function
taking an int parameter. How would a cast change anything, much less
one to unsigned char?


The standardese for it is: "In all cases, the argument is an int, the
value of which shall be representable as an unsigned char or shall equal
the value of the macro EOF. If the argument has any other value, the
behavior is undefined." (That exact wording is from $7.4/1 of the C99
standard, but it's essentially the same for C and C++ overall).

To explain that in a bit more detail, in a typical case, char is signed,
and some characters (especially those used in non-English alphabets) are
represented as negative numbers. Casting to unsigned char converts those
to positive numbers and this positive number is subsequently converted
to int, normally maintaining its value.

Perhaps a concrete example would help. In a typical case, char has a
range of -128..127. Casting to unsigned char gives a number in the range
0-255. Anything that started out in the range 0-127 remains unchanged,
while anything that was in the range -128..-1 maps to the range 128-255.
This value is then converted to an int -- but since int must accomodate
positive values of at least 32767, all values remain unchanged.

Most of the isXXX and toXXX functions are typically table-driven. This
means the value they receive is used as an index into an array. For
example, toupper might look like:

int toupper(int ch) {
return __upper_case[ch+1];
}

where __upper_case looks something like:

int __upper_case[UCHAR_MAX+1];

and somewhere in the startup code, it's initialized something like this:

for (int i=0; i<UCHAR_MAX+1; ++i)
__upper_case = i-1;
for (int i=0; i<26; i++)
__upper_case['a'+i+1] = 'A'+i;
// ...

Of course, this code is non-portable -- it's basically for ASCII in the
"C" locale. For other locales and/or character sets (EBCDIC, ISO/8859/x,
etc.) the initialization would be different. The exact values aren't
terribly important at the moment though -- what's important is that the
value you pass is being used (almost) unchanged as an index into an
array, and the only negative number that's accomodated is -1 (which is
the typical encoding for EOF). If you pass other negative numbers, it
attempts to index before the beginning of the array, which gives
undefined behavior. As noted above, implementing toupper and tolower in
this fashion still conforms entirely with the requirements of the
standard.

People often wonder why tolower and toupper don't do this cast
themselves -- in a typical case (i.e. a twos-complement machine) the
cast just reinterprets the same bit pattern, so it carries no run-time
performane penalty. The answer is simple: these functions ARE required
to accomodate EOF, and if they cast EOF to an unsigned char, they'd
(typically) produce incorrect results. If they added in a test for EOF
before doing the cast, that would add overhead.
 
J

Justin.SpahrSummers

for(i=0; myStr; i++) {
myStr = toupper(myStr);
This will usually work, but can give undefined behavior. You normally
want something like:
myStr = toupper((unsigned char)myStr);

I don't really understand this statement. toupper() is a function
taking an int parameter. How would a cast change anything, much less
one to unsigned char?

The standardese for it is: "In all cases, the argument is an int, the
value of which shall be representable as an unsigned char or shall equal
the value of the macro EOF. If the argument has any other value, the
behavior is undefined." (That exact wording is from $7.4/1 of the C99
standard, but it's essentially the same for C and C++ overall).

To explain that in a bit more detail, in a typical case, char is signed,
and some characters (especially those used in non-English alphabets) are
represented as negative numbers. Casting to unsigned char converts those
to positive numbers and this positive number is subsequently converted
to int, normally maintaining its value.

Perhaps a concrete example would help. In a typical case, char has a
range of -128..127. Casting to unsigned char gives a number in the range
0-255. Anything that started out in the range 0-127 remains unchanged,
while anything that was in the range -128..-1 maps to the range 128-255.
This value is then converted to an int -- but since int must accomodate
positive values of at least 32767, all values remain unchanged.


You're right (obviously). I knew about each individual item you
mentioned, but I just didn't connect it to the bigger picture like
you've done in that explanation, so thanks for that.
 
J

Jack Klein

It's probably not related to the problem you're seeing, but this name
(and any other starting with 'str') is reserved for use by the
implementation.

Actually, this usage is ok. Identifiers beginning with "is", "to",
"str", and "mem" followed by a lower case letter are reserved.
Following "str" with 'U' does not violate the implementation
namespace.

--
Jack Klein
Home: http://JK-Technology.Com
FAQs for
comp.lang.c http://c-faq.com/
comp.lang.c++ http://www.parashift.com/c++-faq-lite/
alt.comp.lang.learn.c-c++
http://www.club.cc.cmu.edu/~ajo/docs/FAQ-acllc.html
 
J

Jerry Coffin

[ ... ]
Actually, this usage is ok. Identifiers beginning with "is", "to",
"str", and "mem" followed by a lower case letter are reserved.
Following "str" with 'U' does not violate the implementation
namespace.

Oops -- quite right. My apologies for the misinformation, and thanks for
the correction.
 
J

James Kanze

gaga schrieb:
my function should accept a pointer to a string as its argument. and
it should convert each charater to an uppercase letter. I know what i
need to do, its just my syntax is all out of whack.
void strUpper (char *myStr) {
int i;
strcpy (*myStr);
for(i=0; myStr; i++) {
myStr = toupper(myStr);
}
}

this is the way I would write this function:
void strUpper(char *str)
{
while (*str) {
*str = toupper(*(str++));
}
}

Well, I'd certainly use something different, based on
std::string, keeping the original value somewhere, and in no
case converting in place. (Toupper is not a one-to-one
relationship; converting a single lower case character will
sometimes result in a string of more than one character.) But
if you insist on in place and one to one, then
std::ctype<>::toupper already does the job, without the undefined
behavior above:

void strUpper( char* str, std::locale const& loc = std::locale() )
{
std::use_facet< std::ctype< char > >( loc )
.toupper( str, str + strlen( str ) ) ;
}
 
J

James Kanze

2. Better, use std::string class and std::transform. Something like
this:
void strUpper (string s)
{
string t;
transform(s.begin(), s.end(), back_inserter(t), (int(*)
(int))toupper);
}

Which will result in undefined behavior. The function you want
is std::ctype< char >::toupper(). But as a member function,
you'll need some fancy binders (or boost::bind) to make it work.
The case occurs often enough in my code to have justified
writing my own special binders, so I can write things like:

std::string
strUpper( std::string const& s )
{
std::string result ;
std::transform( s.begin(), s.end(),
std::back_inserter( result ),
CTypeToUpper() ) ;
return result ;
}
 
D

Daniel Kay

James said:
gaga schrieb:
my function should accept a pointer to a string as its argument. and
it should convert each charater to an uppercase letter. I know what i
need to do, its just my syntax is all out of whack.
void strUpper (char *myStr) {
int i;
strcpy (*myStr);
for(i=0; myStr; i++) {
myStr = toupper(myStr);
}
}

this is the way I would write this function:
void strUpper(char *str)
{
while (*str) {
*str = toupper(*(str++));
}
}

Well, I'd certainly use something different, based on
std::string, keeping the original value somewhere, and in no
case converting in place. (Toupper is not a one-to-one
relationship; converting a single lower case character will
sometimes result in a string of more than one character.) But
if you insist on in place and one to one, then
std::ctype<>::toupper already does the job, without the undefined
behavior above:

void strUpper( char* str, std::locale const& loc = std::locale() )
{
std::use_facet< std::ctype< char > >( loc )
.toupper( str, str + strlen( str ) ) ;
}


Off cource std::string is better. But what you have wrote looks
interesting. I'll have a look at it...
 

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,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top