Ok, so I was getting some pretty off course answers so I thought I would edit this post and add the notes from the textbook for clarity:
Sometimes, the number of elements in the array might be less than the size of the array. For example, the number of elements in an array storing student data might increase or decrease as students drop or add courses. In such situations, we want to process only the components of the array that hold actual data. To write a function to process such arrays, in addition to declaring an array as a formal parameter, we declare another formal parameter specifying the number of elements in the array, as in the following function:
void initialize(int list[], int listSize)
{
int count;
for (count = 0; count < listSize; count++)
list[count] = 0;
}
The first parameter of the function initialize is an int array of any size. When the function initialize is called, the size of the actual array is passed as the second parameter of the function initialize.
Ok, now that I posted the entire example with textbook notes in it, my confusion is why they set the array to zero. The notes give me the impression that this function is allowing a user to use the array for any size that they wish because the size is set to zero which (I am guessing here) allows the user to pick any size array they want? and it will just reset every time back to zero so if you need more or less units for the next time, it will be default to zero so you can fill it again?
you said:
I know the function initialize is used to determine the value of the
array list by passing the value of the array to listsize
no. it's not true. this function is not to determine something but to INITIALIZE all the array (up to listsize index, btw: it might be dangerous since you can pass listsize greater than this list size in fact) with 0.
and
by passing the value of the array to listsize
no! listsize is here not the value of element, it is array size, look at "for" loop #Jason xD.
have you tried to call this function on some array with some listsize?
If your code was properly formatted, it might be more apparent that the statement list[count] = 0; gets executed each time through your for loop.
That is, it sets an element to zero each time through the loop. The result is that after the loop is complete, all elements in the array will be set to zero.
If you are talking about the "count = 0", then:
The more usual syntax is:
for(int blah = 0; blah < max; blah++)
But there's no reason why 'blah' has to be declared inside the for() statement itself:
int blah;
for(blah = 0; blah < max; blah++)
...is also acceptable.
Or:
int blah = 0;
for( ; blah < max; blah++)
Sometimes (but not in your example) it's desired to have 'blah' exist beyond the scope of the for() statement, so you can do something with it afterward:
int fileNum = 0;
for( ; fileNum < maxFiles && file_exists(fileNum); fileNum++)
{
//...do something...
}
int lastFileWas = fileNum; //Either it's 'maxFile', or the first file that didn't exist.
Another reason for putting variables outside of the for() statement, is when variables are really really large, and it would make the code easier to read if it's outside of the statement:
std::vector< std::pair<std::string, int> >::iterator myIterator = myVector.begin();
for( ; myIterator != myVector.end(); myIterator++)
This would be very messy if it was inside the for-statement itself (std::vector< std::pair >::iterator is a very long variable name to write out that would be messy to cram into a for() statement). (Though this is less a problem with C++11's 'auto' keyword).
If you are talking about the "list[count] = 0;", then:
With arrays, to assign a value, you "index into" the array using the square brackets (called the 'subscript operator'), and you can access individual variables (called 'elements') held in the memory of the array:
int myArray[10]; //10 integers in a block of memory.
myArray[0] = 5; //Accessing the first element in the block of memory.
myArray[3] = 17; //Accessing the fourth element in the block of memory.
In general:
Since you are using C++, you usually (90% of the time) would be better off using a std::vector. Arrays are rather odd, because they are very similar to pointers to blocks of memory, and can't be treated like regular variables. A std::vector, aside from many other benefits, wraps the array so you can treat it like a regular variable (because a vector is one).
Another quick way of accomplishing the same thing:
memset(list, 0, sizeof(int)*listSize);
This gets the whole block of memory allocated to list by calculating the size of the data type times the number of elements and setting it all to 0.
It is doing what it says, it is initializing. In this case the method is just setting every element of list to 0. It is probably more clear if you add braces:
for (count = 0; count < listSize; count++)
{
list[count] = 0;
}
So based on your updated post, the book's description is saying 1) You may not want to process the whole array because only a portion of it may have valid data 2) In order to write functions to process arrays that behave this way, functions that process these array's must not only take the array as a parameter but also the number of valid elements. 3) We are going to provide an example function initialize which follows the rules we just described BUT nothing in the text actually speaks to end result of initialize.
My above description as well as the other posts provide an accurate description of initialize.
Related
int size = 10;
int arr[size] = {};
for(int i = 0; i < size; i++)
arr[i] = i;
Now how do I find if the array is filled or not in the code.
I know arr[size - 1] = 9, but what is arr[size] and beyond?
How do i compare arr[size] == ? using if statement, or is there another way? I am using ubnutu and this is the compiler g++ (Ubuntu 9.3.0-10ubuntu2) 9.3.0.
When you use raw arrays, it is your responsibility to handle that memory and keep track of what has been written.
This sounds like a good usecase for a std:vector instead. Especially by making use of its reserve(size) function.
With reserve you tell how much memory to keep for your data and then you can fill that array with push_back(content), retrieving the current number of filled elements with size() (of course reserve is just an optimization to avoid re-allocating the memory because even without it, a vector will dynamically grow).
Now how do I find if the array is filled or not
All arrays are always "filled". An array of N elements contains N elements and no less.
An element of trivial type could have an indeterminate value. There is no way to find whether a value is indeterminate. The behaviour of reading an indeterminate value is undefined.
In your example, you value initialised the array, so it is filled with value initialised elements (before the loop where you change the values). Which in case of int means that the array is filled with zeroes. You can test whether an element is zero or not like this:
if (arr[i])
// not zero
else
// is zero
but what is arr[size] and beyond?
There is no "arr[size] and beyond" because those indices are outside the bounds of the array. The behaviour of accessing values outside the bounds of an array is undefined.
I was recently learning to use struct datatype in c++. I know how the basics of struct datatype work and how to manipulate its variables. But I was wondering how would I determine the end of struct datatype array. For example consider the code below:
struct PersonDetails
{
string name, address;
int age, number;
}
Now in c++ program I create an array of struct type as follows:
PersonDetails Data[500];
Now consider that I have 30 records in data array and I have to display these records by looping through data array's index. So how would I determine that I have to loop through only first 30 indexes as the data is only stored in these indexes. As in char array we compare all indexes with '\0' to determine the end of array. Then what method will we use for Data[] array?
An edit that I have no idea about Vectors and the project i am working on requires me to use basics of c++(functions, control structures, loops, etc.).
It's not feasible.
For char[], back in times of C standardization, developers agreed to use \0 (integer value 0) as a special character marking end-of-string. Everything works as long as everyone is following this convention (i.e. both standard library functions and developers using those functions).
If you wanted to have such a convention for your type, you could just write down "Data object with both strings empty and both ints equal to 0 is array terminator", but you would have to follow this convention. You'd have to write functions that would stop processing array upon finding such an object. You'd have to make sure that in every array there is at least one such object.
Instead
You should use std::vector<Data> which can automatically accomodate for any number of Data objects and will now precisely how many of them are currently stored (using size() method)
or
use std::array<Data, 30>, which can store exactly 30 objects and you can assume all of them are valid objects.
IMHO the correct way to solve this is to not use a C-style array, but instead use a std::array or std::vector that knows it's .size().
Iterating a std::vector or std::array is trivial:
for (const auto& element : Data_array) {
// Do something with the array element
}
See also:
https://en.cppreference.com/w/cpp/container/array
https://en.cppreference.com/w/cpp/container/vector
https://en.cppreference.com/w/cpp/language/for
https://en.cppreference.com/w/cpp/language/range-for
The simplest solution is to just have a separate variable specifying how many array elements are filled in.
PersonDetails Data[500];
int numPersons = 0;
Data[0].name = ... ;
Data[0].address = ...;
Data[0].age = ...;
Data[0].number = ...;
numPersons = 1;
Data[1].name = ... ;
Data[1].address = ...;
Data[1].age = ...;
Data[1].number = ...;
numPersons = 2;
...
Then you use that variable when looping through the array.
for (int i = 0; i < numPersons; ++i)
{
// use Data[i] as needed...
}
I don't really agree using std::array makes any difference.
The problem you currently have doesn't occur in whether we have such an element in the container, but whether the element we are inspecting useful.
Consider the example you gave, for an array of chars, we simply check whether one of the elements is \0 to decide whether or not we should halt the iteration.
How does that work? The ramaining elements, of course, default initialized to be \0, they exist, but of no use.
Similarly, you can check, in this example, whether
name.empty()
Or, in order to avoid any possible exception, as mentioned in the comment section, do this:
add user-defined constructor to the class ( or struct, they are same actually.) which initialize age to -1 and then check if age == -1.
because it's impossible for a people not having any name, that means, you have not assign to any of the remaining elements. Thus, stop iteration.
As a supplement, using std::vector makes sense, but if that isn't a option for you for the time being, you don't need to consider it.
I'm still quite inexperienced in C++ and i'm trying to write sum code to add numbers precisely. This is a dll plugin for some finite difference software and the code is called several million times during a run. I want to write a function where any number of arguments can be passed in and the sum will be returned. My code looks like:
#include <cstdarg>
double SumFunction(int numArgs, ...){ // this allows me to pass any number
// of arguments to my function.
va_list args;
va_start(args,numArgs); //necessary prerequisites for using cstdarg
double myarray[10];
for (int i = 0; i < numArgs; i++) {
myarray[i] = va_arg(args,double);
} // I imagine this is sloppy code; however i cannot create
// myarray{numArgs] because numArgs is not a const int.
sum(myarray); // The actual method of addition is not relevant here, but
//for more complicated methods, I need to put the summation
// terms in a list.
vector<double> vec(numArgs); // instead, place all values in a vector
for (int i = 0; i < numArgs; i++) {
vec.at(i) = va_arg(args,double);
}
sum(vec); //This would be passed by reference, of course. The function sum
// doesn't actually exist, it would all be contained within the
// current function. This is method is twice as slow as placing
//all the values in the static array.
double *vec;
vec = new double[numArgs];
for (int i = 0; i < (numArgs); i++) {
vec[i] = va_arg(args,double);
}
sum(vec); // Again half of the speed of using a standard array and
// increasing in magnitude for every extra dynamic array!
delete[] vec;
va_end(args);
}
So the problem I have is that using an oversized static array is sloppy programming, but using either a vector or a dynamic array slows the program down considerably. So I really don't know what to do. Can anyone help, please?
One way to speed the code up (at the cost of making it more complicated) is to reuse a dynamic array or vector between calls, then you will avoid incurring the overhead of memory allocation and deallocation each time you call the function.
For example declare these variables outside your function either as global variables or as member variables inside some class. I'll just make them globals for ease of explanation:
double* sumArray = NULL;
int sumArraySize = 0;
In your SumFunction, check if the array exists and if not allocate it, and resize if necessary:
double SumFunction(int numArgs, ...){ // this allows me to pass any number
// of arguments to my function.
va_list args;
va_start(args,numArgs); //necessary prerequisites for using cstdarg
// if the array has already been allocated, check if it is large enough and delete if not:
if((sumArray != NULL) && (numArgs > sumArraySize))
{
delete[] sumArray;
sumArray = NULL;
}
// allocate the array, but only if necessary:
if(sumArray == NULL)
{
sumArray = new double[numArgs];
sumArraySize = numArgs;
}
double *vec = sumArray; // set to your array, reusable between calls
for (int i = 0; i < (numArgs); i++) {
vec[i] = va_arg(args,double);
}
sum(vec, numArgs); // you will need to pass the array size
va_end(args);
// note no array deallocation
}
The catch is that you need to remember to deallocate the array at some point by calling a function similar to this (like I said, you pay for speed with extra complexity):
void freeSumArray()
{
if(sumArray != NULL)
{
delete[] sumArray;
sumArray = NULL;
sumArraySize = 0;
}
}
You can take a similar (and simpler/cleaner) approach with a vector, allocate it the first time if it doesn't already exist, or call resize() on it with numArgs if it does.
When using a std::vector the optimizer must consider that relocation is possible and this introduces an extra indirection.
In other words the code for
v[index] += value;
where v is for example a std::vector<int> is expanded to
int *p = v._begin + index;
*p += value;
i.e. from vector you need first to get the field _begin (that contains where the content starts in memory), then apply the index, and then dereference to get the value and mutate it.
If the code performing the computation on the elements of the vector in a loop calls any unknown non-inlined code, the optimizer is forced to assume that unknown code may mutate the _begin field of the vector and this will require doing the two-steps indirection for each element.
(NOTE: that the vector is passed with a cost std::vector<T>& reference is totally irrelevant: a const reference doesn't mean that the vector is const but simply puts a limitation on what operations are permitted using that reference; external code could have a non-const reference to access the vector and constness can also be legally casted away... constness of references is basically ignored by the optimizer).
One way to remove this extra lookup (if you know that the vector is not being resized during the computation) is to cache this address in a local and use that instead of the vector operator [] to access the element:
int *p = &v[0];
for (int i=0,n=v.size(); i<n; i++) {
/// use p[i] instead of v[i]
}
This will generate code that is almost as efficient as a static array because, given that the address of p is not published, nothing in the body of the loop can change it and the value p can be assumed constant (something that cannot be done for v._begin as the optimizer cannot know if someone else knows the address of _begin).
I'm saying "almost" because a static array only requires indexing, while using a dynamically allocated area requires "base + indexing" access; most CPUs however provide this kind of memory access at no extra cost. Moreover if you're processing elements in sequence the indexing addressing becomes just a sequential memory access but only if you can assume the start address constant (i.e. not in the case of std::vector<T>::operator[]).
Assuming that the "max storage ever needed" is in the order of 10-50, I'd say using a local array is perfectly fine.
Using vector<T> will use 3 * sizeof(*T) (at least) to track the contents of the vector. So if we compare that to an array of double arr[10];, then that's 7 elements more on the stack of equal size (or 8.5 in 32-bit build). But you also need a call to new, which takes a size argument. So that takes up AT LEAST one, more likely 2-3 elements of stackspace, and the implementation of new is quite possibly not straightforward, so further calls are needed, which take up further stack-space.
If you "don't know" the number of elements, and need to cope with quite large numbers of elements, then using a hybrid solution, where you have a small stack-based local array, and if numargs > small_size use vector, and then pass vec.data() to the function sum.
I am attempting to write a template/class that has a few functions, but I'm running into what seems like a rather newbie problem. I have a simple insert function and a display values function, however whenever I attempt to display the value, I always receive what looks like a memory address(but I have no idea), but I would like to receive the value stored (in this particular example, the int 2). I'm not sure how to dereference that to a value, or if I'm just completely messing up. I know that vectors are a better alternative, however I need to use an array in this implementation - and honestly I would like to gain a more thorough understanding of the code and what's going on. Any help as to how to accomplish this task would be greatly appreciated.
Example Output (running the program in the same way every time):
003358C0
001A58C0
007158C0
Code:
#include <iostream>
using namespace std;
template <typename Comparable>
class Collection
{
public: Collection() {
currentSize = 0;
count = 0;
}
Comparable * values;
int currentSize; // internal counter for the number of elements stored
void insert(Comparable value) {
currentSize++;
// temparray below is used as a way to increase the size of the
// values array each time the insert function is called
Comparable * temparray = new Comparable[currentSize];
memcpy(temparray,values,sizeof values);
// Not sure if the commented section below is necessary,
// but either way it doesn't run the way I intended
temparray[currentSize/* * (sizeof Comparable) */] = value;
values = temparray;
}
void displayValues() {
for (int i = 0; i < currentSize; i++) {
cout << values[i] << endl;
}
}
};
int main()
{
Collection<int> test;
int inserter = 2;
test.insert(inserter);
test.displayValues();
cin.get();
return 0;
}
Well, if you insist, you can write and debug your own limited version of std::vector.
First, don't memcpy from an uninitialized pointer. Set values to new Comparable[0] in the constructor.
Second, memcpy the right number of bytes: (currentSize-1)*sizeof(Comparable).
Third, don't memcpy at all. That assumes that Comparable types can all be copied byte-by-byte, which is a severe limitation in C++. Instead:
EDIT: changed uninitialized_copy to copy:
std::copy(values, values + currentSize - 1, temparray);
Fourth, delete the old array when it's no longer in use:
delete [] values;
Fifth, unless the code is going to make very few insertions, expand the array by more than one. std::vector typically increases its size by a factor of 1.5.
Sixth, don't increment currentSize until the size changes. That will change all those currentSize-1s into currentSize, which is much less annoying. <g>
Seventh, an array of size N has indices from 0 to N-1, so the top element of the new array is at currentSize - 1, not currentSize.
Eighth, did I mention, you really should use std::vector.
This line is wrong:
memcpy(temparray,values,sizeof values);
The first time this line is run, the values pointer is uninitialized, so it will cause undefined behavior. Additionally, using sizeof values is wrong since that will always give the size of a pointer.
Another issue:
temparray[currentSize] = value;
This will also cause undefined bahavior because you have only allocated currentSize items in temparray, so you can only access indices 0 to currentSize-1.
There is also an error in your array access.
temparray[currentSize/* * (sizeof Comparable) */] = value;
Remember that arrays start at index zero. So for an array of length 1, you would set temparray[0] = value. Since you increment currentSize at the top of the insert function, you will need to do this instead:
temparray[currentSize-1] = value;
I'm new to programming and I was wondering, how to get the size of an array, that is, get the size of how many elements are inside the array. For example if I declare an array of size 10, but only input 3 elements into the array, how would I determine the size of this array? If I don't know how many elements I placed in initially.
If you declare an array, e.g. int array[10], then its size is always 10 * sizeof(int). There is no way to know how many times you've accessed it; you'd need to keep track of that manually.
You should consider using container classes, e.g. std::vector:
std::vector<int> vec;
vec.push_back(5);
vec.push_back(10);
vec.push_back(42);
std::cout << vec.size() << "\n"; // Prints "3"
If you declare an old-style array of 10 elements, e.g. std::string words[10], the size of the array is always 10 strings. Even with the new style (std::array), it would be a fixed size.
You might be looking for a std::vector<>. This doesn't have a fixed size, but does have a .size() method. Therefore, if you add three elements to it, it will have .size()==3
to get the array size (in number of elements) assuming you do not know it in advance
use sizeof(a)/sizeof(a[0])
see the below example program. I used C but it should carry over to C++ just fine
#include <stdio.h>
int main(){
int a[10];
printf("%d elements\n",sizeof(a)/sizeof(a[0]));
return 0;
}
//output: 10 elements
There's several possible ways, but they depend on your definition.
If you know there is a value the user won't input (also known as a sentinel value), you can use a function like memset, to set the entire array to that unused value. You would then iterate through the list counting all the variables in the list that don't match that value.
The other way is to build your own array class, which counts whenever the array is modified (you'd have to overload the = and [] functions as appropriate).
You could also build a dynamically linked list, so as the user adds variables, the count can either be determined by walking the list or keeping count.
But, if you're taking the array as the basic array, with no idea as to it's actual starting state, and no idea what to expect from the user (given this is your program, this shouldn't occur), then generally speaking, no, there is known way to know this.
You maintain a counter variable count initialized to 0.
Whenever you are adding to array increment the count by 1.
Whenever you are removing from array decrement the count by 1.
anytime count will give you the size of the array.
Suggestion:
int[10] arr;
//init all to null
for (int i =0; i < 10; i++)
arr[i] = 0;
arr[0]=1;
arr[2]=5;
int sz = 0;
for (int j = 0; j < 10; j++)
if (arr[j] != 0) sz++;