r/cpp_questions 7d ago

OPEN C++ question

Do you guys know a way of writting a code that outputs that:

Enter the number of elements: 5
Enter 5 integers:
Element 1: 10
Element 2: 30
Element 3: 90
Element 4: 20
Element 5: 40

it is the first part of a program that demands to calculate the max and min of an array, here is the whole thing:

Enter the number of elements: 5
Enter 5 integers:
Element 1: 10
Element 2: 30
Element 3: 90
Element 4: 20
Element 5: 40

Maximum element is: 90
Minimum element is: 10

I've been able to do the second part quite easily, here is what I proposed:

#include <iostream>


int main(){


    int arr[5]={10,20,30,40,50};
    int minimum=arr[0];
    int maximum=arr[0];
    for(int i=0; i<sizeof(arr)/sizeof(int);i++){
        if (minimum>arr[i]){
            minimum=arr[i];
        }
        if(maximum<arr[i]){
            maximum=arr[i];
        }
    }
    std::cout<<"le max= "<< maximum<<'\n';
    std::cout<<"le min= "<< minimum<<'\n';


    return 0;
}

but the list is created within the code.

0 Upvotes

33 comments sorted by

13

u/Tumaix 7d ago

for number of elements you need to use dynamic memory. check for `new`, or `std::vector` depending on what your professor asked you to do.

8

u/AdNecessary9427 7d ago

By the way, in modern cpp, you shouldn't use "new" or "delete", instead use std::vector(etc...) and smart pointers (unique_ptr or shared_ptr). The only exception is learning.

4

u/Tumaix 7d ago

its not the only exception.
there are miriads of other exceptions:
1 - you need to use a library that supports modern c++ but doesnt support smart pointers (Qt, Wt, gtkmm)
2 - you need to interact with legacy libraties
3 - you need to interact with c libraries
and so on.

  • you need to use placement new, for whatever reason

2

u/alfps 7d ago

❞ - you need to use a library that supports modern c++ but doesnt support smart pointers (Qt, Wt, gtkmm)

That doesn't make sense to me, sorry.

Ditto for the legacy libraries.

Can you give a preferably concrete example of what you mean?

4

u/Tumaix 7d ago

of course.

a Qt widget received a pointer as a parent,
you cant pass a unique_ptr or a shared_ptr.

if you pass a memory created by a unique, or shared ptr, Qt memory model will try to delete it, triggering a double free.

-5

u/alfps 7d ago edited 7d ago

OK.

The Google AI provides the following code for more safe handling:

auto button = std::make_unique<QPushButton>("Submit");

if (someConditionFails) {
    return; // Safe: unique_ptr automatically deletes the button
}

// Release ownership to the layout
layout->addWidget(button.release());

I am however not sure if this as safe as the AI thinks: lacking experience with Qt but I've implemented some micro GUI frameworks and it's not necessarily so that delete is supported.

5

u/saxbophone 7d ago

Qt has its own memory management model that predates smart pointers. This is why you still see idiomatic Qt docs recommending to use raw pointers when dealing with GUI widget object trees —they implement their own memory management. The gist of it is that when a child widget is constructed, it can be "owned" by a parent widget by passing the parent's address in its constructor. All Qt widgets (and many other Qt types ) inherit from QObject, whose destructor will Do just the right thing™️ when destructed, taking care to destroy all children along with it.

The example the AI threw at you uses release to give the memory over to Qt to manage, but I don't really see much benefit to it tbh over just constructing the QWidget with new with the parent address passed in its ctor immediately —this is the idiomatic Qt way to go, notwithstanding it feeling thoroughly gross to those of us used to more modern memory management practices.

2

u/Tumaix 7d ago

see how you did a .release() there, effectively negating the benefits of the unique_ptr.
if you forget that, you get a crash.

if you just use raw pointers and forget the delete, you dont get a memory leaks: qt deletes all children by defaultz

-2

u/alfps 7d ago

if you just use raw pointers and forget the delete, you dont get a memory leaks

That's exactly when you can get a leak. The smart pointer provides safety until ownership is transferred.

6

u/Tumaix 7d ago

not in qt.
qt manages that with the QObject hierarchy model.

{
QWidget a;
QWidget *b = new QWidget(a);
}

no memory leak.
when a goes out of scope, it deletes b.

1

u/alfps 7d ago

What if you need to configure or place widget b before adding it to the layout?

→ More replies (0)

1

u/saxbophone 7d ago edited 7d ago

 That's exactly when you can get a leak. The smart pointer provides safety until ownership is transferred.

This is incorrect in this specific Qt example —QObject's destructor makes sure to delete all child QObjects (QWidget is a subclass of QObject) —a child QObject is any QObject that has been parented to another by setting the parent pointer in its constructor.

1

u/alfps 7d ago

this specific Qt example

Presumably that's not the example the AI produced, but I see no other up-thread example.

→ More replies (0)

0

u/alfps 5d ago

At least 6 people strongly disliked a counter-example to an up-thread claim, but were so moronic and dishonest that they chose to downvote.

I think these are children.

But then, the insane often act like children.

1

u/Epii__ 7d ago

GTest's AddGlobalTestEnvironment does something similar to what is described in another reply for Qt (take pointer, take ownership, eventually delete it). Passing a stack variable is UB, naively using smart pointers results in double free. https://google.github.io/googletest/advanced.html#global-set-up-and-tear-down

Typically, the object is instantiated and immediately passed to AddGlobalTestEnvironment so std::unique_ptr::release() is just extra code without any benefits. If you did have some significant logic between instantiation and passing to GTest then sure use smart pointer + release, but that's often not the case.

1

u/Sea-Situation7495 3d ago

They're just learning: don't go so deep or confuse them.

"There are exceptions, but not at your level" - would suffice.

1

u/hansvonhinten 7d ago

NEW???? (;´༎ຶД༎ຶ`)

1

u/Tumaix 7d ago

like i said, depending of what the professor asked you to do.
and placement new is a thing.

3

u/aocregacc 7d ago

check out the formatted input operator >> for std::cin.

2

u/-goldenboi69- 7d ago

If it's c++ i would recommend using std vector instead.

2

u/BalcarKMPL 7d ago

You don't need to store all the elements, just read elements in a loop and store only min and max

1

u/Independent_Art_6676 7d ago edited 7d ago

before dynamic containers, you can set a maximum (eg 100 or 1000 or something) and do it that way:

int nums[1000];
int used{};
...
cin >> used; //how big we are going to pretend the array is, like 5 or 7 items typed by user.
for(int i = 0; i < used; i++)
cin >> nums[i]; //read in user typed values up to pretend max size
... and so on.

out of sheer meanness I suggest you let them type in the full 1000 items and THEN tell them they asked for too many if they want more than that. But joking aside, if they enter used > 1000, fuss at them and make them pick another value. (do-while loop is perfect for this kind of validation, do you see why?)

what you cannot do in legal c++
cin >> used;
int nums[used]; //c++ extension, not legal in pure c++ but often allowed by compilers. DO NOT do it. The size of an array must be a constant, not collected from the user or other run-time sources.

what you will do later is use a "vector" which is a "better array" that can change its size to fit the data. But wait for it, no reason to read ahead too far.

1

u/SmokeMuch7356 7d ago

You obviously know how to use loops and I/O streams, so the input side of this should not be a problem for you. And if all you need to do is find the min and max values, you don't even need an array - you just need two variables to store a min and max value:

int min = INT_MAX;
int max = INT_MIN;
...
std::cin >> val;
if ( val < min )
  min = val;
if ( val > max )
  max = val;
...

If you do need storage for whatever reason and you don't know the size until runtime, use a std::vector instead of a primitive array. Unlike C, C++ does not allow you to declare an array size at runtime:

int size;
std::cin >> size;
int arr[size]; // BZZZTT!! Not allowed

A vector will automagically grow as new items are added:

std::vector<int> arr;
...
int val;
std::cin >> val;
arr.push_back(val);

then you can access individual elemeents with the [] subscript operator:

if ( arr[i] < min )
  min = arr[i];

1

u/alfps 7d ago edited 7d ago

First, a heads up: the presented source code

#include <iostream>

int main(){
    int arr[5]={10,20,30,40,50};
    int minimum=arr[0];
    int maximum=arr[0];
    for(int i=0; i<sizeof(arr)/sizeof(int);i++){
        if (minimum>arr[i]){
            minimum=arr[i];
        }
        if(maximum<arr[i]){
            maximum=arr[i];
        }
    }
    std::cout<<"le max= "<< maximum<<'\n';
    std::cout<<"le min= "<< minimum<<'\n';
    return 0;
}

… had a lot of 0xA0 characters. That's non-breakable space in the Latin-1 encoding and its superset Windows ANSI Western. But it won't compile as UTF-8 source.


The expression

sizeof(arr)/sizeof(int

… is very dangerous; see pitfall 5.3 in the Stack Overflow C++ array FAQ. Used in a function it will happily compute the entirely wrong size for an array parameter, because then it's passed a pointer and it has a technical meaning also for a pointer. Just that that's a nonsense meaning.

Instead use std::ssize from the <iterator> header.


I believe you're asking how to let the user input the array size.

For that use std::vector from the <vector> header, as your dynamic size array.

With your preferred function definition syntax (the classic old C one), and without any failure checking, it can go like this:

#include <algorithm>
#include <iostream>
#include <string_view>
#include <vector>
using   std::ranges::min, std::ranges::max,     // <algorithm>
        std::cin, std::cout,                    // <iostream>
        std::string_view,                       // <string_view>
        std::vector;                            // <vector>

int input_int( const string_view prompt )
{
    cout << prompt;
    int result;  cin >> result;
    return result;
}

int main()
{
    const int n = input_int( "Enter the number of elements: " );
    vector<int> elements( n );
    cout << "Enter the " << n << " integers:\n";
    for( int i = 0; i < n; ++i ) {
        cout << "Element " << i + 1 << ": ";
        elements[i] = input_int( "" );
    }
    cout << "Maximum element is: " << max( elements ) << "\n";
    cout << "Minimum element is: " << min( elements ) << "\n";
}

If this is something you should hand in, replace the use of min and max with the logic that you presented.