-2

My sourcecode:

#include <stdio.h>

int main()
{
    char myArray[150];
    int n = sizeof(myArray);
    for(int i = 0; i < n; i++)
    {
        myArray[i] = i + 1; 
        printf("%d\n", myArray[i]); 
    }
    return 0;
}

I'm using Ubuntu 14 and gcc to compile it, what it prints out is:

1
2
3
...
125
126
127
-128
-127
-126
-125
...

Why doesn't it just count up to 150?

Amit
  • 41,690
  • 8
  • 66
  • 101
steve178
  • 1
  • 2
  • Doesn't it seem suspicious to you that it stops at 127 (2^7-1) ? – cnicutar Aug 14 '15 at 09:46
  • Unpleasant is also, that you are using an `int` where a `size_t` should be used, as `sizeof` evaluates to such. Also it should at least be `int main(void)`. – alk Aug 14 '15 at 10:15
  • @alk Why is `int main()` incorrect? – fuz Aug 14 '15 at 10:22
  • Never use the plain `char` type for anything but strings. Instead, use `uint8_t`. – Lundin Aug 14 '15 at 11:14
  • 1
    @FUZxxl It may be correct on some freestanding systems but I doubt it. In most versions of C, it is incorrect. It is however perfectly fine in C++. [Complete reference](http://stackoverflow.com/a/31263079/584518). – Lundin Aug 14 '15 at 11:22
  • @Lundin Beginning with C99, an empty parameter list in a function *definition* specifies a function taking zero arguments, therefore `int main()` is valid and equal to `int main(void)`. Furthermore, the standard only specifies that the type of `main` shall be compatible to one of the two types provided. Even in C89, `int main()` is compatible to `int main(int, char**)`. – fuz Aug 14 '15 at 12:49
  • @FUZxxl Beginning with C99, empty parameter list (in declaration or definition) is also an obsolete feature which may be removed in the next version of the language. Unfortunately they didn't remove it in C11, so lets hope such stupid nonsense gets removed in Cxx. – Lundin Aug 14 '15 at 13:23
  • @FUZxxl [See this answer](http://stackoverflow.com/questions/12225171/difference-between-int-main-and-int-mainvoid/31336367#31336367). – Lundin Aug 14 '15 at 13:25
  • @Lundin What might be removed is an empty parameter list meaning “this function takes arbitrary arguments of arbitrary type.” The fact that the committee decided that an empty parameter list in a definition means “no argument” is a pretty good hint at what an empty parameter list is going to mean in a declaration once they remove this obsolete feature. – fuz Aug 14 '15 at 13:58

4 Answers4

3

int value of a char can range from 0 to 255 or -127 to 127, depending on implementation. Therefore once the value reaches 127 in your case, it overflows and you get negative value as output.

Nishant
  • 1,597
  • 1
  • 10
  • 24
2

The signedness of a plain char is implementation defined.

In your case, a char is a signed char, which can hold the value of a range to -128 to +127.

As you're incrementing the value of i beyond the limit signed char can hold and trying to assign the same to myArray[i] you're facing an implementation-defined behaviour.

To quote C11, chapter §6.3.1.4,

  1. Otherwise, the new type is signed and the value cannot be represented in it; either the result is implementation-defined or an implementation-defined signal is raised.
Sourav Ghosh
  • 127,934
  • 16
  • 167
  • 234
1

Because a char is a SIGNED BYTE. That means it's value range is -128 -> 127.

EDIT Due to all the below comment suggesting this is wrong / not the issue / signdness / what not...

Running this code:

char a, b;
unsigned char c, d;
int si, ui, t;
t = 200;

a = b = t;
c = d = t;
si = a + b;
ui = c + d;

printf("Signed:%d | Unsigned:%d", si, ui);

Prints: Signed:-112 | Unsigned:400
Try yourself

The reason is the same. a & b are signed chars (signed variables of size byte - 8bits). c & d are unsigned. Assigning 200 to the signed variables overflows and they get the value -56. In memory, a, b,c&d` all hold the same value, but when used their type "signdness" dictates how the value is used, and in this case it makes a big difference.

Note about standard

It has been noted (in the comments to this answer, as well as other answers) that the standard doesn't mandate that char is signed. That is true. However, in the case presented by OP, as well the code above, char IS signed.

Amit
  • 41,690
  • 8
  • 66
  • 101
  • 4
    *Because a char is a SIGNED BYTE*. Wrong, the standard doesn't say whether it's signed or unsigned. And you got 3 upvotes, shame on the upvoters. – cnicutar Aug 14 '15 at 09:47
  • `a char is a SIGNED BYTE`..can you quote something? – Sourav Ghosh Aug 14 '15 at 09:48
  • @cnicutar - You're right regarding standard, I'm right regarding what happened (`myArray` IS an array of signed bytes...) – Amit Aug 14 '15 at 09:49
  • @Amit Ummm.. I think no, as this is UB. So, nothing's guaranteed. – Sourav Ghosh Aug 14 '15 at 09:50
  • @SouravGhosh - are you referring to the use of the term byte vs. char? if so, what I meant is that it's a signed value in a byte sized variable – Amit Aug 14 '15 at 09:50
  • 3
    @cnicutar Just to make it clear, signedness of `char` is implementation defined, overflow of signed type is UB. Right? – Sourav Ghosh Aug 14 '15 at 09:52
  • @SouravGhosh Right. I figured you were talking about overflow. – cnicutar Aug 14 '15 at 09:52
  • @SouravGhosh, cnicutar. Beyond the discussion of UB's overflows & standards.. In terms of answering the question (*Whats wrong with this C code*, *Why doesn't it just count up to 150?*), Isn't my answer correct in your opinion(s)? Is it not that the "8 bit" variable used (array of actually) has a range of -128 -> 127? – Amit Aug 14 '15 at 09:55
  • @Amit, your answer is conceptually wrong, whether you think it explains the scenario here or not, is totally different. – vish4071 Aug 14 '15 at 09:59
  • And char is actually `unsigned` according to standard. So, your answer is essentially wrong – vish4071 Aug 14 '15 at 10:00
  • @vish4071 so if it's unsigned according to standard, Is the compiler used not following the standard, or is there any other reason why the output was as it was? – Amit Aug 14 '15 at 10:02
  • The reason is not compiler here. It is the format specifier of printf, '%d' in this case that is causing this, as %d prints signed int values. This is in no way, related to 'char' as a data type. – vish4071 Aug 14 '15 at 10:03
  • @vish4071 you're wrong. bluntly wrong. change the array type to `int ..[]` and everything will work just fine.in this case `char` IS signed, and overflows on assignment. After that manipulating with format specifiers doesn't change the value, just the representation – Amit Aug 14 '15 at 10:06
  • @Amit, that is because int is 4 bytes and 8th bit is not the sign-bit then. – vish4071 Aug 14 '15 at 10:09
  • @vish4071 see edited answer, I hope you understand now. – Amit Aug 14 '15 at 10:17
  • hmm, ok @Amit, I get it now. – vish4071 Aug 14 '15 at 10:25
0

It seems that your compiler by default considers type char like type signed char. In this case CHAR_MIN is equal to SCHAR_MIN and in turn equal to -128 while CHAR_MAX is equal to SCHAR_MAX and in turn equal to 127 (See header <limits.h>)

According to the C Standard (6.2.5 Types)

15 The three types char, signed char, and unsigned char are collectively called the character types. The implementation shall define char to have the same range, representation, and behavior as either signed char or unsigned char

For signed types one bit is used as the sign bit. So for the type signed char the maximum value corresponds to the following representation in the hexadecimal notation

0x7F

and equal to 127. The most significant bit is the signed bit and is equal to 0.

For negative values the signed bit is set to 1 and for example -128 is represented like

0x80

When in your program the value stored in char reaches its positive maximum 0x7Fand was increased it becomes equal to 0x80 that in the decimal notation is equal to -128.

You should explicitly use type unsigned char instead of the char if you want that the result of the program execution did not depend on the compiler settings.

Or in the printf statement you could explicitly cast type char to type unsigned char. For example

printf("%d\n", ( unsigned char )myArray[i]); 

Or to compare results you could write in the loop

printf("%d %d\n", myArray[i], ( unsigned char )myArray[i]); 
Vlad from Moscow
  • 224,104
  • 15
  • 141
  • 268
  • Sir, I don't think the reason is compiler dependent. It is the format specifier of printf, '%d' in this case that is causing this. This is in no way, related to 'char' as a data type. – vish4071 Aug 14 '15 at 10:02
  • @vish4071 You are wrong. When the argument is promoted from type char to type int its signedness is preserved. – Vlad from Moscow Aug 14 '15 at 10:09