What's wrong with increment operator in pointer array? - c

I just found a little confusion while using increment operator in pointer array.
Code 1:
int main(void) {
char *array[] = {"howdy", "mani"};
printf("%s", *(++array));
return 0;
}
While compiling, gcc throws a well known error "lvalue required as increment operand".
But, when I compile the below code it shows no error!!! Why?
Code2:
int main(int argc, char *argv[]) {
printf("%s",*(++argv));
return 0;
}
In both cases, I have been incrementing an array of pointer. So, it should be done by this way.
char *array[] = {"howdy","mani"};
char **pointer = array;
printf("%s",*(++pointer));
But, why code2 shows no error?

Arrays cannot be incremented.
In your first code sample you try to increment an array. In the second code sample you try to increment a pointer.
What's tripping you up is that when an array declarator appears in a function parameter list, it actually gets adjusted to be a pointer declarator. (This is different to array-pointer decay). In the second snippet, char *argv[] actually means char **argv.
See this thread for a similar discussion.

Related

Conflicting point between char array and char pointer with returning the adress

Purpose : My main purpose was to create a string in some kind of function , it should return an adress , by returning adress using the string in main.
But I learned char array and char pointer actually using for the same purpose.
If we suppose that's true , We have these declaration :
char *arr and char arr[10] , *(arr+9)=arr[10] isn't it?
Application 1 does not work.
Application 2 does work fine.
Application 1:
#include <stdio.h>
char *foo(char arr[]);
int main(void)
{
char example[10];
example=foo(example);
printf("%s\n",example);
return 0;
}
char *foo(char arr[])
{
arr[10]="attempt";
return arr;
}
Application 2:
#include <stdio.h>
char *foo(char*);
int main(void)
{
char *example;
example=foo(example);
printf("%s\n",example);
return 0;
}
char *foo(char* arr)
{
arr="attempt";
return arr;
}
Your code will invoke undefined behavior in both segments. ( Even though you have observed that Code 2 works, it only seems to work. In reality a failure is lurking, and can show without warning. )
Make these corrections to address that problem, and see comments for explanations:
In code 1:
//int main(void){
int main(void){//int main(void) is minimum prototype for main function.
//char example[10]; // this will invoke undefined behavior
char example[10] = {"something"}; // 'example' initialized with content,
// thus averting undefined behavior
//example=foo(example);
strcpy (example, foo(example)); // char array is not assignable using `=`
// use strcpy to transfer result of "foo"
printf("%s\n",example);
return 0;
}
char *foo(char arr[]) //note: char arr[] decays into char *arr
{
//char arr[10]="attempt"; // Error: redefinition of 'arr' with a
// different type: char[10] vs char *
arr = "attempt"; //because char [] decays into char *, 'arr' is usable as is.
return arr;
}
To answer your question in comments: Why using strcpy function [after variable example was initialized] is not a undefined behaviour.
First the definition of a C string is important to know. ( C string definition is found here. )
The variable example in its original form, i.e. initialized:
char example[10];
Can contain anything. For example:
|%|h|8|\#|d|o|-|~|*|U|?|?|?|?|
// ^end of memory for 'example`
// note that the character in example[9] == 'U', not NULL, therefore, not a C string.
This would cause the function strcpy() to fail. Initializing guarantees predictable results:
char example[10] = {"something"};//properly initialized
|s|o|m|e|t|h|i|n|g|0|?|?|?|?|
// ^end of memory for 'example`
//or
char example[10] = {0}; //also properly initialized
|0|0|0|0|0|0|0|0|0|0|?|?|?|?|
// ^end of memory for 'example`
(This would require an extra step to place proper content.):
strcpy(example, "something");
The only required adjustment to Code 2 is to initialize the pointer before using: (See the reason why pointer must be initialized here.)
char *foo(char*);
//int main(void){
int main(void){//int main(void) is minimum prototype for main function.
{
//char *example; // passing this will envoke undefined behavior
char *example = NULL;// must initialize before using
example=foo(example);
printf("%s\n",example);
return 0;
}
char *foo(char* arr)
{
arr="attempt";
return arr;
}
Both do not "work" for different reasons.
The first is undefined behavior (UB) as code attempts to assign an element outside the bounds of example[10].
arr[0]='\0'; or arr[9]='\0'; would have been OK given the value passed to foo().
Converting the address of the string literal "attempt" to a char is not good code either. A well enabled compiler will warn of this basic coding lapse. #f3rmat example
char *foo(char arr[]) {
arr[10]="attempt"; <-- UB
return arr;
}
char example[10];
example=foo(example);
The 2nd is UB because code attempted to use an uninitialized value in passing a pointer. This "works" in that the UB of passing an uninitialized pointer is often benign. Since foo() does not use this "garbage" value and the rest of good is well defined, it "works".
char *foo(char* arr) {
arr="attempt";
return arr;
}
char *example;
example=foo(example); // UB - likely a garbage value is passed to `foo()`.
printf("%s\n",example); // `example` is now pointing to `"attempt"`.
I learned char array and char pointer actually using the same purpose.
Pointers and arrays are related, yet different. Avoid the "actually using the same purpose" idea.
An array is like a row of houses on a street. A pointer is the address of a house written on a piece of paper in your hand. Houses ≠ scrap of paper. You can refer to the house by its address or even a row of houses by the first house's address, yet a house and its address are different.
I tried to compile Code '1' and got the following error:
prog.c: In function ‘main’:
prog.c:8:12: error: assignment to expression with array type
example=foo(example);
prog.c: In function ‘foo’:
prog.c:14:12: warning: assignment makes integer from pointer without a cast [-
Wint-conversion]
arr[10]="attempt\n";
^
You get error: assignment to expression with array type example=foo(example); because in your left hand side, you're using an array type, which is not assignable. Assignment operator (=) needs to have a modifiable lvalue as its left operand.
You get a warning: assignment makes integer from pointer without a cast [Wint-conversion] arr[10]="attempt\n"; because the left hand side and the right hand side in this assignment have different types.
Pointer and array are not the same.
char *arr = "attempt"
Here you're creating a string constant "attempt" and assigning its address to arr which is valid
char arr[10];
arr = "attempt";
This is invalid.
you can add elements to the array by following methods.
char arr[10] = "attempt";
char arr[10] = {'a', 't', 't', 'e', 'm', 'p', 't'};
arr[0] = 'a';
arr[1] = 't'; // and so on.
when you are passing the array as an argument to another function
arr = foo(arr);
you are passing the address of the zeroth element in the array arr[0]
Hope that helps..
Char arrays can be initialized but cannot be assigned.
char example[10]="attempt";
is valid.
But
char example[10];
example="attempt"
is not valid.
More details here
Your second example works because you pass a uninitialized pointer to a function and return an address of the string literal attempt
which will work perfectly as mentioned in the answer by chux

incrementing pointers to multi-dimensional array in C

I have this small program:
#include <stdio.h>
int main() {
char *argv[3] = {{"abc"}, {"def"}, {"ghi"}};
printf("%c\n", (*++argv)[1]); //error. I wanted to print 'b'
printf("%c\n", *++argv[1]); //prints e
return 0;
}
The error message:
error: cannot increment value of type 'char *[3]'
printf("%c\n", (*++argv)[1]);
I want to increment argv to point to b. I took this usage (*++argv)[i] straight from C Programming Language by K&R where they have an example on page 117 on incrementing argv exactly like I did. They also point out that (*++argv)[0] is the pointer to the first character in a string while *++argv[0] increments the pointer argv[0]. Indeed (*argv)[1] will print b while *argv[1] will print d. Yet somehow incrementing (*++argv)[0] just keep resulting in error.
First, this:
char *argv[3] = {{"abc"},{"def"},{"ghi"}};
Should be this, as noted by others:
char *argv[3] = {"abc", "def", "ghi"};
Second, what you've done is not what the K&R book does.
Array names act like they were constant pointers, so you can't change them like you tried to with that argv = argv + 1 (expanded version of ++argv).
But the book does that to an argv passed into main by the command line, so when char* argv[] enters main, it decays to a pointer to pointer (char**) and then, yes, you could make (*++argv)[1] work if you pass the strings as command line arguments.
Try to create a bogus argv inside main, like you did, and compare its related addresses with the addresses related to a real argv passed into main via command line.
You'll see that one is a char** and the other is a char* array:
#include <stdio.h>
int main(int argc, char* argv[])
{
printf("argv: %p\n", argv);
printf("&argv[0]: %p\n", &argv[0]);
printf("&argv: %p\n\n", &argv);
char* bogus_argv[] = {"abc", "def", "ghi"};
printf("bogus_argv: %p\n", bogus_argv);
printf("&bogus_argv[0]: %p\n", &bogus_argv[0]);
printf("&bogus_argv: %p\n\n", &bogus_argv);
printf("%c\n", (*++argv)[1]); // prints 'b'
printf("%c\n", *++argv[1]); // prints 'e'
return 0;
}
Run: ./program abc def ghi
Output on my machine:
argv: 0x7ffcde5aca98
&argv[0]: 0x7ffcde5aca98
&argv: 0x7ffcde5ac9a0
bogus_argv: 0x7ffcde5ac980
&bogus_argv[0]: 0x7ffcde5ac980
&bogus_argv: 0x7ffcde5ac980
b
e
The example from K&R refers to argv as defined as the second argument to function main. Your definition is different, you define an array of 3 pointers to strings whereas the function argument is a pointer to such an array.
The function prototype syntax is somewhat misleading as the same syntax is used for a different type of object. Some people prefer this syntax:
int main(int argc, char **argv) {
...
}
With this prototype, the nature of argv (a pointer to a pointer to char) appears more explicitly, but many programmers prefer the equivalent char *argv[] syntax to underline the fact that argv points to an array of pointers as opposed to a single pointer.
argv being an array in your code, you cannot increment it: this explains why you get an error for printf("%c\n", (*++argv)[1]);.
You can change your program this way:
#include <stdio.h>
int main(void) {
char *argument_array[4] = { "abc", "def", "ghi", NULL };
char **argv = argument_array;
printf("%c\n", (*++argv)[1]); // will print 'e' instead of 'b'
printf("%c\n", *++argv[1]); // prints 'h', not 'e'
return 0;
}
Also note that you should remove the redundant {} in the initializer, and the ++ operator is prefix, so the output is not exactly what you expect.
you made a mistake with array your declaration. It should you a warning. It should be
char *argv[3] = {"abc","def","ghi"};
The inner braces are not neccessary as strings are char pointers and therefore "arrays".
You could declare a second pointer variable and assign it to argv:
char ** p;
p = argv;
and then increment p.
Last but not least, if you want to print b first and then e, you have to put the "++" operator behind the variable. Otherwise it would increment the pointer before the evaluation and you would print e and h.

Stepping through an array of pointers to strings - "lvalue required as increment operand"

I'm confused about this program which I'm going to state here.
I wrote two simple programs to print a list of strings. First I made an array of pointers to the strings. And this is how I tried to do it
#include <stdio.h>
int main()
{
int i = 2;
char *a[] = {"Hello", "World"};
while (--i >= 0) {
printf("%s\n", *a++); // error is here.
}
return 0;
}
I need it to print
Hello
World
but there is compilation error and it says,
lvalue required as increment operand.
Then I changed the program to the following
#include <stdio.h>
void printout(char *a[], int n)
{
while (n-- > 0)
printf("%s\n", *a++);
}
int main()
{
int i = 2;
char *a[] = {"Hello", "World"};
printout(a,i);
return 0;
}
Then it worked as expected.
My question is, What's the difference happen when I pass the array name to a function? Why didn't it work the first time (I suspect that "array names cannot be modified" is the reason But WHY in the second program, it allowed me to increment)?
*a++
++ requires its operand to be a modifiable lvalue.
In the first example, a is an array. In the second example, when passed to a function as argument, the array decays to a pointer (to its first element), so the code compiles.

Difference between char *argv[] and char **argv for the second argument to main() [duplicate]

This question already has answers here:
C difference between *[] and **
(8 answers)
Closed 2 years ago.
CODE 1
#include<stdio.h>
int main(int argc, char *argv[])
{
int j;
printf("%d", argv[1][0]);
return 0;
}
CODE 2
#include<stdio.h>
int main(int argc, char **argv)
{
int j;
printf("%d", argv[1][0]);
return 0;
}
CODE 1 and CODE 2 both give same output. but argument 2 of main function in CODE 1 and CODE 2 are different. Array of pointers are created above data section at compile time. argv is array of pointers. Then we should declare argument in main function as pointer to pointer to character i.e., **argv. How it is correct to declare as in CODE 1?
It is fundamental to c that char** x and char* x[] are two ways of expressing the same thing. Both declare that the parameter receives a pointer to an array of pointers. Recall that you can always write:
char *parray[100];
char **x;
x = &parray[0];
and then use x identically.
Basically, char* argv[] means array of char pointers, whereas char** argv means pointer to a char pointer.
In any array, the name of the array is a pointer to first element of the array, that is, it contains the address of the first element.
So in the code given below, in char array x, x is a pointer to first element, '1', which is a character. So it's pointer to a character.
And in array arr, arr is pointer first element, x, which is itself a pointer to a character. So it a pointer to another pointer.
Hence, x is char*, and arr is char**.
While receiving something in a function, basic rule is that, you have to tell the type of the thing you are receiving. So either you simply say that you want to receive a char**, or you can also say char* arr[].
In first case, we don't need to think anything complex. We simply know, we are receiving an array of char*. Don't we know this? So, we receive it, and use it.
In second case, it is simple, as i have explained above that arr is a char**, you can put this as it's type and receive it safely. Now the system knows the type of the stuff we have received, we can access next elements by simply using array annotation. It's like, we have received the starting address of the array, we can surely go to the next elements, and as we know it's type, we know what it contains and how we can use that further. We know it contains pointer to char, so we can legally access them as well.
void func1(char* arr[])
{
//function body
}
void func2(char** arr)
{
//function body
}
int main()
{
//x, y and z are pointer to char
char x[3]={'1', '2', '3'};
char y[3]={'4', '5', '6'};
char z[3]={'7', '8', '9'};
//arr is pointer to char pointer
char* arr[3]={x, y, z};
func1(arr);
func2(arr);
}
They're exactly the same. §5.1.2.2.2 of the C11 standard states:
The function called at program startup is named main. The
implementation declares no prototype for this function. It shall be
defined with a return type of int and with no parameters:
int main(void) { /* ... */ }
or with two parameters (referred to here as argc and argv, though
any names may be used, as they are local to the function in which they
are declared):
int main(int argc, char *argv[]) { /* ... */ }
or equivalent;10) or in some other implementation-defined
manner.
10) Thus, int can be replaced by a typedef name defined as int, or
the type of argv can be written as char ** argv, and so on.
Clearly the intent is for both declarations to be identical. On top of that, the rule is described in §6.7.6.3/7:
A declaration of a parameter as ‘‘array of type’’ shall be adjusted
to ‘‘qualified pointer to
type’’, where the type qualifiers (if any) are those specified within the [ and ] of the array type derivation. ...
[EDIT] Using GCC at the time of the comment probably GCC 7.2
declaring an array like this
char array[]
makes it const which means that you CAN'T have the following code
char array[] = "hello";
array = "hey";
even though the second string is smaller and should fit you get this error
error: array type 'char [6]' is not assignable
if you have **argv you can write
main(int argc, char **argv)
{
char **other_array;
/*
* do stuff with other_array
*/
argv = other_array;
}
if you have *argv[] then
main(int argc, char *argv[])
{
char **other_array;
/*
* do stuff with other_array
*/
argv = other_array;
}
gives you this warning
warning: assigning to 'const char **' from 'char **' discards qualifiers in nested pointer types
so it is technically a small optimisation as if you had written const

defining a string value for structure variable

I was just going through certain interview questions. Got this structure related issue, I m not understanding what is happening wit the output, Please if some could explain the reason.
When is use a character pointer in the structure like
#include <stdio.h>
struct name {
char *array;
}variable;
int main( int argc, char * argv[] ){
variable.array="hello";
printf( "%s\n", variable.array );
}
The output is hello printed, but when change the structure variable to
struct name {
char array[10];
}variable;
The compiler throws an error "incompatible types in assignment" at
variable.array="hello";
I am really confused as to where i am missing the point. Why does it show the error like assignment problem?? Please correct me
Thank you
You can only initialize array like that at the time of declaration only,
else you need to use
strcpy(variable.array,"hello");
you can't even do like that with a simple char array
char a[10];
a="hello";
the complier will tell :
incompatible types when assigning to type ‘char[10]’ from type ‘char *’
because "hello" is a string literal that is being held by a pointer which can't be assigned like this to an array.
In C the term "hello" means "a pointer to a string that has the chars 'hello\0' in it".
So when you assign array="hello" in the first case you are assigning the pointer to the string into a pointer variable. Which is right.
In the second case you try to assign a pointer to an array which is wrong!
you can't assign value to an array.
It raises an error because an array of char and a pointer to char are different things.
An array is not a pointer. A pointer is not an array. Sometimes a pointer might point to an array. But even when a pointer points to an array, it's not an array.
Your compiler gives an address to variable.array at compile time. It also gives an address to the string literal "hello". They're not the same address. The string literal and the array (or "the buffer") are in different places; logically, the string has to be copied into the buffer.
#include <stdio.h>
#include <string.h>
struct name {
char array[10];
}variable;
int main( void ){
strcpy(variable.array, "hello");
printf( "%s\n", variable.array );
return 0;
}
You might find the C FAQ useful.
The first thing is array is a constant pointer to the first element in the
array,we can not change its address location once we declared..like
int a[3]; is equivalent to int *const a;
so we cant change the array address location
int a[3]={1,2,3};
a++;//its an error
int b[3];
b=a;//its also an error
but int *c;
c=a;//Not an error because c is a pointer to integer not constant pointer to integer
similar to
char str[10]="hello";
if i change like this
str="world";//its also an error
Pointers and arrays are always not equal, in some cases only like dereferencing
char a[10]="hello";
for(i=0;a[i]!='\0';i++)
printf("%c",a[i]);
for(i=0;a[i]!='\0';i++)
printf("%c",*(a+i));

Resources