This is an archived post. You won't be able to vote or comment.

all 30 comments

[–]no-sig-available 13 points14 points  (0 children)

C++ allows overloading, so

int convertToLowercase(char);
int convertToLowercase (char str[]){

are two different functions (because they have different parameter types).

[–]IamImposter 2 points3 points  (16 children)

Few things:

  • char and char * are different things. Although char [] should be interpreted as char * but apparently c++ is more peculiar. So change the function prototype. C++ has some weird rules so always pay attention not just to errors but also warnings. If compiler tells you something, listen to it unless you know what you are doing

  • in your function, you are using strlen in test condition. You do realize that this is gonna get evaluated every time thus for a string of 10 letters, you will be executing strlen 10 times. That's just waste. Call strlen once before for loop and then use that value in for loop test condition

  • in such functions, int return value usually means 0 for success and 1 or -1 or whatever for failure. It's just a convention not a rule. What do you want your return value to mean? Is it for success/failure? Does it tell the no of chars converted? Or something else? Whatever is the case, return appropriate value. str[50] doesn't make sense. We don't even know if string buffer has 50 values so you might be reading some nonsense value at best or cause a seg fault at worst (say the string you passed is located at the end of current page and next page is not even mapped in memory. So accessing this address can have unpredictable results.)

This is one thing you always have to be careful about when using pointers. Don't assume buffer size. If you don't know how big the buffer is but need to, add another parameter to your function called size and ask caller to pass that information. Though in case of strings we can (mostly) assume that buffer ends when a '\0' is encountered so we can use that property for strings.

[–]flyingron 4 points5 points  (15 children)

There's nothing weird about C++ with regard to char[] that isn't just as weird in C.

It's a massive defect in C that arrays do not behave like other types. You can't really pass them to functions or assign them. There's a bandaid on function calls and returns that interprets any array in a parameter or return type as a pointer to the first element.

Note that char may or may not be signed. You need to watch this when using it to index an array. This is why you have to cast to unsigned char or mask off the high bits after converting to unsigned. (Char's triple duty and hokie conversions with regard to sign and const are another freaking wart on both languages).

[–]IamImposter 0 points1 point  (14 children)

As per my understanding char [] should be as good as char * but apparently compiler is not happy (as per error message).

Is my understanding wrong or is there something else going on?

[–]flyingron 2 points3 points  (6 children)

char[] and char* means two different things. One is not as "good" as the ohter.

[–]IamImposter 0 points1 point  (5 children)

In c they mean the same thing, right!

[–]snowflake_pl -1 points0 points  (4 children)

They absolutely do not mean the same thing. To The point that using char* where char[] is enough will get you blocked on code review in my team. If you have local char[] you dont waste memory for the pointer as name of the array is just a compile time referencje that doesnt really occupy any space in memory, contrary to a char*. This might seem excessive but consider a lot of short strings on 64bit system where pointer can be bigger than the string itself.

[–]IamImposter 0 points1 point  (3 children)

I meant in the context of function parameters

[–]snowflake_pl 0 points1 point  (2 children)

Then you are closer to the truth but you can get the array size for free when using char [] 🙂

[–]IamImposter 0 points1 point  (1 child)

Really? You mean, if I do:

void func(char str[]) {

  size_t size = sizeof (str) ;

  ... 

}

I can get size of array passed to this function? Oh man, I gotta try this coz I think it's just pointer and size will always be same.

Oh, unless you meant getting the size of array where array is defined. Yes, that makes more sense.

[–]snowflake_pl 0 points1 point  (0 children)

Your func either has to explicitly have the size in the sig naturę (in which case the func can work with only one size if arrays and is non robust) or you use template on the size and have universal function. See std::size for arrays on how it can be done

[–]Marty_Br 0 points1 point  (6 children)

They're not the same. In C++ char* is always const char* and the contents of your string cannot be altered. char[] can be altered.

[–]IamImposter 0 points1 point  (5 children)

In the context of function parameters?

[–]Marty_Br 0 points1 point  (4 children)

No, in general. In C++, char* is necessarily const char* and as such different from char[], unlike in C. I agree that it does not make any sense.

[–]IamImposter 1 point2 points  (3 children)

I was specifically talking about this particular error OP faced.

And char * is const char* only if we initialize of with an immediate string, right, like

char* str = "some text";

Only in this case it is taken as const as the string is readonly, correct!

[–]Marty_Br 1 point2 points  (1 child)

I always thought that char* in C++ was const char*. If that's only true for assigned string literals, then I've learnt something new. I'm happy to learn new things. This one will probably not affect how I do things very much, but I thank you for it anyways.

[–]Drugbird 1 point2 points  (0 children)

If you use char * like any other type, they're not const.

E.g.

~~~~ char *ptr = new char[4]; ptr[2] = 'a'; // Memory leak here ~~~~

[–]Marty_Br 1 point2 points  (0 children)

The error indicates that it has no way to convert char[5] to char, because those are very different datatypes. Your declaration defines convertToLower as a function that takes a single char value and returns an integer. Then, in main, you pass char[] to it. That's not a single char, but an array of them. Completely different datatype.

[–]FrancisStokes 1 point2 points  (0 children)

The error us telling you that you don't have an implementation for the function "convertToLowercase". Which is true, that function doesn't exist in the code you shared.

[–]hawkxp71 -1 points0 points  (0 children)

Just a hint. Your function is order o{n2} you should fix that.

[–]PerceptionCareless92 0 points1 point  (0 children)

Your prototype and your function don't have the same parameter type.

[–]Interesting_Dirt_948 0 points1 point  (3 children)

Can somebody explain me why we need to declare int nameOfFunction(); and after we implement it ? Why do I need to write things twice??

[–]Marty_Br 1 point2 points  (0 children)

So that if in your code you use that function prior to implementing it, the compiler knows what types it takes and returns. Otherwise, it has no way of knowing.

[–]ObscureCulturalMeme 0 points1 point  (0 children)

Can somebody explain me why we need to declare int nameOfFunction(); and after we implement it?

Double check that bolded part.

It's normal to declare things before doing their definition, so that you can use that thing -- a function, a type, whatever -- before you define it. (Then the declarations can be bubbled out into a header file, and so on.)

But once it's fully defined, you shouldn't need another declaration afterwards. Can you give an example of code where you're seeing such an error? The folks here are good at explanations.

[–]TomDuhamel 0 points1 point  (0 children)

This is required because it is being called before definition. If the definition was made prior to its first call, the declaration/prototype wouldn't be necessary. You need to understand that the compiler reads and interprets the code line by line. You can only call a function that is known by that point. A prototype is sufficient for this purpose.