I'm trying to do the CS50 substitution problem. My code uses cs50.h library to handle strings.
Currently I have a function to convert a string to lower case, and one to convert it to uppercase:
string strtolower(string text)
{
int length = strlen(text);
for (int i = 0; i < length; i )
{
text[i] = tolower(text[i]);
}
return text;
}
string strtoupper(string text)
{
int length = strlen(text);
for (int i = 0; i < length; i )
{
text[i] = toupper(text[i]);
}
return text;
}
I have checked and they are returning the correct uppercase and lowercase string.
However when I call them in main as:
string key_upper = strtoupper(key);
string key_lower = strtolower(key);
printf("%s\n", key_upper);
printf("%s\n", key_lower);
I get (using key
FFFFFFFFFFFFFFFFFFFFFFFFFF
or ffffffffffffffffffffffffff
, same result):
ffffffffffffffffffffffffff
ffffffffffffffffffffffffff
if I print like this:
string key_upper = strtoupper(key);
string key_lower = strtolower(key);
printf("%s\n", key_upper);
printf("%s\n", key_lower);
printf("%s\n", strtoupper(key));
then I get:
ffffffffffffffffffffffffff
ffffffffffffffffffffffffff
FFFFFFFFFFFFFFFFFFFFFFFFFF
if I do:
printf("%s\n", key_upper);
printf("%s\n", key_lower);
printf("%s\n", strtoupper(key));
printf("%s\n", key_lower);
printf("%s\n", strtolower(key));
then I get:
ffffffffffffffffffffffffff
ffffffffffffffffffffffffff
FFFFFFFFFFFFFFFFFFFFFFFFFF
FFFFFFFFFFFFFFFFFFFFFFFFFF
ffffffffffffffffffffffffff
Does anyone know what is happening? Why so I get different results depending on whether I print the return of the function directly vs storing it in a variable first? Is it just some funk related to how cs50.h implements strings? How could I store the return in a variable successfully and call it later?
My full code: https://pastebin.com/pvUzT6iv
Tried:
printf("%s\n", key_upper);
printf("%s\n", key_lower);
Expected:
FFFFFFFFFFFFFFFFFFFFFFFFFF
ffffffffffffffffffffffffff
Got:
ffffffffffffffffffffffffff
ffffffffffffffffffffffffff
CodePudding user response:
This is the kind of misconception CS50 teaches. string
is actually a char*
, declared as typedef char* string
which is incredibly bad practice.
So string strtolower(string text)
is actually char* strtolower(char* text)
. And since you modify the passed string key
, that one changes in each function call. key_upper
is not a copy of it, just a pointer pointing at the same space as key
.
The quick fix is something like this:
string key_upper = strdup(key);
string key_lower = strdup(key);
key_upper = strtoupper(key_upper);
key_lower = strtolower(key_lower);
The longterm solution is to drop out of CS50 and find better study material that actually teaches how string handling and pointers work in C.
CodePudding user response:
Q. why is my char array printing in lower case after i've converted it to uppercase?
Because this:
string key_upper = strtoupper(key);
converts all the characters (that weren't already and were lowercase alphabets) to uppercase.
string key_upper
is pointing to a char *
returned by the strtoupper
function.
You then go on to declare another char *
(under the hood, string
is a char *
) and initialising it with the pointer returned by the strtolower
function.
Note that you passed the same char *
to both the functions, and upper_key
and lower_key
are pointing at the same address. So if you change the memory contents of the address they were pointing to, the pointers would still be pointing to the same memory address. So this:
string key_lower = strtolower(key);
converts the characters back to lowercase.
-------- --------
ptr1 ---> A <--- ptr2
-------- --------
-------- --------
ptr1 ---> a <--- ptr2
-------- --------
See how they're still pointing to the same location? So now if you go on to print their contents, you'd get the same result. In this case, you called strtoupper
first, so the output was all lowercase characters.
CodePudding user response:
It looks like the issue is with the way you are passing the key
string to the strtolower
and strtoupper
functions. In C, strings
are passed as pointers to the first character in the string, and any changes made to the string within the function will be reflected in the original string.
To fix this issue, you can pass a copy of the string to the functions instead of the original string. One way to do this is to use the strdup
function, which creates a duplicate of a string and returns a pointer to the new string. Try this:
string strtolower(string text)
{
int length = strlen(text);
char* lower = strdup(text);
for (int i = 0; i < length; i )
{
lower[i] = tolower(lower[i]);
}
string result = lower;
free(lower);
return result;
}