What's wrong with this template [closed] - c++

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 3 years ago.
Improve this question
I am doing c++ 6th edition the 6th exercise of 8th chapter. I have questions on this template. I don't know why it always shows the last string not shows the string that has the max length.
#include <iostream>
#include <cstring>
//8.6
using namespace std;
template <typename T> T Maxn(T *,int);
template <> char * Maxn<>(char **,int );
int main()
{
double arr_1[5] = { 0.0,3.0,1.0,4.0,5.0 };
cout << "double max: " << Maxn(arr_1,5) << endl;
int arr_2[4] = { 3,4,1,0 };
cout << "int max: " << Maxn(arr_2, 4) << endl;
const char *arr_3[4] = { "sdf","tttq","ttttrrsdss" ,"q12221"};
cout << "char max:" << Maxn(arr_3, 4) << endl;
return 0;
}
template <typename T>
T Maxn(T *p,int n)
{
T max = p[0];
for (int i = 0; i < n; i++)
{
if (p[i] > max)
max = p[i];
}
return max;
}
template <> char * Maxn<>(char **p, int n)
{
char * max = p[0];
for (int i = 0; i < n; i++)
{
if (strlen(p[i]) > strlen(max))
{
max = p[i];
}
}
return max;
}

You should simply start using a debugger or at minimum you could visit your code by using printf debugging. You will see, that your char* specialization is never used!
Reason:
Your data type for the "strings" is const char* which matches better for the first template than to your specialization and so simply the first template version is called. And this compares now the address of the strings. If your compiler puts the strings in the order presented in the source, you will always see the last string as result, as it has the highest address.
Simply use:
template <> const char * Maxn<>(const char **p, int n)
{
const char * max = p[0];
for (int i = 0; i < n; i++)
{
if (strlen(p[i]) > strlen(max))
{
max = p[i];
}
}
return max;
}
BTW: Your code has some efficiency flows. You compare in the first step two times the same value which is not needed.

Type of arr_3 is const char *, but not char *:
const char *arr_3[4] = { "sdf","tttq","ttttrrsdss" ,"q12221"};
, so the first implementation of Maxn is called, where strlen is not used.

Related

C++ invalid conversion from 'char' to 'const char*' in strcmp() within a template specialization

I am having trouble with using strcmp() for a const char* array inside a template specialization.
In my script I want to sort several array's from large values/length to smaller ones. It works for an integer and float array however it does not work for a const char* array. I declared 3 template functions with their definition. For the const char* array I use a specialized template function which uses the strcmp(const char*, const char*) function to sort the array.
My script is as follows (first the template declarations, second the main script, third the template function definitions):
#include <iostream>
#include <string.h>
using namespace std ;
// Template function declarations
template <class T>
void order(T& a, T& b) ;
template <class T>
void sort(T* c, int d) ;
template <class T>
void display(T* e, int f) ;
// Main
int main() {
int random[10] = {10,23,5,37,56,0,20,88,95,32} ; // Random Array of integers
float random_fl[10] = {9.5,66.2,5.8,41.1,89.4,0.6,23.4,66.5,90.9,57.7} ; // Random Array of floats
const char* random_char[] = {"blah", "blahblah", "string", "character", "literal", "one", "randomize", "unsigned", "red", "wolf"} ;
int length = sizeof(random)/sizeof(int) ; // Calculating the lenght of the array
int length_fl = sizeof(random_fl)/sizeof(float) ;
int length_char = sizeof(random_char)/sizeof(const char*) ;
cout << "Initial integer Array: "; // Terminal message giving the initial array
for (int i = 0; i < length; ++i) {
cout << random[i] << " ";
}
cout << endl;
cout << "Initial float Array: ";
for (int i = 0; i < length_fl; ++i) {
cout << random_fl[i] << " ";
}
cout << endl;
cout << "Initial character Array: ";
for (int i = 0; i < length_char; ++i) {
cout << random_char[i] << " ";
}
cout << endl;
sort(random, length) ; // Call sort() function to sort array
sort(random_fl, length_fl) ;
sort(random_char, length_char) ;
display(random, length) ; // Call display() function to print sorted array in terminal
display(random_fl, length_fl) ;
//display(random_char, length_char) ;
return 0 ;
}
// Template function definitions
template <class T>
void order(T& a, T& b) { // order function using references
T Temp = a ;
a = b ;
b = Temp ;
}
template <class T>
void sort(T* c, int d) { // Sorting function
for (int i=0; i<d-1; i++) {
for (int j=0; j<d-1-i; j++) {
if(c[j+1] > c[j]) {
order(c[j] , c[j+1]) ;
}
}
}
}
template<>
void sort(const char* a, int b) { // Template specialization sort function for character string
for (int i=0; i<b-1; i++) {
for (int j=0; j<b-1-i; j++) {
if(strcmp(a[j+1], a[j])>0) {
order(a[j], a[j+1]) ;
}
}
}
}
template <class T>
void display(T* e, int f) { // Display function
cout << "Sorted Array: ";
for (int i=0; i<f; i++) {
cout << e[i] << " ";
}
cout << endl ;
}
When compiling the script, I get the error saying that an invalid conversion is occurring from 'char' to 'const char*' in the strcmp(const char*, const char*) function inside my specialized template function. I am wondering why, since I have defined a const char* array with 10 string literals. So the array elements a[j+1] and a[j] should be const char* elements as well since this is what they are expected to be at the start of the specialized sort function with the definition of const char* a.
I am fairly new to c++ and have especially difficulty in understanding pointers and how to refer to array elements with pointers/references which I think is at the root of this problem.
Please don't mind my English and thank you in advance.
Edit:
Even though my if() statement to get a sorted character string is not correct yet, as pointed out by Steiner, the strcmp() is now working as intended.
I thank you all kindly for your help.
As partially mentioned by #Arkadiy, you are missing a star in the specialization of sort for the const char* and the if condition is not correct :
template<>
void sort(const char** a, int b) {
for (int i=0; i<b-1; i++) {
for (int j=0; j<b-1-i; j++) {
if( strcmp(a[j+1], a[j]) > 0 ) {
order(a[j], a[j+1]) ;
}
}
}
And this specialization must appear before the main otherwise you get a compiler error of the type: specialization after instantiation (see this question).
If you change this you get the correct output :
Initial chararacter Array: blah blahblah string character literal one randomize unsigned red wolf
Sorted Array: wolf unsigned string red randomize one literal character blahblah blah
The compiler will complain if you pass a const variable to a function the takes a non-const argument. An element of a const char* is a const char, and that is not compatible with your function order(T&, T&).
Besides that, there are a few other issues with your program, such as the parentheses of strcmp(), and the usage of strcmp() with single chars at all.
My previous answer was a nonsense, steiner answer is correct, your sort template should be:
template<>
void sort(const char** a, int b) {
and be located above its point of instantiation (i.e. above main())

Array pointer to the attribute of an array of struct [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
I have the following struct and main function:
struct myStruct{
string name;
int id;
int group;
};
int main(){
myStruct student[5]; // The struct student has an array of 5 elements
search(student, 1, 33); // We pass the struct student with all the 5 elements
}
I want to pass a struct to the function search, and then make an array pointer that stores the value of a certain attribute, but of all the arrays of the struct.
*e is pointing to student, with all the arrays(5), so if type equals 1 the pointer is going to point to all the values of the attribute of each array of the structure e
void search(myStruct *e, int type, int value){
if (type == 1) int *ptr[] = e[0]->id; //An int pointer because the id is an int
if (type == 2) int *ptr[] = e[0]->group;
for (int i = 0; i < 5; i++){
if(*ptr[i] == value){
cout << e[i]->name << endl;
cout << e[i]->id << endl;
cout << e[i]->group << endl;
}
}
}
I want *ptr[] pointing to each array of the attribute depending on the parameter passed in type. Ex:
if ( type == 1 )
ptr[0] = e[0].id;
ptr[1] = e[1].id;
ptr[2] = e[2].id;
ptr[3] = e[3].id;
ptr[4] = e[4].id;
^Notice that is just the id
if ( type == 2 )
ptr[0] = e[0].group;
ptr[1] = e[1].group;
ptr[2] = e[2].group;
ptr[3] = e[3].group;
ptr[4] = e[4].group;
^Notice that is just the group
The problem is that I can't find a way to do that, the real struct in my program has more than just three attributes, it actually has eight, so it will be a waste of code if I do a case for each one.
Thanks for your help.
One way to do this is to make a "pointer to member". Note: This isn't an array of pointers, but rather a pointer that you can only use with an object of the class.
Also note: this is reasonably advanced, so you might want to get normal pointers straight in your head first.
void search(myStruct *e, int type, int value) {
int myStruct::*ptr; // ptr is a pointer to a member variable of an object
if (type == 1) ptr = &myStruct::id;
if (type == 2) ptr = &myStruct::group;
for (int i = 0; i < 5; i++){
if (e[i].*ptr == value){ // access the value of the current object using ptr.
cout << e[i].name << endl; // Note that you had these accesses wrong.
cout << e[i].id << endl;
cout << e[i].group << endl;
}
}
}
A very hack approach that is somewhat low-level and only applies to POD struct type whose attributes are of the same type (e.g., int) and stored continuously.
Suppose your struct looks like this:
struct myStruct {
string name;
int attr1;
int attr2;
...
int attr8;
}
You can write your search function as follow:
void search(myStruct *e, int type, int value) {
int *ptr[5];
for (int i = 0; i < 5; ++i) {
int *base = &e[i].attr1; // treat attr1...attr8 as an int array
ptr[i] = &base[type - 1];
if (*ptr[i] == value) {
cout << e[i].name << endl;
for (int j = 0; j < 8; ++j) {
cout << base[j] << endl;
}
}
}
}

How to make all array elements accessible [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
I've been trying to make the elements of an array accessible, but I've had no success so far. This is the code, and I've created it due to the given assignment.
#include<iostream>
#include<iomanip>
#include<cmath>
using namespace std;
class Matrix_1D
{
private:
int *p2values;
int num_elements;
public:
Matrix_1D(int *p2v, int n); // CTOR
~Matrix_1D(); // DTOR
void show();
};
Matrix_1D::Matrix_1D(int *p2v, int n)
{
n = sizeof(p2v)/sizeof(int); // the problem comes from the fact that sizeof(p2v) = 4 bytes, and not the length of the entire array!!!
num_elements = n;
p2values = new int [n];
for(int i = 0; i<num_elements; i++)
p2values[i] = p2v[i];
}
Matrix_1D::~Matrix_1D()
{
delete [] p2values;
}
void Matrix_1D::show()
{
for(int i=0; i<num_elements; i++)
cout << p2values[i] << endl;
}
int main()
{
int array_a[] = {5,3,5};
Matrix_1D fkt_1D_a(array_a, sizeof(array_a)/sizeof(int));
fkt_1D_a.show();
system("pause");
return 0;
}
Matrix_1D::Matrix_1D(int *p2v, int n)
{
n = sizeof(p2v)/sizeof(int); // the problem comes from the fact that sizeof(p2v) = 4 bytes, and not the length of the entire array!!!
num_elements = n;
p2values = new int [n];
for(int i = 0; i<num_elements; i++)
p2values[i] = p2v[i];
}
As you state the sizeof p2v is the size of the pointer so you have no idea how large the array is. Instead, use the parameter that is passed in and don't overwrite it:
Matrix_1D::Matrix_1D(int *p2v, int n)
{
// you don't need the first line at all.
num_elements = n;
p2values = new int [n];
for(int i = 0; i<num_elements; i++)
p2values[i] = p2v[i];
}
The proper C++ way to get the size of your int array is to use a template:
template <typename T, size_t N>
size_t size(T (&)[N]) {
return N; // size of array
}

Two dimensional arrays error [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question appears to be off-topic because it lacks sufficient information to diagnose the problem. Describe your problem in more detail or include a minimal example in the question itself.
Closed 9 years ago.
Improve this question
#include<iostream>
using namespace std;
double NUMB_COLS = 3;
void readMatrix(int matr[] [3], int numb_rows, int numb_cols)
{
for (int i = 0; i<numb_rows; i++)
{
for (int j = 0; j < numb_cols; j++)
{
cout <<"[" << i << "] [" <<j <<"] =";
cin >> matr[i][j];
}
}
}
void printMatr(int matr[][3], int numb_rows, int numb_cols)
{
for (int i = 0; i < numb_rows; i++)
{
for (int j = 0; j < numb_cols; j++)
{
cout << "[" << i << "][" << j << "] = " << matr[i][j];
}
cout << endl;
}
}
int main()
{
int matr[5][10];
printMatr(matr, 4, 5);
readMatrix(matr, 4, 5);
return 0;
}
The error is
31 23 C:\Users\Windows\Desktop\programs\arrays2.cpp [Error] cannot convert 'int ()[10]' to 'int ()[3]' for argument '1' to 'void readMatrix(int (*)[3], int, int)'
What to do??
The first error is, that you pass a pointer to matr to a function expecting a different array layout. Remember that all ints in matr are consecutive in memory. Even if you did cast your matr to the expected type before passing it to the function, what was at position matr[0][7] in main() will end up in position matr[2][1] inside readMatrix().
The second error is, that your function accepts a column count, even though it already declared the column count to be 3. Such inconsistencies are an ample source of bugs, and should be avoided at all cost. Unfortunately, C++ forbids you to use dynamically sized array types, so you cannot just change your function declaration to
void readMatrix(int numb_rows, int numb_cols, int matr[numb_rows][numb_cols]) {
as you can in C.
The easiest way to fix your problem is probably to use std::vector<>.
You need to specify the correct subscripts.
void readMatrix(int matr[5][10], int numb_rows, int numb_cols)
a std::vector would be a lot easier in this case.
You defined the array in main as
int matr[5][10];
but in the functions the corresponding parameter is defined as
int matr[][3]
They are different types.
If you want to use in the functions only a part of the array int matr[5][10]; that is only 4 first rows and 5 first columns then you have to define the corresponding parameter of the functions the same way as the original array that is as
int matr[][10];
For example
void printMatr(int matr[][10], int numb_rows, int numb_cols)
Or you have to change code in main and write
int matr[5][3];
printMatr(matr, 5, 3);
readMatrix(matr, 5, 3);
Also take into account that you defined variable
double NUMB_COLS = 3;
but do not use it (thogh it should be defined having integral type).
If you would write
const int NUMB_COLS = 3;
and then use it in array definitions there would not be such an error. For example
#include<iostream>
using namespace std;
const int NUMB_COLS = 3;
void readMatrix(int matr[] [NUMB_COLS], int numb_rows, int numb_cols)
{
for (int i = 0; i<numb_rows; i++)
{
for (int j = 0; j < numb_cols; j++)
{
cout <<"[" << i << "] [" <<j <<"] =";
cin >> matr[i][j];
}
}
}
void printMatr(int matr[][NUMB_COLS], int numb_rows, int numb_cols)
{
for (int i = 0; i < numb_rows; i++)
{
for (int j = 0; j < numb_cols; j++)
{
cout << "[" << i << "][" << j << "] = " << matr[i][j];
}
cout << endl;
}
}
int main()
{
int matr[5][NUMB_COLS];
printMatr(matr, 5, NUMB_COLS);
readMatrix(matr, 5, NUMB_COLS);
return 0;
}
You can assign NUMB_COLS any number including 10 used in your original code. The code I showed will not depend on "magic numbers". It uses only named constant NUMB_COLS

Template specialization error - C++ (C++ Primer Plus exercise)

I'm currently learning C++ so I don't have much knowledge on the topic . I'm using the C++ primer plus book and here's the problem :
Write a template function maxn() that takes as its arguments an array of items of type T
and an integer representing the number of elements in the array and that returns the
largest item in the array. Test it in a program that uses the function template with an
array of six int value and an array of four double values. The program should also
include a specialization that takes an array of pointers-to-char as an argument and the
number of pointers as a second argument and that returns the address of the longest
string. If multiple strings are tied for having the longest length, the function should
return the address of the first one tied for longest. Test the specialization with an array of
five string pointers.
Here's my code :
#include <iostream>
#include <cstring>
using namespace std;
template <class T> T maxn(T arr[] , int n);
template <> char * maxn<char (*)[10]> (char (*arr)[10] , int n);
int main()
{
double array[5] = { 1.2 , 4.12 ,7.32 ,2.1 ,3.5};
cout << endl << maxn(array , 5) << endl << endl;
char strings[5][6] = { "asta" , " m" , "ta" , "taree" , "e"};
cout << maxn(strings , 5) << endl;
return 0;
}
template <class T> T maxn(T arr[] , int n)
{
T max = 0;
for (int i = 0 ; i < n ; ++i)
{
if (arr[i] > max)
max = arr[i];
}
return max;
}
template <> char * maxn<char (*)[10]> (char (*arr)[10] , int n)
{
int length = 0;
int mem = 0;
for ( int i = 0 ; i < n ; ++i)
{
if (strlen(arr[i]) > length)
{
length = strlen(arr[i]);
mem = i;
}
}
return arr[mem];
}
I'm trying to pass an array of strings . I get the following errors :
g++ -Wall -o "untitled5" "untitled5.cpp" (in directory: /home/eukristian)
untitled5.cpp:6: error: template-id ‘maxn<char (*)[10]>’ for ‘char* maxn(char (*)[10], int)’ does not match any template declaration
untitled5.cpp: In function ‘int main()’:
untitled5.cpp:14: error: no matching function for call to ‘maxn(char [5][6], int)’
untitled5.cpp: At global scope:
untitled5.cpp:31: error: template-id ‘maxn<char (*)[10]>’ for ‘char* maxn(char (*)[10], int)’ does not match any template declaration
Compilation failed.
I'm quite sure I've made some newbie mistake and I can't detect it .
Thanks .
char (*)[10] is a pointer to an array of 10 chars. char *[10] is an array of 10 char pointers.
Also you're specifying a different type for the return value than for T. I.e. if the function is supposed to return char*, the value for T should be char*, too. Your specialization should look like this:
template <> char * maxn<char *> (char *arr[] , int n);
Also your array of strings should be of type char *[5].
The program should also include a specialization that takes an array of pointers-to-char as an argument and the number of pointers as a second argument and that returns the address of the longest string.
What you have in your code is not that, it's a two-dimensional array of characters (a single block of 5 * 6 bytes of memory). Compare with array of five pointers
const char* strings[5] = {"asta" , " m" , "ta" , "taree" , "e"};
Your code is also making the assumption that 0 is the smallest value for any T.
#include <iostream>
#include <cstring>
#include <locale>
//#include <windows.h>
using namespace std;
const int maxcharval = 5;
const int maxintval = 6;
const int maxdoubleval = 4;
template <typename T>
T maxn(T* arr, int n);
template <> const char * maxn <const char *> (const char* arr[], int n);
int main(int argc, char *argv[])
{
//setlocale(LC_CTYPE, ".866");
const char * charr[] = {"qwer","qwert","qwe","qw","q"};
const int intarr[] = {1,3,2,5,3,0};
const double doublearr[] = {5.4, 2.3, 3.1, 3.2};
cout << "maxint: " << maxn(intarr, maxintval) << endl;
cout << "maxdouble: " << maxn(doublearr, maxdoubleval)
<< endl;
cout << "maxcharstring:" << maxn(charr, maxcharval)
<< endl;
//system("pause");
return 0;
}
template <typename T>
T maxn(T *arr, int n)
{
T* value = &arr[0];
for (int i = 1; i < n; i++)
{
if (*value < arr[i])
value = &arr[i];
}
return *value;
}
template <> const char * maxn <const char *>(const char* arr[], int n)
{
const char* val = arr[0];
for (int i = 1; i < n; i++)
{
if (strlen(val) < strlen(arr[i]))
val = arr[i];
}
return val;
}
It's work. Good luck!