C++ invalid conversion from 'char' to 'const char' - c++

I am having trouble with a two-dimensional array comparison. I need to create a pseudo login system that asks the user for a username and password and then compares the input to a predefined list of usernames.
In the function, the predefined usernames are represented by the *s and the user input is *s1. When I try to compile it, this pesky trouble-maker appears:
68 D:\Personal\Dev-Cpp\projects\loginSysTest\main.cpp
invalid conversion from char' toconst
regarding the strncmp function in the if statement.
This is the code:
#define nameLenght 30
#define User 10
char usernames[User][User] = {{"student"}, {"admin"}, {"Deus Ex Machina"}};
//=====================================================================
int main(int argc, char *argv[])
{
char usernameInput[nameLenght + 1] = {0};
gets(usernameInput);
int login = compS(*usernames, usernameInput);
if(login == 0)
printf("Access Granted! \n");
else
printf("Access Denied!");
system("PAUSE");
return 0;
}
//=====================================================================
int compS(char *s, char *s1)
{
for(int k = 0 ;k < nameLenght; k++)
{
if(strncmp(s[k], s1, strlen(s1)) == 0)
return 1;
}
}
Thank you in advance.

Just use std::vector and std::string along the lines of:
std::vector<std::string> usernames({"student", "admin", "Deus Ex Machina"});
std::string input;
std::cin >> input;
if (std::find(begin(usernames), end(usernames), input) != end(usernames))
std::cout << "Access Granted!\n";
else std::cout << "Access Denied!\n";
Live demo

If you want (or need) to keep your C-style not-pretty-nor-very-safe code, you could write
strncmp(s + (k+nameLenght), s1, strlen(s1))
That would compile and perhaps work with some more efforts, but you'll have to correct the usernames sizes and actually call compS.
See that other answer for a safer C++-styled code.

There are a few ways you can accomplish this. This is the first way that comes to mind.
char* usernames[] = { "student" , "admin", "Deus Ex Machina", NULL };
int compS(char **s, char *s1)
{
for (int k = 0; s[k] != NULL; k++)
{
if (strncmp(s[k], s1, strlen(s1)) == 0)
return 0;
}
return 1;
}
You have to pass a pointer to a string to strncmp() so I changed your array to an array of pointers to strings. The array has a null pointer at the end to allow the loop to know when it has reached the end.

Related

Is this a usable solution for a `strcmp` substitute in C code?

I have made a <stdio.h> only strcmp equivalent... "ish"
But i WOULD like to know. Is there something i've skipped and/or should fix, if i decide to use this as a substitute for strcmp?
DISCLAIMER:: I have no intend to actually substitute strcmp from my daily usage, but I would like to know if I'm currently able to create a similar substitute for it.
code for it:
#include <stdio.h>
// #include <ctype.h> // Optional
typedef char string[20];
int stringcmp(string str1, string str2);
int strcount(string str);
int main (void)
{
string cmp1, cmp2;
printf("cmp1: ");
scanf("%s", cmp1);
printf("cmp2: ");
scanf("%s", cmp2);
// If you want the function to be ran Case-Insensitive, [ctype] library might be your friend
int result = stringcmp(cmp1, cmp2);
printf("(%i)\n", result);
return result;
}
int strcount(string str)
{
int i = 0;
while(str[i] != '\0')
{
i++;
}
return i;
}
int stringcmp(string str1, string str2)
{
int imax = strcount(str1);
if (imax < strcount(str2))
{
imax = strcount(str2);
}
for (int i = 0; i < imax; i++)
{
if (str1[i] < str2[i])
{
return 1;
}
else if (str1[i] > str2[i])
{
return 2;
}
}
return 0;
}
the function in topic makes usage of another one, by the way. Is that a problem in any way?
For starters the function declaration is incorrect.
In fact your function declaration after adjusting the parameters by the compiler looks like
int stringcmp( char *str1, char *str2);
while the declaration of the standard function strcmp looks like
int strcmp(const char *str1, const char *str2);
That is the function deals with pointers to constant strings because within the function passed strings are not changed.
To compare two strings there is no any need to calculate their lengths. It is just inefficient. Moreover you shall use the type size_t instead of the type int to store a length of a string because an object of the type int can be not large enough to store values of lengths of strings.
Also there is an explicit bug in your approach
if (str1[i] < str2[i])
{
return 1;
}
else if (str1[i] > str2[i])
{
return 2;
}
because you are returning a positive value ( 1 ) when the first string is less than the second string while the standard C function strcmp returns a negative value in this case. and vice versa when the first string is greater than the second string you are returning again a positive value ( 2 ).
From the C Standard (7.23.4.2 The strcmp function)
3 The strcmp function returns an integer greater than, equal to,
or less than zero, accordingly as the string pointed to by s1 is
greater than, equal to, or less than the string pointed to by s2.
And moreover the elements of strings shall be compared as objects of the type unsigned char.
Consider the following demonstrative program.
#include <stdio.h>
#include <string.h>
#include <limits.h>
int main(void)
{
char s1[] = { CHAR_MIN, '\0' };
char s2[] = { CHAR_MAX, '\0' };
printf( "s1 is greater than s2 is %s\n", 0 < strcmp( s1, s2 ) ? "true" : "false" );
return 0;
}
Its output is
s1 is greater than s2 is true
In fact the arrays are declared like
char s1[] = { -128, '\0' };
char s2[] = { 127, '\0' };
provided that the type char behaves as the type signed char (that is usually the default behavior of the type char for many compilers).
So if the elements of the arrays will be compared as objects of the type char then you will get an opposite result to the result of the standard C function strcmp.
The function can be much simpler defined for example the following way
int stringcmp( const char *str1, const char *str2 )
{
while ( *str1 && *str1 == *str2 )
{
++str1;
++str2;
}
return ( unsigned char )*str1 - ( unsigned char )*str2;
}
As you can see there is no any need to calculate preliminary lengths of the strings.
It seems like it would work, although strcmp does not return 0, 1, and 2, but 0, <0, and >0.
See https://www.cplusplus.com/reference/cstring/strcmp/ for reference.
By the way, why not use string.c_str()?
strcmp(string str1,string str2) will:
return an a number less than zero if str1 < str2
return zero if str1 == str2
return an a number more than zero if str1 > str2
so your function should imitate this behavior
int stringcmp(string str1, string str2)
{
int imax = strcount(str1);
if (imax < strcount(str2))
{
imax = strcount(str2);
}
for (int i = 0; i < imax; i++)
{
if (str1[i] == 0 && str2[i] == 0) return 0;
if (str1[i] == 0) return 1;
if (str2[i] == 0) return -1;
if (str1[i] < str2[i])
{
return -1;
}
else if (str1[i] > str2[i])
{
return 1;
}
}
return 0;
}
#include<stdio.h>
#include<string.h>
int main(){
printf("%d",strcmp("hell ","hell"));
}
bro scanf dosent scan white spaces but if you run the above code white spaces play an important role it prints 1;
so check alternative

What necessary changes are required to pass String using reference

I'm designing a user defined String Compare function using "Pass by Reference" in C++.
My code is working fine when passing a pointer to the first character, but I'm struggling to pass the argument by reference. This is my code below:
#include <iostream>
int StrCmp(char [], int, char []);
int main()
{
char Str1[100], Str2[100];
int Compare = 0, StrSize1 = 10; //Both strings are having same number of alphabets.
std::cout<<"Input the First String: "<<std::endl;
gets(Str1);
std::cout<<"Input the Second String: "<<std::endl;
gets(Str2);
Compare = StrCmp(Str1, StrSize1, Str2);
if (Compare == 1)
std::cout<<"String 1 *"<<Str1<<"* is Greater Than String 2 *"<<Str2<<"*"<<std::endl;
else if(Compare == -1)
std::cout<<"String 1 *"<<Str1<<"* is Smaller Than String 2 *"<<Str2<<"*"<<std::endl;
else if(Compare == 0)
std::cout<<"Both String 1 *"<<Str1<<"* and String 2 *"<<Str2<<"* are Equal"<<std::endl;
return 0;
}
int StrCmp(char PassedStr1[], int Size1, char PassedStr2[])
{
for(int i=0; i<Size1 ; ++i)
{
int CodeAscii_1 = PassedStr1[i];
int CodeAscii_2 = PassedStr2[i];
if(CodeAscii_1 > CodeAscii_2)
return 1;
else if(CodeAscii_1 < CodeAscii_2)
return -1;
}
return 0;
}
I would really appreciate if someone please help me understand what necessary changes I need to do to make the code work for passing the argument by reference.
Thanks
You can pass C style arrays by reference in C++ to avoid having them decay into pointers but you need to tell the compiler exactly the fixed size of the array you're passing. Here is an example declaration for your two arrays.
int StrCmp(const char (&PassedStr1)[100], const char (&PassedStr2)[100]);

Pointing to a specific element in a character array

I've been trying to bend my head around this problem for a week now, but I can't seem to find anything online and I've given up on trying to solve it on my own.
My assignment is to write a program which will read names from a file and accept new entries from the user, then sort the entires and write them out to the file. The only crux about this is that I have to sort them in a function and use pointers to do so. This code is supposed to be written in C++ aswell, using character arrays.
The code I have right now looks like this. This is a working version, the only problem is that I don't use neither pointers or a function to sort the names.
#include<iostream>
#include<cstdlib>
#include<fstream>
#include<cstring>
bool sorted;
using namespace std;
int main()
{
int i = 0;
int numNames = 0;
ifstream ifs;
ifs.open("namn.txt");
char c[20][20];
if(ifs.is_open())
{
while(!ifs.eof())
{
ifs >> c[i];
i++;
}
}
cout<<"How many names do you want to enter?"<<endl;
cin>>numNames;
for(int l = i-1; l<numNames+i-1; l++)
{
system("cls");
cout<<"Enter a name: ";
cin>>c[l];
}
while(sorted == false)
{
for(int j = 0; j<numNames+i-1; j++)
{
for(int k = j; k<numNames+i-1; k++)
{
if(c[j][0] > c[k][0])
{
char snorre[20];
strcpy(snorre,c[j]);
strcpy(c[j],c[k]);
strcpy(c[k],snorre);
}
else if(c[j][0] == c[k][0])
{
if(c[j][1] > c[k][1])
{
char snorre[20];
strcpy(snorre,c[j]);
strcpy(c[j],c[k]);
strcpy(c[k],snorre);
}
}
}
}
cout<<endl<<endl<<endl;
ofstream ofs;
ofs.open("namn.txt");
for(int o = 0; o<numNames+i-1; o++)
{
cout<<c[o]<<" ";
ofs<<c[o]<<endl;
}
ofs.close();
system("pause");
sorted = true;
}
}
So hopefully someone could help me out with this problem, thanks in advance! :)
To get your code to use pointers and functions, you can do this- you should change your code and make it use the following:
First, Get each name from the file to an std::string, using getline(ifstream_object, std::string_object), for reference see here.
Convert each one to a const char * (also shown in that example), using .c_str().
Do the following to each of the new names entered.
Store all names entered in this array pointers: char *names[20];, like this: names[i] = name;
Next, Create a function such as follows:
int location_of_bigger_string(const char* s1, const char* s2)
{
// Returns 1 if s1 should be before s2 and 2 otherwise
// This way, you use functions and pointers together.
// Use strcmp(s1,s2) here to determine returning value
}
strcmp(char*, char*) - read about it here.
Finally, to sort all the strings, use qsort or this example.
Here's the complete code,
Note that the compare function gets pointers to the elements, here the elements are pointers themselves, so what's passed to "compare" function is of type "char **"
{
#include "stdafx.h"
#include<iostream>
//retruns +1 if str1 > str2 alphabetically
int compare(const void * a, const void * b )
{
const char * str1 = *((const char **)a);
const char * str2 = *((const char **)b);
int i;
for ( i = 0 ; str1[i] && str2[i] ; i++ )
{
if ( str1[i] > str2[i] )
{
return +1;
}
else if ( str1[i] < str2[i] )
{
return -1;
}
}
//one or both strings have ended
if (str1[i]) //str1 is longer
return +1;
else if (str2[i]) //str2 is longer
return -1;
else
return 0;
}
int _tmain(int argc, _TCHAR* argv[])
{
char * names[]={"Zebra","Kousha","Koosha","Kou","Koush","Test"};
qsort( names, 6, sizeof(char *), compare );
return 0;
}
}

Find string inside 2D char array in C

I am trying to find a string which is inside 2D char array and return it's index. For example:
char idTable[255][32];
char tester[] = { 't','e','s','t','e','r','\0' };
memcpy(idTable[43], tester, 7);
uint8_t id = getID(name[0]);
//name is returned from function "char **name = func();"
//but I have the same results when I try using normal char array...
I've had partial success with the first part of the below code, but it is finding a match if a part of the word is the same (one, oneTwo). If I add "else if" to the first "if" it always goes to the "else if".
The rest of the file prints different results for
printf("idTable string lenght:\t %u\n", strlen(idTable[index]));
and
printf("foundMatch string lenght:\t %u\n", strlen(foundMatch));
, unless I add printf("Index:\t %i\n", index);.
uint8_t getID(char *name) {
printf("\nInserted name:\t %s\n", name);
uint8_t index;
for (uint8_t r = 0; r < 255; r++) {
if (strstr(idTable[r], name) != NULL) {
printf("Found '%s' in position:\t %d\n", name, r);
index = r;
}
}
printf("Index:\t %i\n", index); // THIS LINE
char foundMatch[strlen(idTable[index])];
printf("idTable string lenght:\t %u\n", strlen(idTable[index]));
for (uint8_t c=0; c<strlen(idTable[index]); c++) {
foundMatch[c] = idTable[index][c];
}
printf("foundMatch string lenght:\t %u\n", strlen(foundMatch));
if (strcmp(foundMatch, nodeName) == 0) {
printf("Confirmed\n");
return index;
} else {
printf("Second test failed\n");
return 0;
}
}
Why am I getting this strange results and is there a better way to do this?
I don't know how you are initializing your idTable entries, but if you are using the method that you showed at the start of the question you'll have problems. You can't assume all of the space reserved by idTable is initialed to 0's, so idTable[43] isn't a null terminated string. Therefore idTable[43] need not compare equal to the null terminated string "tester".
Also your getID function doesn't return anything despite its signature. So it won't even compile as-is.
Here's a solution in actual C++, not C.
std::array<std::string, 255> idTable;
idTable.at(43) = "tester";
std::pair<std::size_t, std::size_t> findInIdTable(std::string const& what) {
for (unsigned i = 0; i < idTable.size(); ++i) {
std::size_t pos = idTable.at(i).find(what);
if (pos != std::string::npos) {
return std::make_pair(i, pos);
}
}
// if the code reaches this place, it means "not found". Choose how you want to deal with it
// my personal suggestion would be to return std::optional<std::pair<...> instead.
}
If you want to discard the pos value, it's easy to change as well.
Live On Coliru
In the category: Use C++
Of course, use std::array<char, 32> or std::string if possible. I stuck with your choices for this answer:
Live On Coliru
#include <algorithm>
#include <iostream>
#include <cstring>
char idTable[255][32] = { };
int main() {
using namespace std;
// initialize an entry
copy_n("tester", 7, idTable[43]);
// find match
auto match = [](const char* a) { return strcmp(a, "tester") == 0; };
auto index = find_if(begin(idTable), end(idTable), match) - idTable;
// print result
cout << "match at: " << index;
}
Prints
match at: 43
You need to add a nul to the end of the foundMatch array after copying in the idTable row:
foundMatch[strlen(idTable[index])] = '\0';
right before the 'foundMatch string lenght' (length) message.
strlen is an expensive function that walks the string every time. You should call that once, store it in a local variable, then reference that variable rather than calling strlen repeatedly.

c++ returning and using char array pointers

Here is my code:
#include<stdio.h>
#define MAXLINE 100
/*print the reverse of the input*/
int getline1(char line[], int maxline);
char *reverse(char);
main(){
int len;
char line[MAXLINE];
char *rp;
while ((len = getline1(line, MAXLINE)) > 0)
rp = reverse(line);
printf("%s", *rp);
return 0;
}
int getline1(char s[], int lim){
int c, i;
for (i = 0; (c=getchar()) != EOF && c != '\n'; i++)
if (i > lim-1)
continue;
else
s[i] = c;
if (c == '\n'){
s[i] = c;
i++;
}
s[i] = '\0';
return i;
}
char *reverse(char ca[]){
int i;
int i1 = 0;
char *rp;
char reversed[MAXLINE];
for (i = MAXLINE-1; i >= 0; i--){
reversed[i1] = ca[i];
i1++;
}
rp = reversed;
return rp;
}
But when I try to compile it, I get the following errors:
reverse.cpp: In function ‘int main()’:
reverse.cpp:14:20: error: invalid conversion from ‘char*’ to ‘char’ [-fpermissive]
reverse.cpp:7:7: error: initializing argument 1 of ‘char* reverse(char)’ [-fpermissive]
reverse.cpp:15:19: warning: format ‘%s’ expects argument of type ‘char*’, but argument 2 has type ‘int’ [-Wformat]
I don't have much experience with C++. What am I doing wrong? I just want to make a pointer to a char array and return it.
I just want to make a pointer to a char array and return it.
You appear to want to return a string. That is not a pointer to a char array. Even if your program compiled, you would invoke UB, as you return a pointer to an automatic object- and there are quite a few other runtime errors in your code as well. You got lucky that you also made a compile-time error so the compiler did not accept your program. This C++ program achieves what you intend:
#include <string>
#include <iostream>
std::string reverse(std::string val) {
return std::string(val.rbegin(), val.rend());
}
int main() {
std::string str;
while(std::getline(std::cout, str))
std::cout << reverse(str);
}
What am I doing wrong?
You're learning C89 intead of C++11. They're really different things.
If you wish to learn to code C++, you must learn std::string, and the rest of the Standard library. You will not get anywhere with char*, char[], and MAGIC_BUFFER_SIZE.
You first declare the function prototype
char *reverse(char);
But the actual function is declared as
char *reverse(char ca[])
That's your problem.
What are you trying to achieve ? There are logical errors in the code ...
while ((len = getline1(line, MAXLINE)) > 0)
rp = reverse(line);
printf("%s", *rp);
this part will call reverse on every /n character but printf will never be called...
Also you have string of 100 chars and your reverse will put leading char on end of reverse string.. so if you have string of 5 chars you will have garbage on first 95 positions and then 5 chars you need ...