Undefined behaviour with char arrays

closed account (SNToE3v7)
I compiled a simple c++ program involving char arrays, i am getting serious undefined behaviour, please help, i am having the problem with TDM-GCC-5.1-32BIT, it works fine on 64bit tdm-gcc-5.1. The program output is here, please check it, this also has the 32 and 64 bit compiled programs :
https://drive.google.com/folderview?id=1s3-7P3a92ofY92HbU3v_QDUX8orToeMl
32bit output:
https://drive.google.com/file/d/1cZraOCLryR2JXwJj5GyJ35xOk1Fl9GMX/view?usp=drivesdk

64bit output:
https://drive.google.com/file/d/1J7YBba5Wbuwoh2Ge6Pu1BGoX6Q96Cmkh/view?usp=drivesdk

The issue is that the data in id is copied to sid and it holds 4 char even though its defined size is 2
Code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
 
#include <iostream>
#include <string>
#include <stdlib.h>
using namespace std;

struct AuthDataParsed
{
	int ID;
	int sID;
}; 
void AuthDataParser(char RawMessage[],AuthDataParsed& msg)
{
	char id[2] = " ",sid[2] = " ";
	cout<<"msg: "<<RawMessage<<endl;
	for(int i=0;i<2;i++)
	{
		id[i] = RawMessage[i];
		cout<<"first loop: "<<id[i]<<" "<<RawMessage[i]<<endl;
	}
	
	for(int j=0;j<2;j++)
	{
		sid[j] = RawMessage[j+2];
		cout<<"second loop: "<<sid[j]<<" "<<RawMessage[j+2]<<endl;
	}
	
	cout<<"test sid: "<<sid[0]<<" "<<sid[1]<<" "<<sid[2]<<" "<<sid[3]<<" "<<sid[4]<<endl;
	
	cout<<"after operation: "<<id<<" "<<sid<<endl;
	cout<<"after atoi: "<<atoi(id)<<" "<<atoi(sid)<<endl;
	msg.ID = atoi(id);
	msg.sID = atoi(sid);
	cout<<"from struct :"<<msg.ID<<" "<<msg.sID<<endl;
}
 
int main()
{
  AuthDataParsed md;
  char message[10];
  cin>>message;
  AuthDataParser(message,md);
  cout<<md.ID<<" "<<md.sID<<endl;
  system("pause");
  return 0;
}
 


Last edited on
for(int i=0;i<2;i++)
{
id[i] = RawMessage[i];

if raw message isn't 1 character followed by a zero, it will crash if you do any string things to it anywhere.

this is completely broken also:

char id[2] = " ",sid[2] = " ";
cout<<"test sid: "<<sid[0]<<" "<<sid[1]<<" "<<sid[2]<<" "<<sid[3]<<" "<<sid[4]<<endl;

use std::string maybe?
Last edited on
closed account (SNToE3v7)
But is this some error on my part or its a compiler bug, correct my code if there's a mistake on my part.
There some kind of restraint, so that i cant use std::string
Does this bug exist across all 32bit c++ compilers or is it compiler specific?
And what do you mean by broken, is it doing the same blunder as i described?
Last edited on
This is an error on your part.

You declared char sid[2] which allocates 2 character positions which are sid[0] and sid[1]. Therefore references to sid[2], sid[3], sid[4] are out of bounds references.

closed account (SNToE3v7)
@AbstractionAnon, so you didnot see the image(the 32bit compiler output https://drive.google.com/file/d/1cZraOCLryR2JXwJj5GyJ35xOk1Fl9GMX/view?usp=drivesdk
Even though i do sid [2],etc i am seeing charecters stored in id,go ahead and correct the code, the problem will still be present

Please checkout the image, and analyze the code output and the code, maybe you will spot what i mean.
Last edited on
I fixed it (I made id and sid both 5 in size) and ran it with 12345 and I get:

12345
msg: 12345
first loop: 1 1
first loop: 2 2
second loop: 3 3
second loop: 4 4
test sid: 3 4
after operation: 12 34
after atoi: 12 34
from struct :12 34
12 34
sh: pause: command not found

is this the expected output (apart from the OS specific command line snafu)?

Last edited on
closed account (SNToE3v7)
pause is windows specific, you can remove that.
and did you use 64bit compiler or 32bit compiler, it runs alright on 64bit, the error is on 32bit
VeTech16

It's a bug in YOUR code, not the compiler.

Read what @jonnin and @AbstractionAnon wrote. You are trying to access arrays beyond their bounds. Your [] operator will point to any offset from the start of the array that you specify, even if it hasn't been set aside for array sid[]. You will access whatever happens to be there, and this is likely to be different between different compilers (and possibly the same compiler with different compile options).

If it works with one compiler then it is more by luck than judgement.

Don't deliberately try to access arrays beyond bounds.

And please stop asking people to click and access external sites. It's a recipe for malicious software. You can paste code and output directly here. If you need copies of output then redirect your program's output or error logs to a text file.
Last edited on
closed account (SNToE3v7)
@lastchance, i know that this should not be done, i did that to show that even though sid [] has size 2, still i can access beyond index 1.
And even if i remove that, even though i assigned sid[] two chars in the second loop, when i cout <<sid i get chars stored in sid+id.
That was my issue, and why did that happen??

closed account (SNToE3v7)
I figured that out from @jonin answer
I am using 2 element array, and storing exactly 2 members in it, there is no place to store the "/0" character. That was my error,
Is the reason for my problem correct?
If wrong, please correct me
Thankyou
I am using 2 element array, and storing exactly 2 members in it, there is no place to store the "/0" character. That was my error,


Partly; you won't be able to use functions like atoi() or print it out unless it has '\0' at the end. However, if you simply need to store 2 characters then an array size of 2 is fine. It may run differently on different compilers simply because various memory slots might, by luck or otherwise, contain '\0' at that point, so allowing routines like atoi() to operate on what they think is a valid C-string.

atoi(id) doesn't know anything about the declared length of id. It simply gets a pointer to the start and then keeps going until it finds a '\0'. Then it concludes that the C-string is finished. This may be long after the length of id.

The problem is your code, not the compiler.

Why not try
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <iostream>
#include <string>
using namespace std;

struct AuthDataParsed
{
   int ID;
   int sID;
}; 

void AuthDataParser( string RawMessage, AuthDataParsed& msg )
{
   msg.ID  = stoi( RawMessage.substr( 0, 2 ) );
   msg.sID = stoi( RawMessage.substr( 2, 2 ) );
}
 
int main()
{
   AuthDataParsed md;
   string message;
   cout << "Input message: ";     cin >> message;
   AuthDataParser( message, md );
   cout << "Message ID = " << md.ID << "      " << "Message sID = " << md.sID << endl;
}


Input message: 12345
Message ID = 12      Message sID = 34
Last edited on
closed account (SNToE3v7)
Thankyou, this solved my problem
Topic archived. No new replies allowed.