Inconsistent lvalue required error when incrementing array variable - c++

I am getting "lvalue required as increment operand" while doing *++a. Where I am going wrong? I thought it will be equivalent to *(a+1). This behaviour is weird as *++argv is working fine. Please help.
#include <stdio.h>
int main(int argc, char *argv[])
{
printf("Arg is: = %s\n", *++argv);
int a1[] = {1,2,3,4,5,6};
int a2[] = {7,8,9,10,11,12};
int *a[2];
a[0] = a1;
a[1] = a2;
printf("ptr = %d\n", *++a);
return 0;
}

a is a constant(array name) you can't change its value by doing ++a, that is equal to a = a + 1.
You might wanted to do *a = *a + 1 (increment 0 indexed value), for this try *a++ instead. notice I have changed ++ from prefix to postfix.
Note: char* argv[] is defined as function parameter and argv is pointer variable of char** type ( char*[]).
Whereas in your code int* a[] is not a function parameter. Here a is an array of int type (int*)(array names are constant). Remember declaration in function parameter and normal declarations are different.
Further, by using ++ with argv and a you just found one difference, one more interesting difference you can observe if you use sizeof operator to print there size. for example check this working code Codepade
int main(int argc, char* argv[]){
int* a[2];
printf(" a: %u, argv: %u", sizeof(a), sizeof(argv));
return 1;
}
Output is:
a: 8, argv: 4
Address size in system is four bytes. output 8 is size of array a consists of two elements of type int addresses (because a is array), whereas 4 is size of argv (because argv is pointer).

++a and a + 1 are not equivalent. ++a is the same as a = a + 1, i.e it attempts to modify a and requires a to be a modifiable lvalue. Arrays are not modifiable lvalues, which is why you cannot do ++a with an array.
argv declaration in main parameter list is not an array, which is why you can do ++argv. When you use a[] declaration in function parameter list, this is just syntactic sugar for pointer declaration. I.e.
int main(int argc, char *argv[])
is equivalent to
int main(int argc, char **argv)
But when you declare an array as a local variable (as in your question), it is indeed a true array, not a pointer. It cannot be "incremented".

Arrays are not pointers. a is an array; you cannot increment an array.

Related

What is ++argv? & confusing compiler error

This code was provided by my c++ instructor on a sample midterm. We covered argc and argv on a very basic level, so I understand what those expressions alone mean. However, any additions to those like the dereference operator and '++' confuse me and what I've googled hasn't been clear enough for me to apply it to this specific example. Also, when I try to compile, it provides this error:
In function 'int summer(int*, char**)':
Line 9: error: cannot convert 'char**' to 'const char*' for argument '1' to 'int atoi(const char*)'
compilation terminated due to -Wfatal-errors.
We haven't officially covered pointers, but I think I understand them well enough. char** means you're dereferencing twice, so the value of the pointer char, which is a pointer to something else, so the second * means we want the value of that. Is it constant because we are relying on something input in the command line and that can't be changed? I don't understand this.
#include <iostream>
using namespace std;
int summer(int *acc, char * ptr[])
{
register int n;
n = atoi(ptr);
*acc = *acc + n;
}
main(int argc, char * argv [])
{
int sum = 0;
while (--argc)
summer(&sum, *++argv);
cout << "sum is " << sum << endl;
}
Another question: When passing *++argv to summer(), does that mean the value of (argv[] + 1)? What would that even be? Adding the value one to the entire vector? I know that atoi(array) means changing the string into a numerical value, and then we are storing that in register int 'n', and then adding that to the sum which is directly changed in main. And that's about the only part of this code I really understand. Sorry if my questions/this post is kind of a mess.
To sum up what my questions are:
What does the compiling error message mean?
What does ++argv do?
Thank you.
Edited:
Okay, I've made the changes you guys have suggested (thank you!!):
#include <iostream>
using namespace std;
int summer(int *acc, char * ptr)
{
register int n;
n = atoi(ptr);
*acc = *acc + n;
return 0;
}
int main(int argc, char * argv[])
{
int sum = 0;
while (--argc)
summer(&sum, *++argv);
cout << "sum is " << sum << endl;
return 0;
}
I also added the returns because the compiler gave a new error due to no return value for the function type. On Codepad it compiles and prints "the sum is zero," however, it still does not compile on Dev C++ 5.7.1 which is what I am using. It doesn't display error messages (the ones I have been reading are from Codepad online compiler), or at least I can't find where to turn them on. It just highlights the lines it seems to have a problem with, and that is still the line with atoi(ptr).
*argv is equivalent to argv[0], so ++argv; would make *argv equivalent to what was originally argv[1]. So *++argv evaluates to the same thing as argv[1] (the first command line argument, after the name of the program itself), except it increments argv whereas argv[1] obviously does not.
For your error, you should change:
int summer(int *acc, char * ptr[])
{
to:
int summer(int *acc, char * ptr)
{
When you dereference a char **, which is the type of argv, you get a char *. char * is what atoi() is expecting.
Your program is essentially equivalent to this:
#include <iostream>
#include <cstdlib>
using namespace std;
void summer(int * acc, char * ptr)
{
*acc += atoi(ptr);
}
int main(int argc, char * argv [])
{
int sum = 0;
for ( int i = 1; i < argc; ++i ) {
summer(&sum, argv[i]);
}
cout << "sum is " << sum << endl;
}
except that your's doesn't check for troublesome values of argc.
The ++ is called the increment operator. It usually adds 1 to something.
The argv decays to a pointer that points to a container of arguments to your program.
The expression ++argv points to next parameter, if there is one.
Incrementing a pointer means to make it point to the next item in the list.
argv has type char ** (don't be distracted by the square brackets), meaning it points to a char * which is in a list of adjacent char *s. The argc parameter lets us know where to find the end of said list.
So, doing ++argv means that argv will now point to the next char * in the list. Applying * to that (and passing the result to a function) means that we send the value of the next char * in the list to that function.
The result of all this is that the function is called once for each argument, excluding the first one (since we ++'d before dereferencing the first time).
NB. This code actually has a bug; if argc == 0 it will go off into la-la land. It should check for this case before entering the loop.
Is it constant because we are relying on something input in the command line and that can't be changed?
No, the const char * bit refers to the type of argument that atoi() accepts. It is a pointer to a constant char. Note that char * is implicitly convertible to const char *, but not the opposite.
All this means is that atoi() accepts a pointer to a character, and it promises that it will not modify the target of the pointer.
My guess is that the ptr argument should have been char * ptr instead of char * ptr[]. If you change that, the code should compile.

Confusion about argc argv and env

I just don't know how to explain my question precisely. So I wrote that title above.
Here is my confusion about a very simple program. Exactly, the results.
#include <iostream>
using namespace std;
char * tmp[]={"aaa", "bbb", "ccc"};//there are 3 members
int main(int argc, char* argv[], char* env[])
{
cout << sizeof(env)/sizeof(char*) << endl;
cout << sizeof(tmp)/sizeof(char*) << endl;
}
Results:1 3
What I want is the length of env[]. How can this possible that I got number 1 of env[], while the length of 'tmp'(3) is absolutely rigth.
There's no way that the length of env is 1, cause I tested it and the number is 47.
Why this happened?
Thanks!
The difference is that tmp is an array, whereas env is a pointer. Arrays and pointers are different. It's a bit confusing because array syntax in a function formal parameter list is actually a pointer in disguise.
There is no way to get the number of elements pointed to by env using sizeof. You have to go through them until you find the NULL element terminating the list.
The important thing to remember is that argv and env are pointers, not arrays. In the context of a function parameter declaration, T a[] and T a[N] are interpreted as T *a, so the types of both argv and env are char **, not char *[N].
The only way to determine how many elements each points to is by iterating through them until you find a NULL pointer:
size_t i;
for ( i = 0; argv[i] != NULL; i++ )
; // empty loop body
printf( "There are %zu elements in argv\n", i );
for ( i = 0; env[i] != NULL; i++ )
; // empty loop body
printf( "There are %zu elements in env\n", i );
The language C has certain syntactical features that are convenient for the experienced programmer, but confusing for the new learner. While the syntax T * X[] looks the same in your two cases, they actually mean two very different things:
int a[] = { 1, 2, 3}; is the same as int a[3] = { 1, 2, 3 };. Here a is an array, and the size of the array is deduced from the initializer.
void f(int b[]) is the same as void f(int * b). Here b is a pointer, and the notation is merely suggestive of the fact that you should call f with a pointer to an element of an array. For instance, you could call f(a), or equivalently f(&a[0]), or even f(a + 2). But the declarator syntax is purely a cosmetic convenience, and b is not an array, but a pointer.
This has little to do with these being parameters to main, sizeof anything is a compile time expression. Obviously, the environment and arguments passed to your program aren't. sizeof(array)/sizeof(element_type) is only the length of the array if that array was declared with a static size. Otherwise, sizeof(array) will be equivalent to sizeof(element*) (and because sizeof(char**) == sizeof(char*) you get 1 in your program).

c++ pointers:-why is this code not running

int main(int argc, char** argv) {
char a[2][5]={"hell","worl"};
char **p;
p=a; // error here
cout<<*(*(a+1)+1);
cout<<endl;
cout<<(*a)[2];
return 0;
}
error:
C:\Dev-Cpp\main.cpp [Error] initializer-string for array of chars is too long [-fpermissive]
Why would you expect it to work? You declare p as char**,
and you try to assign a char[2][5] to it. The char[2][5]
will convert implicitly to a char (*)[5], but afterwards, you
have a pointer, and no further implicit conversions. (EDIT: except to void*.)
If you think about it, it should be obvious. If you dereference
a char**, you get a char*. And this char* must reside
somewhere in memory, since you have a pointer to it. So where
is it?
If you want to iterate over the outer array in your example:
char (*p)[5] = a;
std::cout << *p[0] << sdt::endl;
std::cout << *p[1] << sdt::endl;
Note that your expression *(*(a+1)+1) also supposes that you
have an array of pointers somewhere.
Or you can use the usual solution when working with C style
strings:
char const* const a[] = { "hell", "worl" };
and
char const* const* p = a;
In this case, you do have an array of pointers, which does
implicitly convert to a pointer to a pointer (the first element
of the array).
(Of course, the only time you'll really want to use C style
strings is with const variables with static lifetimes. In
most other cases, std::string is preferable.)
Other way to access the a[2][5] is,
char **p=(char**)a;
to get a[0]
printf("\n a[0] is [%s]", ((char*)p));
to get a[1]
printf("\n a[1] is [%s]", (((char*)p) + strlen(a[0])+1));
hope this helps.

Incompatible types in assignment char ** to char *

I have the following bit of code:
As a global variable:
char *orderFiles[10];
And then my main method:
int main(int argc, char *argv[])
{
orderFiles = argv;
}
However it keeps giving me an error. What am I doing wrong?
It's giving you an error because char *x[10] gives you an array of ten char pointers which is non-modifiable. In other words, you cannot assign to x, nor change it in any way. The equivalent changeable version would be char **orderFiles - you can assign argv to that just fine.
As an aside, you could transfer individual arguments to your array thus:
for (i = 0; i <= argc && i < sizeof(orderFiles)/(sizeof(*orderFiles); i++)
orderFiles[i] = argv[i];
but that seems rather convoluted. It will either fill up orderFiles with the first N arguments or partially fill it, making the next one NULL.
If your intent is simply to stash away the arguments into a global so that you can reference them anywhere, you should do something like:
#include <stdio.h>
char **orderFiles;
int orderCount;
static void someFn (void) {
int i;
printf ("Count = %d\n", orderCount);
for (i = 0; i < orderCount; i++)
printf ("%3d: [%s]\n", i, orderFiles[i]);
// or, without orderCount:
// for (i = 0; orderFiles[i] != NULL; i++)
// printf ("%3d: [%s]\n", i, orderFiles[i]);
// printf ("Count was %d\n", i);
}
int main (int argc, char **argv) {
orderCount = argc;
orderFiles = argv;
someFn();
return 0;
}
That code saves the arguments into globals so they can be accessed in a different function.
You should save both arguments to main if you want to use argc as well although, technically, it's not necessary since argv[argc] is guaranteed to be NULL for hosted environments - you could use that to detect the end of the argument array.
orderFiles is a const char **, you can't modify it (the array pointer itself).
You could try assigning the array members (i.e. orderFiles[0] = argv[0] and so on).
The problem is that there is a difference between arrays initialized without a length, and those initialized with one. Remove the 10 from the global variables declaration, and then it should work
The reason for this is that argv is really just a char**, but orderFiles is an array of 10 char*.
There is an implicit char** for orderFiles yes, but it's constant because you initialized it to a link time allocated block of memory by specifying the size [10]. You should create a non-constant char** or maybe memcpy from argv to your array.
Like they all said two different data types. In other terms think of it this way: argv is an array of c-strings, and your orderFiles is declared as a single c-string.
So how to assign orderFiles depends on what you're trying to do. I typically iterate through argv to get the arguments passed to the application. Note that argv[0] is the application name.

Why can't char** be the return type of the following function in C++?

I have the following function in C++ :
char** f()
{
char (*v)[10] = new char[5][10];
return v;
}
Visual studio 2008 says the following:
error C2440: 'return' : cannot convert from 'char (*)[10]' to 'char **'
What exactly should the return type to be, in order for this function to work?
char** is not the same type as char (*)[10]. Both of these are incompatible types and so char (*)[10] cannot be implicitly converted to char**. Hence the compilation error.
The return type of the function looks very ugly. You have to write it as:
char (*f())[10]
{
char (*v)[10] = new char[5][10];
return v;
}
Now it compiles.
Or you can use typedef as:
typedef char carr[10];
carr* f()
{
char (*v)[10] = new char[5][10];
return v;
}
Ideone.
Basically, char (*v)[10] defines a pointer to a char array of size 10. It's the same as the following:
typedef char carr[10]; //carr is a char array of size 10
carr *v; //v is a pointer to array of size 10
So your code becomes equivalent to this:
carr* f()
{
carr *v = new carr[5];
return v;
}
cdecl.org helps here:
char v[10] reads as declare v as array 10 of char
char (*v)[10] reads as declare v as pointer to array 10 of char
A pointer to pointers is not the same as a pointer to arrays.
(In particular, notice how sizeof(*ptr1) is sizeof(char)*6, whereas sizeof(*ptr3) is sizeof(char*) — this has serious ramifications for pointer arithmetic.)
new char[5][10] gives you a char (*)[10] (which has absolutely nothing to do with function pointers, by the way), because the pointers and chars are laid out in that fashion in memory (my second example).
This is not the same as char** (which represents a different layout), so a conversion between the two makes no sense; hence, it is disallowed.
So your function's return type must be char (*)[10]:
char (*f())[10] {
char (*v)[10] = new char[5][10];
return v;
}
Of course, this is really ugly, so you're far better off with a std::vector<std::string>.
This FAQ entry explains it best, under the title "Conversions".
Because char** and char (*)[10] are two different types. char** is a pointer to pointer(to char), while char (*)[10] is a pointer to an array(of size 10) of char. Resultantly, the moving step of char** is sizeof(void *) bytes which is 4 bytes on win32 platform, and the moving step of char (*)[10] is sizeof(char) * 10 bytes.
Example
char *c = NULL;
char **v = &c;
cout << typeid(v).name() << endl;
cout << (void*)v << endl;
v += 1;
cout << (void*)v << endl;
char d[10];
char (*u)[10] = &d;
cout << typeid(u).name() << endl;
cout << (void*)u << endl;
u += 1;
cout << (void*)u << endl;
Output
char * *
0034FB1C
0034FB20
char (*)[10]
001AFC50
001AFC5A
To use char (*)[10] as a function's return type(or as input/output parameter of the function), the easiest and most readable way is to use a typedef:
// read from inside-out: PTRTARR is a pointer, and, it points to an array, of chars.
typedef char (*PTRTARR)[10];
Note that it can easily be mixed up with typedef of an array of pointers, if not careful:
// operator[] has higher precedence than operator*,
// PTRARR is an array of pointers to char.
typedef char *PTRARR[10];
Reference
Arrays and Pointers