Code: Select all
char *data_1;
char *data_2;
Are allocated on the stack for the function. These variables are called local. They are always allocated on the stack. Lets talk a little about variables in C. You have quite a few basic ones like: char, short, and int.
Signed/Unsigned And Space Used On i386+
Then you can perpend unsigned or signed onto them like: unsigned short, signed int, or unsigned char. On a i386+ machine all types are by default signed.
So what does signed and unsigned mean? Well, they have to do with weather the integer can handle negative numbers. In mathematics you have something called a sign that tells if a number is negative like: +4, -5, or 6. Where 6 is by default positive. On the i386 processor there exists instructions to deal with signed or unsigned numbers. Why have unsigned or signed numbers? Well, the represent a number as negative or positive requires some space to store this. It is stored for a signed number in the most significant bit. If you remember that a byte is eight bits then you should understand that a signed byte would only have seven actual bits to store a value since the eight-th bit is used for the negative or positive sign.
This causes your data types like: char, short, and int; to change range. The range is two numbers that describe what values the integer can hold. For example:
unsigned char 0 to 255
signed char -128 to 128
unsigned short 0 to 65535
signed short -32767 to 32767
unsigned int 0 to 4294967296
signed int -2147483648 to 2147483648
Also lets go over how much space each takes on the i386+.
unsigned char and signed char take 1 byte
unsigned short and signed short take 2 bytes
unsigned int and signed int take 4 bytes
More Portable Types
You can also use the include file stdint.h like: #include <stdint.h>
Which defines types such as:
uint8_t, int8_t, uint16_t, int16_t, uint32_t, int32_t that are guaranteed to use the same numbers of bytes no matter what machine your are targeting when compiling.
http://en.wikipedia.org/wiki/Stdint.h
Local Function Variables On Stack
When your function is compiled the compiler emits machine instruction that reserve some space on the stack. This space it reserves is enough to hold your local function variables. Lets say you have:
Code: Select all
char myVariable1;
char myVariable2;
Code: Select all
printf("The size of a char is %u.\n", sizeof(char));
Code: Select all
sub %esp, $2
Code: Select all
myFunction:
mov %esp, %ebp
sub %esp, $2
movb $0, (%ebp)
movb $1, $-1(%ebp)
call myOtherFunction
ret
Code: Select all
void myFunction(void)
{
char myVariable1;
char myVariable2;
myVariable1 = 0;
myVariable2= 1;
myOtherFunction();
return;
}
Local Function Variable Arrays
Lets say you want to use arrays as local function variables. For instance:
Code: Select all
char myVariable[25];
The actual amount of space on a i386+ is 25 bytes, because each char is one byte in size for that times 25 gives 25. If we used a short it would reserve 50 bytes instead of 25 since a short takes two bytes. Another example is a unsigned short which will take 50 bytes just like a signed short. The only difference in signed and unsigned is the instructions the compiler generates to perform operations on the data that the processor executes.
Pointers
Lets take a close look at pointer since they seem to be the core of much confusion. They are actually part of your problem of why both buffers always contain the same data. Take a look at:
Code: Select all
char *pchar;
short *pshort;
int *pint;
Lets take a look at the difference in instructions when using a pointer and basic data type.
Code: Select all
---- C/C++ Code ---
char *pchar;
short *pshort;
pchar = 0;
pchar = (char*)5;
pshort = 0;
pshort = (short*)3;
--- GAS Assembly ---
mov %esp, %ebp
addl %esp, $8
movl $0, (%ebp)
movl $5, (%ebp)
movl $0, $-4(%ebp)
movl $3, $-4(%ebp)
Code: Select all
---- C/C++ Code ---
char a;
short b;
a = 0;
a = 5;
b = 0;
b = 3;
--- GAS Assembly ---
movl %esp, %ebp
addl %esp, $3
movb $0, (%ebp)
movb $5, (%ebp)
movw $0, $-1(%ebp)
movw $3, $-1(%ebp)
Code: Select all
---- C/C++ Code ---
char *pchar;
short *pshort;
pchar = 0;
*pchar = 5;
pshort = 0;
*pshort = 3;
--- GAS Assembly ---
movl %esp, %ebp
addl %esp, $8
movl $0, (%ebp)
movl (%ebp), %eax
movb $5, (%eax)
movl $0, $-4(%ebp)
movl $-4(%ebp), %eax
movw $3, (%eax)
Code: Select all
pchar = (char*)3392;
So since pchar is a pointer to char type we must use it like a pointer. There are two ways:
Code: Select all
*pchar = 5;
pchar[0] = 5;
*(pchar + 1) = 22;
pchar[1] = 22;
Code: Select all
char ***a;
***a = 5;
Code: Select all
movl (%ebp), %eax
movl (%eax), %eax
movl (%eax), %eax
movb $5, (%eax)
Just Using A Pointer
Lets say you do something like:
Code: Select all
char *buffer_1;
char *buffer_2;
You have to initialize the pointer to point somewhere, or it could essentially cause the program to terminate from an exception. It could overwrite data or code in your program and thats not good unless you do it on purpose and in this case you have no control. So we have two ways to initialize pointers under normal circumstances.
Malloc (C/C++ Language)
Code: Select all
buffer_1 = malloc(sizeof(char) * 100);
buffer_2 = malloc(sizeof(char) * 100);
Code: Select all
buffer_1 = new char[100];
buffer_2 = new char[100];
Code: Select all
buffer_1 = (char*)0x91838;
buffer_2 = (char*)0x99382;
Once you make these calls they will fill the pointer with an address to an area of memory. the new char[100] and malloc(sizeof(char) * 100) both allocate 100 bytes since a char is one byte in size and 100 times 1 equals 100.
Once this is done you can use your pointers..
To Fix Your Problem
Try something like:
Code: Select all
char *buffer_1 = (char*)malloc(sizeof(char) * 50);
char *buffer_2 = (char*)malloc(sizeof(char) * 50);