32

gcc 4.4.4

What am I doing wrong?

char x[10];
char y[] = "Hello";
while(y != NULL)
    *x++ = *y++;

Many thanks for any advice.

MD XF
  • 7,484
  • 7
  • 37
  • 66
ant2009
  • 29,065
  • 146
  • 383
  • 576

10 Answers10

37

x++ is the short form of x = x + 1. However, x here is an array and you cannot modify the address of an array. So is the case with your variable y too.

Instead of trying to increment arrays, you can declare an integer i and increment that, then access the i'th index of an arrays.

char x[10], y[5] = "Hello";
int i = 0;
while (y[i] != 0)
{
    x[i] = *y[i];
    i++;
}
x[i] = 0;
MD XF
  • 7,484
  • 7
  • 37
  • 66
naivnomore
  • 1,241
  • 7
  • 13
  • 5
    Why would you mix the `*(x+i)` and `x[i]` forms in the same code? – caf Jul 30 '10 at 08:33
  • @caf To demonstrate the relationship between the two. – John Roberts Dec 25 '12 at 17:19
  • why are you allowed to do argv++ then? what is special about argv? – David Feb 07 '14 at 02:21
  • @David I'm a beginner at C myself, so I could be wrong, but isn't `argv` declared as `char *argv[]` (as opposed to `char buf[]` in these examples)? Thus, that wouldn't modify the base address of the array itself, only a pointer relative to that array. Or? – user966939 Nov 24 '15 at 06:07
  • @David `argv` isn't special; it's an argument. Arguments (well, arguments that aren't `const`, anyhow) are fully mutable because they are **copies** of the original variables. That's why a function that modifies `int x` has to be defined like this `void modifyX(int *x){ ... }` and invoked like this `modifyX(&x)`. Consequentially, that led me here because I'm so used to passing a `char[]` into a function and modifying it directly that I was confused when I got this compile error after defining a `char[]` in the same function that modified the base address. TIL – Braden Best Jul 13 '16 at 03:43
  • @user966939 no, it's because argv is an argument, which is copied into the local scope separately from the original variable. I'd say that the fact that [this](http://pastebin.com/EJjVBgwT) works is sufficient proof of that. – Braden Best Jul 13 '16 at 04:05
  • Should not be while(y[i] != '\0') ? – Alex May 13 '17 at 09:39
31

Most likely you fell victim to a popular misconception that "array is a pointer", i.e. when you define an array what you actually get is an ordinary pointer that points to some block of memory allocated somewhere. In your code you are making an attempt to increment that pointer.

The code does not "work" because in reality arrays are not pointers. Arrays are arrays. Arrays cannot be incremented. There's no such operation as "increment an array" in C language. In fact, arrays by themselves in C are non-modifiable lvalues. There are no operations in C that can modify the array itself (only individual elements can be modifiable).

If you want to traverse your arrays using the "sliding pointer" technique (which is what you are actually trying to do), you need to create the pointers explicitly and make them point to the starting elements of your arrays

char *px = x;
char *py = y;

After that you can increment these pointers as much as you want.

AnT
  • 302,239
  • 39
  • 506
  • 752
  • 6
    In "reality", arrays **are** pointers. It's true that stack-allocated arrays like `char myString[]` are immutable in the sense that you can't modify the pointer's address. But that doesn't change the fact that they're still pointers, to the beginning of a chunk of memory located in the stack. So when you say "Arrays aren't pointers", you are directly contradicting fundamental implementation details that are necessary for understanding C. – Braden Best Jul 13 '16 at 05:08
  • 1
    @Braden Best: Wrong. Arrays are NOT pointers. And this is indeed one fundamental detail, understanding of which is required for understanding C. This matter has been explained to death already (http://c-faq.com/aryptr/index.html) and it is highly unusual to see anyone still struggling with the concept today, in 2016. Dennis Ritchie's decision to abandon pointers for implementing arrays was one of the critical steps in the evolution of the language. And you still keep reiterating this "arrays are pointers" nonsense today? – AnT Jul 13 '16 at 06:09
  • 4
    okay, then what does `printf("%p", myString)` print? Oh, right, a memory address. Cause p is for pointer. Because they are implemented as pointers, because no type error is raised when you send an array into a function that expects a pointer. Even in a C++ compiler with `-Wall -pedantic`. Why would anyone believe it's a pointer? Maybe because it is. Maybe because `*myString` dereferences the address and returns the value that the pointer points to. Pointers are rectangles and arrays are squares. All arrays are pointers, but not all pointers are arrays. They are NOT mutually exclusive. – Braden Best Jul 13 '16 at 06:49
  • 4
    `array[n]` is syntax sugar for `*(pointer + n)`. You might find it surprising, in your delusional everything is high level, machine code doesn't exist fantasy world, that `n[array]` will return the exact same thing and produce not a single error or warning from a C nor C++ compiler running with `-Wall -pedantic`. ALL of the observable evidence seen in practice points to arrays being syntax sugar for pointers. The single contradiction, that an array's address can't be modified within the same scope it was defined in, doesn't mean anything when it can just be passed into another function anyway. – Braden Best Jul 13 '16 at 06:59
  • 1
    @Braden Best: No. Your `printf` correctly prints memory address simply because in C language array `myString` in this context is immediately subjected to so called **array-to-pointer conversion** (aka "array type decay"). The temporary result of that conversion - indeed a pointer - is sent to `printf` instead of the array. The same applies to all of your little experiments, all of which have been beaten to death already, as I said before. The FAQ link I gave you explains all of this. – AnT Jul 13 '16 at 15:42
  • The only contexts in C that do not trigger the array-to-pointer conversion are: 1) `sizeof`, 2) unary `&`, 3) intialization of `char[]` with string literal (in C++ there are more). In other words, you made a bunch of [non-representative] experiments and then jumped to a naive and preposterous conclusion: "arrays are pointers". Arrays are NOT pointers. Arrays only convert (decay) to pointers implicitly in most contexts cases in C. But not in all contexts. – AnT Jul 13 '16 at 15:44
  • I'm talking about low level implementation details, as in, how C is actually implemented at the machine level, and not the abstractions that the compiler uses to evaluate code correctness. At the lowest level, everything is an integer. An array is an integer stored in RAM, which when examined, reveals the location in RAM for another integer, stored elsewhere. Pointers also fit this bill, because they are an integer that reveals the location of another integer somewhere else. It is important to understand this so one can intuitively understand arrays and pointers. – Braden Best Jul 13 '16 at 21:44
  • Also, you should work on your use of articles, punctuation and sentence flow. Because your English is hard to read. `"Your printf correctly prints memory address simply because in C language array myString in this context is immediately subjected to so called array-to-pointer conversion (aka "array type decay")"` – Braden Best Jul 13 '16 at 21:44
  • `"The only reason your printf example works is because, in this context, arrays are subjected to array-to-pointer conversion, a.k.a. array type decay."` – Braden Best Jul 13 '16 at 21:54
  • 1
    @Braden Best: Low-level implementatin details is exactly what I'm talking about. Indeed, at the lowest level everything is an integer. And NO, array is not stored as an "integer which reveals the location in RAM for another integer, stored elsewhere". By making this claim you are, agian, trying to force your imaginary "pointers" into the picture. An array is stored in memory immediately, as a continous block of integers. There's no need for a intermediate integer to "point" to that memory block. – AnT Jul 13 '16 at 22:17
  • When you declare `char a[100]`, what you get is a continous memory block of 100 bytes (`char`s) directly associated with name `a`. When you access `a`, you immediately and directly access that block of 100 bytes. There's NO intermediate integer that contains the location of that 100 byte block, as you seem to incorrectly believe. – AnT Jul 13 '16 at 22:18
  • 1
    It is important to understand that, in order to "get" the simple fact that in C language arrays and pointers are two completely different entities (which just happen to behave similarly at superficial language level in some contexts). In reality arrays are NOT pointers and array are NOT implemented under the hood as "pointers in disguise". – AnT Jul 13 '16 at 22:25
  • 1
    There are (used to be) quite a few people in C circles who suffer from this popular "arrays are pointers" misconception, until they finally start using unary `&` or `sizeof` with arrays or start working with mutidimensional arrays. This is when this misconception comes crashing down on them and they finally get around to learning what arrays really are in C. – AnT Jul 13 '16 at 22:28
  • "There is NO intermediate integer" Uh huh, and how, then, does the CPU magically store an array, without a physical location in RAM to store it in? It has to store it somewhere, and that somewhere is, in fact, an integer. The x'th byte from the starting point in RAM is where the array starts. x is the address, and the "intermediate integer". For it to have "no intermediate integer" is physically impossible because then there'd be no way the CPU could store it. The L1 cache and the CPU's on-board registers are incapable of holding a 1000-length char array. It has to go on the stack or the heap. – Braden Best Jul 13 '16 at 23:32
  • @Braden Best: Wow wow wow! Let's stop for a second here. First, you need to decide what exactly you are talking about whwn you are saying that "arrays are pointers". It is true that every object in memeory has an address and will be referred to by an integer (address) emebedded into the machine instruction. But that is true for all objects stored in memory. Every time you declare an `int a;` variable or `double x;` variable or `struct S { int x, y; } s;` variable, these variables will be referred to by integer addresses in the generated machine code. – AnT Jul 13 '16 at 23:41
  • 1
    So, are you trying to claim that `int a;` is also a pointer? Are you trying to claim that every `struct` object is a pointer? Basically, this logic would lead us to conclude that every object and every function in C is "really a pointer". Sorry, while this might hold water in assembly language terminolgy, this has nothing to do with C whatsoever. In C language obejcts in memory are called **lvalues**. **Lvalue** is the proper C term for what you are talking about. "Lvalue" and "pointer" in C are two completely different concepts. Don't mix them. And arrays are not pointers in C. – AnT Jul 13 '16 at 23:45
  • Meanwhile, you started with something completely different. You started with a `printf` example and `*(a + i)` example, claiming that these examples demonstrate that "arrays are pointers". This has nothing to do with how object addersses are represented in machine commands. You stared with a claim that arrays in C are "bipartite" objects: a data pointer pointing to another data block in memory. This claim is simply not true. Arrays are not different from struct in this regard: they are just continuous blocks of memory. Structs are not pointers in C. Neither are arrays, in exactly the same way. – AnT Jul 13 '16 at 23:48
  • So, again, you need to decide first what you are talking about. You are mixing (and flip-flopping between) two completely different concepts/topics. – AnT Jul 13 '16 at 23:51
  • Hi ANT, this conversation is great.! i came here because my professor told something which i didn't believe in , So i executed the code and it didn't work .! he was doing a++ on normal array .!!! telling us that now baseaddress/pointer of array has been shifted and when i execute it, throwed me an error.! As far as i know you can't change the base address isn't it .! – surya kiran Dec 10 '20 at 22:59
13

Arrays in C are indeed pointers, but constant pointers, which means after declaration their values can't be changed.

int arr[] = {1, 2, 3};
// arr is declared as const pointer.

(arr + 1) is possible but arr++ is not possible because arr can not store another address since it is constant.

MD XF
  • 7,484
  • 7
  • 37
  • 66
Sushil Kadu
  • 419
  • 3
  • 5
5
char x[10];
char y[] = "Hello";
char *p_x = &x[0];
char *p_y = &y[0];
while(*p_y != '\0') *p_x++ = *p_y++;

Since you can't modify the array addresses (done by x++ and y++ in your code) and you can modify the pointer address, I copied over the address of the array into separate pointers and then incremented them.

If you want, I'm sure you can reduce the notation, but I hope you got the point.

Jacob
  • 33,685
  • 14
  • 109
  • 164
3

x and y are arrays, not pointers.

They decay into pointers in most expression contexts, such as your increment expression, but they decay into rvalues, not lvalues and you can only apply increment operators to lvalues.

CB Bailey
  • 700,257
  • 99
  • 619
  • 646
2

At most times, array just like a pointer.

Just remember you can't modify array!

And y++ is y = y + 1.

char y[] = "Hello";

So you do modify array when you y++!!

It will produce error: lvalue required as increment operand.

user2959760
  • 380
  • 2
  • 10
1

We can not modify a array name, but What about argv++ in f(int argv[])?

Quotes from K&R in p99 “an array name is not a varible; construction like a = pa and a++ are illegal" which says the name of an array is a synonym for the location of the initial element.”

But why in function parameter func(char *argv[]), we can do argv++ despite of argv is a array name.

And in int *a[10], we can't do the a++ like argv++.

The name of array is a synonym for the location of the initial element. ---K&R

arrayname++ is illegal.

In function parameter, such as char *argv[], it is the same as char **argv. type *arrayname_para[] in parameter is a another synonym for type **arrayname_para.

EvanL00
  • 320
  • 2
  • 12
1

Since you've defined both x and y as arrays, you can't modify them. One possibility would be to use pointers instead:

char x[10];
char *xx = x;

char *y = "Hello";

while (*y != '\0')
    *xx++ = *y++;

Note that I've also fixed your termination condition -- a pointer won't become NULL just because it's reached the end of a string.

Jerry Coffin
  • 455,417
  • 76
  • 598
  • 1,067
1

Array is a static continuous block of allocated memory. Array names are immutable references to the first block memory. An attempt to increment the address (referenced by name of array) would result in loss (better to say deference) of other memory locations. Say we have array

int p[]={10,20,30}

Here p (by design) refers to index 0. Say somewhere we increment p as : p++
Assuming increment to be allowed would result in p to point to index 1. Now thinking what p[1]=?
p[1] would then translate to dereferencing the value one place to the right of the current p location

Or location p[2] for original array.
Do this repeatedly and soon tracking the array indices would become very troublesome.
So to avoid such mishaps array names(lvalues) addresses are immutable. Another concept is word addressing and byte addressing:-

Character Arrays(string) in C are byte addressable instead of being word addressable. So if we have an array

int a[]={10,20,30}

printf("%d",*(a+1)) //Ouput:20 (int is word addressable)
printf("%d",*(++a)) // Error: Array references are immutable

int* cpya=a;
printf("%d",*(++cpya)) /* Output:20 (cpy is not array reference but a copy. Hence is Mutable) */

char b[]="Hello"
printf("%c",*(++b)) // Error : Array references are immutable
printf("%c",*(b+1)) /* undefined_behavior as character Array(strings) are byte addressable and not word addressable */
printf("%c",*(b+sizeof(char)*1)) // Output :e (It's byte addressable).

To understand more I suggest reading the official docs for B Programming Lang at
[B Reference Manual- Data Objects][1]
LFC
  • 30
  • 5
-1

Arrays are constant pointers. We can't change them.

int q;
int *const p = &q;
p = NULL; // this is not allowed.
Jeffrey Bosboom
  • 12,791
  • 16
  • 74
  • 91
Sujon
  • 1