I was wondering if you could help me overcome a hurdle I've run into with my C syntax. I have written the function:
binary_and_trim(char *password, unsigned *key1, unsigned *key2)
that has achieved the goal of converting a provided string into binary and trimmed off the leading zero. I have assigned my key1 and key2 pointers to the correct indexes. But then, when I return to the main function the values are all lost.
I believe that the problem is that when I pass the *key1/*key2 pointers to the function it only receives a copy of them. But, as I am new to C, I don't know how to fix it?
I created a for loop to help me test/debug.
#include <stdio.h>
#include <string.h>
void binary_and_trim(char *password, unsigned *key1, unsigned *key2);
unsigned int get_n_bits(unsigned *bits, int width, int index);
int main(int argc, const char * argv[]) {
unsigned *key1 = NULL;
unsigned *key2 = NULL;
binary_and_trim("password", key1, key2);
//This test fails with a EXC_BAD_ACCESS error
for(int i = 0 ; i < 28; i++){
printf("key1[%d] %u key2[%d] %d\n", i, key1[i], i, (key2 + i));
}
}
void binary_and_trim(char *password, unsigned *key1, unsigned *key2){
char c;
int count = 0;
unsigned tmp;
unsigned long len = strlen(password);
unsigned trimmedbinary[len * 7];
for(int i = 0; i < len; i++){
c = *(password + i);
for( int j = 6; j >= 0; j--) {
tmp = 0;
if(c >> j & 1){
tmp = 1;
}
*(trimmedbinary + count) = tmp;
count++;
}
}
key1 = trimmedbinary;
key2 = &trimmedbinary[28];
//This test works correctly!!!
for(int i = 0 ; i < 28; i++){
printf("key1[%d] %d key2[%d] %d\n", i, *(key1 + i), i, *(key2 + i));
}
}
I believe that the problem is that when I pass the *key1/*key2 pointers to the function it only receives a copy of them.
Yes, exactly. Pointers are just integers and integers get copied. You solve this with a pointer to a pointer, a "double pointer".
However, there is another problem. trimmedbinary is using stack/automatic memory. "Automatic" meaning it will be freed once the function exits. Once the function returns key1 and key2 will point at freed memory. trimmedbinary must be declared in heap/dynamic memory with malloc.
void binary_and_trim(char *password, unsigned int **key1, unsigned int **key2){
unsigned int *trimmedbinary = malloc(len * 7 * sizeof(unsigned int));
...
*key1 = trimmedbinary;
*key2 = &trimmedbinary[28];
for(int i = 0 ; i < 28; i++) {
printf("key1[%d] %u, key2[%d] %u\n", i, (*key1)[i], i, (*key2)[i]);
}
return;
}
And call it as binary_and_trim("password", &key1, &key2);
Update: I answered the question about how to alter the pointer value, but I have not noticed the memory issue in the code. Please refer to this answer instead.
Pointers are variables themselves. You may already know that with a pointer, you can change the value stored in the variable the pointer points to. Therefore, you need to use a pointer to a pointer to change the value (the memory address) stored in the pointer.
Change your function signature to:
void binary_and_trim(char *password, unsigned **key1, unsigned **key2)
Call with:
binary_and_trim("password", &key1, &key2);
and replace key1 and key2 to *key1 and *key2 in the function definition.
Your problem is that the variable you use to fill with your keys data trimmedbinary is allocated only for the scope of the function binary_and_trim. That said, when you print inside the function
void binary_and_trim(char *password, unsigned **key1, unsigned **key2){
...
unsigned trimmedbinary[len * 7]; // <--
...
*key1 = trimmedbinary; // <--
*key2 = &trimmedbinary[28]; // <--
//This test works correctly!!!
for(int i = 0 ; i < 28; i++){
printf("key1[%d] %d key2[%d] %d\n", i, *(key1 + i), i, *(key2 + i));
}
}
it just works because the data your key1 pointer is trying to access is still there.
However, when you return from your function back to main, key1 and key2 still point back to the buffer you initialized inside binary_and_trim, which is no longer valid because is out of scope.
I suggest you create a buffer in main and pass it as a parameter,
int main(int argc, const char * argv[]) {
const char* password = "password";
unsigned long len = strlen(password);
unsigned buffer[len * 7]; // <-- Add buffer here
unsigned *key1 = NULL;
unsigned *key2 = NULL;
binary_and_trim(password, &key1, &key2, &buffer, len * 7);
//This test succeeds
for(int i = 0 ; i < 28; i++){
printf("key1[%d] %u key2[%d] %d\n", i, key1[i], i, (key2 + i));
}
}
void binary_and_trim(char *password, unsigned **key1, unsigned **key2, unsigned** buffer, size_t buff_size){
char c;
int count = 0;
unsigned tmp;
...
//Use *buffer instead of trimmedbinary
//Check if buff_size matches len(password) * 7
or alternatively, make the buffer heap allocated (dont forget to free() later).
I believe that the problem is that when I pass the *key1/*key2
pointers to the function it only receives a copy of them.
Already altered in code as well.
Wow! Thank you EVERYONE! I finally got it up and running (after 4 hours of beating my head against the wall). I can't begin to say how clutch you all are.
I'm realizing I have tons to learn about the granular memory access of C (I'm used to Java). I can't wait to be an actual WIZARD like you all!
Related
I'm trying to iteratively copy an unsigned char array to a uint_32t variable (in 4 byte blocks), perform some operation on the uint_32t variable, and copy it back to the unsigned char array.
Here's my code:
unsigned char byteArray[len]
for (int i=0; i<len; i+=4) {
uint32_t tmpInt = 0;
memcpy(&tmpInt, byteArray+(i*4), sizeof(uint32_t));
// do some operation on tmpInt here
memcpy((void*)(byteArray+(i*4)), &tmpInt, sizeof(uint32_t));
}
It doesn't work though. What's wrong, and how can I achieve what I want to do?
The problem is that you are adding 4 to i with each iteration and multiplying by 4. You should be using byteArray + i.
Also, as #WeatherVane pointed out below, your loop would be more consistent with a sizeof():
for (int i = 0; i < len; i += sizeof(uint32_t)).
As others pointed out you are doing too much by incrementing i as well as multiplying it by the size of your target.
On top of this
the code shown might run into a buffer overflow issue reading beyond the source array.
the sizeof operator evaluates to size_t not int.
the code repeats defining the size of the target independently several times.
Fixing all, the result might look like this:
unsigned char byte_array[len];
typedef uint32_t target_type;
const size_t s = sizeof (target_type);
for (size_t i = 0; i < (len/s)*s; i += s) {
target_type target;
memcpy(&target, byte_array + i, s);
// do some operation on target here
memcpy(byte_array + i, &target, s);
}
To avoid the typedef just define the target outside of the for-loop:
unsigned char byte_array[len];
{
uint32_t target;
const size_t s = sizeof target;
for (size_t i = 0; i < (len/s)*s; i += s) {
memcpy(&target, byte_array + i, s);
// do some operation on target here
memcpy(byte_array + i, &target, s);
}
}
An equivalent to
byte_array + i
would be
&byte_array[i]
which might be more intuitively to read.
To avoid the "strange" (len/s)*s one could step away from using an index at all, but use a pointer instead:
for (unsigned char p = byte_array; p < byte_array + len; p += s) {
memcpy(&target, p, s);
// do some operation on target here
memcpy(p, &target, s);
}
In my opinion this is a more elegant solution.
I'm studying C at uni and am trying to access the string (the string representation of a binary-number) that was passed into a function to convert it into the integer-representation of that string.
Eg. "011" should return 3.
The string is the first 3 bits in a bitstream that's inputted in reverse.
char * temp_holder = (char *)malloc(sizeof(char) * 4);
int index_of_holder = 0;
for(int i = 2; i >= 0; i--){
printf("%c", buffer[i]);
temp_holder[index_of_holder] = buffer[i];
}
printf("\n");
int decimalValue = fromBinaryToInt(&temp_holder, 3);
printf("DECIMAL_VALUE: %d\n", decimalValue);
The fromBinaryToInt function is:
int fromBinaryToInt(char *string[], int length){
for(int i = 0; i < length; i++){
printf("%c", *string[i]);
}
int int_rep = strtol(*string, (char **)NULL, 2);
printf("REP: %d\n", int_rep);
return int_rep;
}
The subsequent error I get is:
==21==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7ffda9f47a08 at pc 0x000000500cdf bp 0x7ffda9f47980 sp 0x7ffda9f47978
- READ of size 8 at 0x7ffda9f47a08 thread T0
I thought this could be due to the null-terminating character so I played around with modifying the length variable (+/- 1) in the for-loop within fromBinaryToInt but that hasn't changed anything.
I also considered the for-loop only accessing the first element and nothing more - but my understanding is I've sent through the memory address and the length of the block so the for-loop should have access to the indexes.
Any help would be greatly appreciated,
Cheers :)
In this code:
int index_of_holder = 0;
for(int i = 2; i >= 0; i--){
printf("%c", buffer[i]);
temp_holder[index_of_holder] = buffer[i];
}
index_of_holder is never changed, so all the characters are put in temp_holder[0]. The rest of temp_holder remains uninitialized.
This:
int fromBinaryToInt(char *string[], int length)
declares string to be an array of pointers to char. It is indeed passed &temp_holder, which may be considered to be a pointer to the first element of an array of one pointer to char. However, a more normal usage is to declare a simple pointer to char
int fromBinaryToInt(char *string, int length)
and pass it temp_holder, as in fromBinaryToInt(temp_holder, 3).
As it is, where it is used here:
printf("%c", *string[i]);
This takes element i of the array. When i is 0 in the loop, that is fine, it takes the first element, which exists and is a pointer to char, and then deferences it with * and prints that. However, when i is 1, it attempts to take the second element of the array. That element does not exist, and the resulting behavior is undefined.
If the parameter were merely char *string, then this printf could be:
printf("%c", string[i]);
and, in calling strtol, you would simply pass string rather than *string:
int int_rep = strtol(string, (char **)NULL, 2);
Firstly, bug in below line, index_of_holder remains same all the time, please increment it.
temp_holder[index_of_holder] = buffer[i];
Secondly, in fromBinaryToInt() string is single pointer only so you can't do *string[i]); in the next printf statement.
Here is the working code
int fromBinaryToInt(char *string, int length){
for(int i = 0; i < length; i++){
printf("%c", string[i] ); /*since string is single pointer now you can do like before you did */
}
int int_rep = strtol(string, (char **)NULL, 2);
printf("REP: %d\n", int_rep);
return int_rep;
}
int main() {
char * temp_holder = (char *)malloc(sizeof(char) * 4);
char buffer[4] ="011";
int index_of_holder = 0;
for(int i = 2; i >= 0; i--){
printf("%c", buffer[i]);
temp_holder[index_of_holder] = buffer[i];
index_of_holder++;
}
printf("\n");
int decimalValue = fromBinaryToInt(temp_holder, 3);/* no need to pass address of temp_holder */
printf("DECIMAL_VALUE: %d\n", decimalValue);
return 0;
}
I have a char * who points to the structure. Here is my structure:
struct prot
{
int size;
unsigned short codeAction;
void *data;
};
I recovered size and codeAction, but now I want to recover data.
And when I cast my last 8 bytes I have nothing in it.
The following code is just a test, it's a bad code:
char lol[4];
for (int i = 0; i < 4; i++)
lol[i] = test[i];
int size = *(int*)lol;
char loli[2];
int index = 0;
for (int i = 4; i < 6; i++)
{
loli[index] = test[i];
index++;
}
int code = *(short*)loli;
char lolo[8];
index = 0;
for (int i = 6; i < size; ++i)
{
lolo[index] = test[i];
index++;
}
void *newData = (char *)lolo; // how can I cast it?
How I can display the content of newData?
Your problem is that when casting lolo you actually cast a pointer to the char array you defined. So the result of the cast would be a char pointer to the first cell of the array.
Why don't you just use this as a struct and access the fields regularly?
Anyway, you want to use lolo as a 64 bit type pointer and the access what's in it.
void* newData = *((uint64_t*)lolo)
Besides, don't loop until size in the last for loop, loop only 8 times, until lolo is full. The number of bytes in newData itself (not what it points to) is constant, and is 4 bytes on 32bit machines, 8 bytes on 64bit ones.
Last thing - index++, not o++. o isn't defined, as much as I can see.
I have an error at the last line, in nullString, a function setting all the string to '\0' with a simple for()
void function ( unsigned char inputArray[], size_t inputSize )
{
size_t cellSize;
if (inputSize <= 256)
cellSize = 1;
else
cellSize = ceil(inputSize / 2 / 256) + 1;
// Sub Box
unsigned char subBox[255];
for (size_t line = 0; line < 255; line++)
subBox[line] = 0;
generate_SubBox(subBox, key);
// Sub Box
// Sub Box reverse
unsigned char subBox_Inverse[255];
for (size_t line = 0; line < 255; line++)
subBox_Inverse[line] = 0;
generate_SubBox_Inverse(subBox_Inverse, subBox, key);
// Sub Box reverse
unsigned char* inputArray2 = NULL;
inputArray2 = malloc(sizeof(unsigned char)* inputSize / 2);
verifyMalloc(inputArray2);
nullString(inputArray2, inputSize / 2);
unsigned char string_temp[3] = { 0 };
size_t w = 0;
for (size_t i = 0; i < inputSize / 2; i++)
{
string_temp[0] = inputArray[w];
string_temp[1] = inputArray[w + 1];
inputArray2[i] = strtoll(string_temp, NULL, 16);
w += 2;
}
}
I tried neutralizing line per line all instructions coming before nullString() by commenting them but it doesn't change anything.
If I neutralize nullString, the error comes after, at
inputArray2[i] = strtoll(...)
Hope you've got the answer :)
Thanks in advance !
EDIT:
Here is nullString:
void nullString(unsigned char input[], size_t length)
{
for (size_t x = 0; x < length; x++)
input[x] = '\0';
}
I commented all the instructions before nullString, the error is still there.
I also verified variables and they all look like good
EDIT 2:
verifyMalloc:
void verifyMalloc(int* pointer)
{
if (pointer == NULL)
{
perror("Erreur");
Sleep(15000);
exit(0);
}
}
Everything we're seeing is seriously hinting at you forgetting to #include <stdlib.h> (and ignoring the warnings resulting from that).
This is what might happens when you use malloc() without including stdlib.h in the same file:
the compiler consider the malloc() function to be declared implicitly, which means it is assuming that it's return types is int (instead of *void).
This might work when sizeof (int) is the same as sizeof (*void). But when int is 32-bits while pointers are 64-bits then the address returned by malloc() might lose half of it's bits and point to an invalid address.
Try using
void bzero(void *s, size_t n); or
void *memset(void *s, int c, size_t n);
instead of your nullString() and for()something[x]=0 loops.
Then, this does not make all of the array zeroed:
unsigned char string_temp[3] = { 0 };
This makes
string[0] = 0;
string[1] = god_knows;
string[2] = god_knows_not;
so either - unsigned char string_temp[3] = {0,0,0};
or bzero(string_temp,3);
Consequently, when you do this:
string_temp[0] = inputArray[w];
string_temp[1] = inputArray[w + 1];
inputArray2[i] = strtoll(string_temp, NULL, 16);
strtoll() will be guessing when to stop. No guarantee this would be at string_temp[2].
Then, this should be enough:
unsigned char* inputArray2 = malloc(sizeof(unsigned char) * inputSize / 2);
inputArray2 will be NULL if malloc failed, or a valid pointer if it succeeded.
You may want to check your inputSize / this_and_that arithmetics. Does it really deliver what you expect? You might be surprised by division result of integer operands.
This also looks suspicious:
inputArray2[i] = strtoll(string_temp, NULL, 16);
strtoll returns longlong integer but your inputArray2 is of unsigned char type. So you are trying to store 8 bytes (sizeof longlong = 8) and you reserved place only for one (sizeof char = 1)
Redeclare your inputArray2 as long long
long long *inputArray2 = malloc(sizeof(long long) * inputSize /2 );
And try this with memset():
size_t size = sizeof(long long) * inputSize/2;
//Do you really need long long? You are storing max three digits. uint_8 will be enough
long long* inputArray2 = malloc(size);
memset(inputArray2, 0, size);
I'm doing a school project and this problem came up.
by the way, i can't use library.
How to convert a int variable to char array?
I have tried this but it didn't work, tried a lot of other things and even magic doesn't work...
char *r = malloc(sizeof(char*));
int i = 1;
r[counter++] = (char) i;
Can someone help me?
Thank you for your time.
In your code, you should allocate for char size and not char *. Please try with this code segment
char *r = malloc(sizeof(char) * N); // Modified here
int i = 1;
r[counter++] = i & 0xff; // To store only the lower 8 bits.
You could also try this:
char *r = malloc(sizeof(char));
char *s = (char*)&i;
r[counter++] = s[0];
This is an other funny way to proceed and it allows you to access the full int with:
s[0], s[1], etc...
Do you mind losing precision? A char is generally 8 bits and an int is generally more. Any int value over 255 is going to be converted to its modulo 255 - unless you want to convert the int into as many chars as is takes to hold an int.
Your title seems ot say that, but none of the answers give so far do.
If so, you need to declare an array of char which is sizeof(int) / sizeof(char) and loop that many times, moving i >> 8 into r[looop_var]. There is no need at all to malloc, unless your teacher told you to do so. In whch case, don't forget to handle malloc failing.
Let's say something like (I am coding this w/o compiling it, so beware)
int numChars = sizeof(int) / sizeof(char);
char charArry[numChard]; // or malloc() later, if you must (& check result)
int convertMe = 0x12345678;
int loopVar;
for (loopVar = 0; loopvar < numChars)
{
charArry[loopVar ] = convertMe ;
convertMe = convertMe >> 8;
}
If you can't use the library, you can't use malloc.
But this will work:
int i = 0;
char *p = (char *)&i;
p[0] = 'H';
p[1] = 'i';
p[2] = '!';
p[3] = '\0';
printf("%s\n", p);
Assuming your int is 32bit or more (and your char is 8).
It then follows that if you have:
int i[100];
You can treat that as an array of char with a size equal to sizeof (i). i.e.
int i[100];
int sz = sizeof(i); // probably 400
char *p = (char *)i; // p[0] to p[sz - 1] is valid.
You can use a union instead. Assuming that sizeof int == 4,
typedef union {
int i;
char[4] cs;
} int_char;
int_char int_char_pun;
int_char_pun.i = 4;
for (int i = 0; i < 4; i++) {
putchar(int_char_pun.cs[i]);
}
Be careful; int_char.cs usually won't be a null-terminated string, or it might be, but with length < 4.
if you don't want to include the math library:
unsigned long pow10(int n);
void main(){
char test[6] = {0};
unsigned int testint = 2410;
char conversion_started = 0;
int i=0,j=0;float k=0;
for(i=sizeof(test);i>-1;i--){
k=testint/pow10(i);
if(k<1 && conversion_started==0) continue;
if(k >= 0 && k < 10){
test[j++]=k+0x30;
testint = testint - (k * pow10(i));
conversion_started=1;
}
}
test[j]=0x00;
printf("%s",test);
}
unsigned long pow10(int n){
long r = 1;
int q = 0;
if(n==0) return 1;
if(n>0){
for(q=0;q<n;q++) r = r * 10;
return r;
}
}
NOTE: I didn't care much about the char array length, so you might better choose it wisely.
hmm... what is wrong with the code below
char *r = malloc(sizeof(char) * ARR_SIZE);
int i = 1;
sprintf(r,"%d",i);
printf("int %d converted int %s",i,r);
will it now work for you