why char array's size is same using sizeof() - c++

I meet a problem with the char array size. I pass an char array into the function and after run the function, I still want to use sizeof to check the size of the array, it won't give me the new size of the array, but the old size? I would like to know why? Thank you very much!
#include<iostream>
using namespace std;
void replacement(char* arr, int len){
int count=0;
for(int i=0; i<len; i++){
if(arr[i]==' '){
count++;
}
}
int newlen=count*2+len;
//arr[newlen]='\0';
int k=newlen-1;
for(int i=len-1; i>=0; i--){
if(arr[i]!=' '){
arr[k--]=arr[i];
}
else{
arr[k--]='0';
arr[k--]='2';
arr[k--]='%';
}
}
}
int main(){
char arr[]="ab c d e g ";
cout<<sizeof(arr)<<endl;
replacement(arr, sizeof(arr));
int i=0;
while(arr[i]!=NULL) cout<<arr[i];
}

You can't change an array's size. If you want to know the length of the string in the array, use strlen() -- this counts the number of characters before the null terminator.
Even better would be to use C++ std::string class.

Right, so you are trying to replace spaces with "%20", right?
Since C++ (or C) doesn't allow an existing array to be resized, you will either need to have enough space in the first place, or use an array allocated on the heap. Then allocate a new "replacement" string in the replacement function and return that.
The proper C++ method of doing this is of course to use std::string, in which case you could just pass it in as a reference, and do the replacement in the existing variable:
void replacement(std::string* str, int len){
std::string perc20 = "%20";
std::string space = " ";
while((pos = str.find(space, pos)) != std::string::npos)
{
str.replace(pos, space.length(), perc20);
pos += perc20.length();
}
}
Much easier...

You can use sizeof() to find the size of only static arrays when the size is known at compile time. Hence it will always return the size of the array as determined at compile time.

Your program technically has Undefined Behavior because your use of sizeof returns the size in bytes of your char array. But a char implicitly contains a null byte \0. That means the for loop is iterating 1 past the length of the array.
It's recommended that you use std::string along with its size member function instead.

Related

What's being compared to the last element of the array?

There's a behavior that I don't understand, the c variable is supposed to increase by one every time an element of the array isn't equal to the one next to it, but there's one increment that's done automatically which increases c by one. I think this is because the last element of the array is compared to something which isn't equal to it. Why is this happening? Or if I'm right what's the thing that the last element is compared to?
#include <iostream>
int main() {
int n, c = 0;
std::cin >> n;
std::string s[n];
for (int i = 0; i < n; i++) {
std::cin >> s[i];
}
for (int i = 0; i < n; i++) {
if (s[i] != s[i+1]) {
c++;
}
}
std::cout << c;
}
std::string s[n]; is creating what is known as a "Variable-Length Array", which is NOT part of standard C++, but is supported as an extension by some compilers. Don't rely on this. Use std::vector instead for a dynamic-length array whose length is not known until runtime.
But, more importantly, your 2nd loop has undefined behavior. The valid indexes for the s[] array's elements are 0..n-1, so on that loop's last iteration, s[i] accesses the last string in the array, and s[i+1] accesses out of bounds, so the value that s[i] is compared to is indeterminate (if the code doesn't just crash outright from accessing invalid memory).
s[s.length()] == ‘\0’
From here: https://www.cplusplus.com/reference/string/string/operator%5B%5D/
“If pos is equal to the string length, the function returns a reference to the null character that follows the last character in the string (which should not be modified).”

Not able to input strings using getline() .It is reading only one string

char* name[4];
int j=0;
while(cin.getline(name[j],80))//input given:you(ent)me(ent)he(ent)she
cout<<name[j++];
this code is reading only one string upto one newline.should'nt it read all 4 strings and print them ?and is this a good way to input string using getline?
Problem: You are not allocating the memory properly. You are declaring an array of pointers not an array of c style strings.
Possible Solutions: You need to read about pointers and memory allocation first. You can either allocate memory first to each of the four pointers that you declared name[0], name[1], name[2], and name[3] using the following code:
char* name[4];
for (int i = 0; i < 4; i++)
{
name[i] = new char[80];
}
OR you can use a 2D array for which the code is posted below:
char name[4][80];
int j=0;
while(j<4 && cin.getline(name[j],80))
{
cout<<name[j++];
}
I made a bit of correction. And it works on my computer.
char* name[4];
for (int i = 0; i < 4; i++)
name[i] = new char[80];
int j = 0;
while (j < 4)
{
cin.getline(name[j], 80); //input given:you(ent)me(ent)he(ent)she
cout << name[j++] << endl;
}
You need to read some more about pointers, arrays and memory management in C++ i guess. You try to operate on C array of strings, but you didn't initialize it properly. You need to allocate memory before you use such pointers. Currently your program results in UB so you are actually really lucky that it did anything same at all.
Another issue is that, when you reach the end of your input, when j=4, you will still attempt to perform cin(getline(name[j], 80) but you are passing the name[4] as a parameter, which may be a cause of another UB, even if you allocate the memory correctly beforehand.
Other then that you are writing in C++, so use C++ string and vector instead of C arrays.
This is easily done with strings and std::getline:
#include <iostream>
#include <vector>
using namespace std;
int main(){
vector<string> names;
string name;
while(getline(cin, name)){
names.push_back(name);
cout<<name<<endl;
}
return 0;
}

After passing by reference to modify an array, why it stays the same?

I am practicing pointers by creating a Big Number struct, which has numDigits (number of digits) and digits (contents of the big number).
I create a function called removeZero(). After passing the integer array and the size n into it, because of passing by reference, I am supposed to cut down the leading zeros for my input. It works, when the integer array is in main function. However, when I pass an array that is in readDigits, it does not return with a non-leading-zero version. Why? How to fix it?
struct BigNum{
int numDigits;
int *digits; //the content of the big num
};
int main(){
int A[] = {0,0,0,0,0,0,1,2,3};
int n=9;
int *B=A;
//removeZero(A,n); If I use this, it cannot compile
//error: invalid initialization of non-const reference of type ‘int*&’ from an rvalue of type ‘int*’
removeZero(B,n);
for (int i=0; i<n; i++){
std::cout << *(B+i) << std::endl;
}
BigNum *num = readDigits();
return 0;
}
BigNum* readDigits(){
std::string digits;
std::cout << "Input a big number:" << std::endl;
std::cin >> digits;
//resultPt in heap or in stack?
int *resultPt = new int[digits.length()]; //in heap
int n = digits.length();
toInt(digits,resultPt);
removeZero(resultPt,n);
//Output the leading zeros, why?
for (int i=0; i<n; i++){
std::cout << *(resultPt +i) << std::endl;
}
BigNum *numPtr = new BigNum();
numPtr->numDigits = n;
numPtr->digits = resultPt;
return numPtr;
}
void toInt(std::string& str, int *result){
for (int i=0;i<str.length() ;i++ ){
result[str.length()-i-1] = (int)(str[i]-'0');
}
}
void removeZero(int* &A,int& n){
int i=0;
while (A[i]==0){
i++;
}
A=A+i; //memory leak?
n=n-i;
}
bool areDigits(std::string num){
for(int i=0;i<num.length();i++){
if(num[i]<'0' || num[i] >'9'){
return false;
}
}
return true;
}
Note that an array and a pointer are two different things. When you pass an array to a function, it degrades to a const pointer. This means that you cannot pass an array to a function which expects a int*&.
It could be the problem of scope of numPtr.numPtr is local variable of function readDigits(). Instead of returning pointer. Pass num to readDigits().
The signature of your removeZero function is:
void removeZero(int* &A,int& n);
That means the forst parameter is a reference of a pointer but the pointer is a non-const one, and you cannot therefore pass an array there, as array is a constant pointer (starting address cannot be changed).
In fact you are changing the starting address within removeZero.
With removeZero, the while loop shopuld be changed from:
while (A[i]==0){
to:
while ((A[i]==0) && (i<n)){
You have a logic error in toInt.
void toInt(std::string& str, int *result){
for (int i=0;i<str.length() ;i++ ){
// This stores the digits in the reverse order.
result[str.length()-i-1] = (int)(str[i]-'0');
}
}
That line should be
result[i] = (int)(str[i]-'0');
If you intend to keep the digits in reverse order, then removeZero has to be changed keeping that in mind.
`
When you say
int *B=A;
you are just creating a pointer to point to the same memory
of the Array A. Just by incrementing the pointer(*B) within the function
removeZero
A=A+i;
you are not deleting anything but you are just incrementing the pointer(*B)
to point to subsequent memory location within the array.
The original array memory pointed to by A remains the same, since you
have not changed any contents of the array, but you have just
incremented a pointer pointing to the same memory location as that of the array.
Also there are so many problems, like "Debasish Jana" mentioned,
you have to change your while loop. ""Code-Apprentice" gave you the reason for your
compilation error when you uncomment your commented code.
Also within "removeZero" you are incrementing A by i instead of "1" like
A=A+1;
This is one of the reason for the strange behavior you experience
Even after changing all this, you cannot see your array getting changed,
since you are not modifying any of the contents of your array.
If you really want to delete the contents of the array and change it dynamically,
you have to go for Vector<>. With static memory allocation you cannot cut the
array size short by removing some elements here and there. Learn Vector<>!

using a string array in a function C++

this question should be easy and straight forward, but after searching online, I couldn't find an answer. might because the question is just too simple.
following code is from cplusplus.com. it's a function of making a string lowercase. I was intended to do something similar.
/* tolower example */
#include <stdio.h>
#include <ctype.h>
int main ()
{
int i=0;
char str[]="Test String.\n";
char c;
while (str[i])
{
c=str[i];
putchar (tolower(c));
i++;
}
return 0;
}
and what I made is this:
void search(string A[], string B[], int k)
{
int temp;
for(int j = 0; j <= 4; j++)
{
for(int i = 0; i <= k; i++)
{
string str (A[i]);
int h = 0;
char lstr[] = B[j];
char c;
while (lstr[h])
{
c = lstr[h];
putchar (tolower(c));
h++;
}
string key (B[j]);
.....
this part of the code is in a for loop. B[j] is a string array.
Visual Studio informed me that char lstr[] = B[j]; part is not right, the error message is:
Error: initialization with '{...}' expected for aggregate object.
I think the problem is that I didn't use the correct syntax of using a string array in a function. something should be done for B[j], in order to make it a char array. I couldn't figure it out.
is that something about pointer? sorry I haven't learn pointer yet.
does my question make sense for you? any help is greatly appreciated!!
If you're looking to make the letters in the string lowercase it's more readable to just work with strings all the way and use std::transform. For example,
// make sure to #include <algorithm>
// at the top
string lstr = B[j];
std::transform(lstr.begin(), lstr.end(), lstr.begin(), ::tolower);
This is much more natural and c++ idiomatic than working with char * directly and less error-prone.
You're trying to assign a char to char[]. You can get the effect you want with the following code:
....
int h = 0;
char* lstr = &B[j]; // point lstr to the address of j'th element of B.
char c;
while (lstr[h])
{
c = lstr[h];
putchar (tolower(c));
h++;
}
.....
What this does is that lstr is now a pointer that points to the j'th character in B. Arrays are essentially pointers. When you do B[j], it's equivalent to writing char ch = *(B + j);, where B points to the address of the first character in the array of characters (otherwise known as string).
EDIT
After your edit, it now seems that you're trying to assign a std::string to a char. Here is the corrected solution.
....
int h = 0;
string& lstr = B[j]; // grab a reference to the j'th string in B.
char c;
while (lstr[h])
{
c = lstr[h];
putchar (tolower(c));
h++;
}
.....
Here, lstr is essentially a reference to the j'th string in B and you can use it as a regular string just like how you're using string str(A[i]);, which makes a copy of the i'th string in A.
You're confusing character arrays and string objects here. A character array is an array of bytes of set size which is null terminated, while a string is an object which expands/contracts as is necessary and doesn't require the null terminator. You're attempting to assign a string object to a character array, which is unsupported. If you're working with string objects, and want to retrieve their equivalent character array, utilize the c_str() function:
const char* lstr = B[j].c_str()
Also, utilizing an array name of B and an index of j is hilarious.

Int Array Length C++

I have to use a dynamic length int array in my program, and want to be able to get the number of objects in it at various points in my code. I am not that familiar with C++, but here is what I have. Why is it not giving me the right length? Thanks.
<#include <iostream>
Using Namespace std;
int length(int*);
void main()
{
int temp[0];
temp[0] = 7;
temp [1] = 10;
temp[2] = '\0';
cout << length(temp) << endl;
}
int length(int* temp)
{
int i = 0;
int count = 0;
while (*temp + i != '\0')
{
count++;
i++;
}
return count;
}
currently it just goes into an endless loop ;_;
In C++ arrays are not dynamic. Your temp array has zero length, and attempting to write to members beyond its length is undefined behaviour. It's most likely not working as it will be writing over some part of the stack.
Either create a fixed size array with enough space to put everything you want to in it, or use a std::vector<int> which is a dynamic data structure.
#include <iostream>
#include <vector>
using namespace std;
int length(int*);
int main () // error: ‘::main’ must return ‘int’
{
int temp[3];
temp[0] = 7;
temp[1] = 10;
// don't use char constants for int values without reason
temp[2] = 0;
cout << length(temp) << endl;
vector<int> vec_temp;
vec_temp.push_back(7);
vec_temp.push_back(10);
cout << vec_temp.size() << endl;
}
int length(int* temp)
{
int i = 0;
int count = 0;
while (*(temp + i) != 0) // *temp + i == (*temp) + i
{
count++;
i++; // don't really need both i and count
}
return count;
}
For the vector, there's no need to specify the size at the start, and you can put a zero in, and finding the length is a simple operation rather than requiring a loop.
Another bug inside your loop was that you were looking at the first member of the array and adding i to that value, rather than incrementing the pointer by i. You don't really need both i and count, so could write that a couple of other ways, either incrementing temp directly:
int length(int* temp)
{
int count = 0;
while (*temp != 0)
{
++count;
++temp;
}
return count;
}
or using count to index temp:
int length(int* temp)
{
int count = 0;
while (temp[count] != 0)
++count;
return count;
}
This approach is a bad idea for a couple of reasons, but first here's some problems:
int temp[0];
This is an array of 0 items, which I don't even think is permitted for stack elements. When declaring an array like this you must specify the maximum number of values you will ever use: E.g. int temp[10];
This is super important! - if you do specify a number less (e.g. [10] and you use [11]) then you will cause a memory overwrite which at best crashes and at worst causes strange bugs that are a nightmare to track down.
The next problem is this line:
while (*temp + i != '\0')
That this line does is take the value stores in the address specified by 'temp' and add i. What you want is to get the value at nth element of the address specified by temp, like so:
while (*(temp + i) != '\0')
So that's what's wrong, but you should take five minutes to think about a better way to do this.
The reasons I mentioned it's a bad idea are:
You need to iterate over the entire array anytime you require its length
You can never store the terminating element (in this case 0) in the array
Instead I would suggest you maintain a separate value that stores the number of elements in the array. A very common way of doing this is to create a class that wraps this concept (a block of elements and the current size).
The C++ standard library comes with a template class named "vector" which can be used for this purpose. It's not quite the same as an array (you must add items first before indexing) but it's very similar. It also provides support for copying/resizing which is handy too.
Here's your program written to use std::vector. Instead of the 'length' function I've added something to print out the values:
#include <vector>
#include <iostream>
void print(std::vector<int> const& vec)
{
using namespace std;
for (size_t i = 0; i < vec.size(); i++)
{
cout << vec[i] << " ";
}
cout << endl;
}
int main()
{
std::vector<int> temp;
temp.push_back(7);
temp.push_back(10);
print(temp);
return 0;
}
You could try:
while (*(temp + i) != '\0')
Your current solution is calculating temp[0] + i (equals 7+i), which apparently is not what you want.
Not only C++ arrays are not dynamic as Pete points out, but only strings (char *) terminate with '\0'. (This is not to say that you can't use a similar convention for other types, but it's rather unusual, and for good reasons: in particular, relying on a terminator symbol requires you to loop through an array to find its size!)
In cases like yours it's better to use the standard library.
#include <vector>
#include <iostream>
int main()
{
std::vector<int> v;
v.push_back(7);
v.push_back(10);
std::cout << v.size() << std::endl;
return 0;
}
If you don't want to use std::vector, try this:
#include <iostream>
using namespace std;
int main () {
int vet[] = {1,2,3,4,5,6};
cout << (sizeof (vet) / sizeof *(vet)) << endl;
return 0;
}
The most common way to get the size of a fixed-length array is something like this:
int temp[256];
int len = sizeof (temp) / sizeof (temp[0]);
// len == 256 * 4 / 4 == 256 on many platforms.
This doesn't work for dynamic arrays because they're actually pointers.
int* temp = new int[256];
int len = sizeof (temp) / sizeof (temp[0]);
// len == 4 / 4 == 1 on many platforms.
For a dynamic-length array if you care about the size, you're best off storing it somewhere when you allocate the array.
The problem with your loop, as pointed out by many is that you have an operator precedence problem here:
*temp + i
should be:
*(temp + i)
But the bigger problem, also pointed out above, is that you don't appear to understand pointers versus fixed-length arrays and are writing off the end of your array.
If you want to use array properly, you have to allocate enough memory for storing values. Once you specified its length, you can't change it. To know array size, you should store it in variable e.g.:
int n;
cin>>n;
int array = new int[n];
int array_length=n;
If you want to change array's length, best way is to use std container, for example std::vector.
Here is the answer to your question
int myarr [] = {1, 2, 3, 4, 5};
int length = sizeof(myarr) / sizeof(myarr[0]);
cout << length;
Because you only allocate space for an array of zero elements.
The following lines
temp [1] = 10;
temp[2] = '\0';
do not allocate more memory or resize the array. You are simply writing data outside the array, corrupting some other part of the application state. Don't do that. ;)
If you want a resizable array, you can use std::vector (and use the push_back member function to insert new values)
A vector also has the size() member function which tells you the current size.
If you want to use the primitive array, you have to track the size yourself. (and, when resizing the array is necessary, copy all elements from the old array to the new, larger one)
To get dynamic behavior in arrays, use a std::vector, or fall back on the old school c style using int * with manual memory allocation (new and delete)[*]
[*] C implementations (discussed in the context of character arrays as C dynamic string length) used malloc, realloc, and free, but these should be avoided in c++ code.
Try this out:
int length(int* temp)
{
int count = 0;
while (*temp != 0 && *temp != -858993460)
{
++count;
++temp;
}
return count;
}