Change content of file - c

Can someone please break down this code for me? I know it changes text from a user file and I know it could be very useful to me. What is the purpose of "~"? How could I amend this code to read a user file word by word and then change it using the same kind of formula?
// first value in the file is the key
if ( fread(&key, sizeof(char), 1, infile) )
{
key = ~key;
}
while( fread(&fval ,sizeof(short), 1, infile) )
{
fputc( (fval / 2) - key, outfile );
}

key = ~key swaps all the bits of key
You know about bits?
ascii A (65) is 100 0001 in binary, so '~' of this is simply swaps each 1 for 0 and each 0 for 1 giving 011 1110 (62) which is >
So this will replace all the As in your document with > and similarly for every other character. The nice thing about ~ is that it's exactly the same process to decrypt - just swap each bit back.
ps. It's not exactly mil-spec encryption!

Comments inline!
#include <stdio.h>
int main(void)
{
/* Integer value of 'A' is 65 and
binary value is 01000001 */
char a='A';
printf("a=%d\n", a);
/* ~a is binary inverse of a so
~01000001 = 10111110 */
a=~a;
printf("a=%d\n", a);
/* easier example */
/* ~0 = 11111111 times # of bytes needed
to store int (whose value is nothing
but negative one) */
int i=0;
printf("i=%d\n", i);
i=~i;
printf("i=%d\n", i);
return 0;
}
$ ./a.out
a=65
a=-66
i=0
i=-1
$
With the above mentioned hint, could you please try and read the code and share your comments.
OTOH, what is crypt? what is its type? what is the value stored in it?!
For more bitwise operations, please refer this page!

Related

bits and arrays in C - New to programming

I have a given code from school, I need this as my output:
Digital Binair
0 is 000,
1 is 001,
2 is 010,
3 is 011,
4 is 100,
5 is 101,
6 is 110,
7 is 111
(3 bits)
I need to work with for loops, this is the given code:
#include <stdio.h>
#include <string.h>
#define ZERO '0'
#define ONE '1'
int main(void)
{
char rij[8][4];
int n, m;
strcpy( rij[0], "000" );
printf( "%s\n", rij[0] );
for ( n=1; n<8; n++ )
{
strcpy( rij[n], rij[n-1] );
printf( "%s\n", rij[n] );
// *ONLY ABLE TO TYPE IN HERE !!!! THE REST IS GIVEN !!!!*
}
for( n=0; n<8; n++ )
{
printf( "%i %s\n", n, rij[n] );
}
return 0;
}
I'm stuck at is how do I make a for loop that is working with bits. So lets say for(n = 0; n < 8; n++) how do I make the loop go form 000 to 001 to 010.
While there are many ways of generating a binary sequence, here the task appears to have been deliberately complicated (or made interesting) by the constraint that you modify code only at the location indicated and the initialisation of each successive string with the content of the previous one.
The arrays serve no purpose other than to make you think - it is a purely academic exercise, not a practical application. Each string is initialised with the content of the previous string (which the code you must add will have modified), the intent of the exercise is that you perform a binary "add 1" at each iteration.
To do that, starting from the LSB (rij[n][2]), if the digit is ZERO you set it to ONE, then move to the next n, else you set it to ZERO, and "carry" one, repeating the above process for the next most significant bit in the string n.
You can do that in a loop from the LSB (2) index to the MSB (0) index, and exiting the loop (break) when you set any bit to ONE.
Or for just three digits you can unroll-the loop thus:
if( rij[n][2] == ZERO )
{
rij[n][2] = ONE ;
}
else
{
rij[n][2] = ZERO ;
if( ... // test next bit [1] - enough of a hint I think.

Writing an array of integers into a file using C [duplicate]

This question already has answers here:
How to write an array to file in C
(3 answers)
Closed 3 years ago.
I would like to write an array of integers into a file using C. However, I get some gibberish in the file.
The code is about a function that converts a decimal number into binary then stores it into a file.
int * decToBinary(int n) //function to transform the decimal numbers to binary
{
static int binaryNum[16]; // array to store binary number
int i = 0; // counter for binary array
while (n > 0) {
binaryNum[i] = n % 2; // storing remainder in binary array
n = n / 2;
i++;
}
return binaryNum;
}
int main()
{
FILE *infile;
int i;
int *p;
int decimal= 2000;
int written = 0;
infile = fopen("myfile.txt","w");
p = decToBinary(decimal);
written = fwrite(p,sizeof(int),sizeof(p),infile) ;
if (written == 0) {
printf("Error during writing to file !");
}
fclose(infile);
return 0;
}
This is what I get in my file:
This is what I get when I write a text as a test, it does not have any problem with the text, but it has with the array.
char str[] = "test text --------- \n";
infile = fopen("myfile.txt","wb");
p=decToBinary(decimal);
fwrite(str , 1 , sizeof(str) , infile);
written = fwrite(p,sizeof(int),sizeof(p),infile) ;
And this is what I get when I make this change:
written = fwrite(&p,sizeof(int),sizeof(p),infile) ;
First, be aware that there are two interpretations for 'binary':
int n = 1012;
fwrite(&n, sizeof(n), 1, file);
This writes out the data just as is; as it is represented in form of bits, output is considered "binary" (a binary file).
Your question and the code you provided, though, rather imply that you actually want to have a file containing the numbers in binary text format, i. e. 7 being represented by string "111".
Then first, be aware that 0 and 1 do not represent the characters '0' and '1' in most, if not all, encodings. Assuming ASCII or compatible, '0' is represented by value 48, '1' by value 49. As C standard requires digits [0..9] being consecutive characters (this does not apply for any other characters!), you can safely do:
binaryNum[i] = '0' + n % 2;
Be aware that, as you want strings, you chose the bad data type, you need a character array:
static char binaryNum[X];
X??? We need to talk about required size!
If we create strings, we need to null-terminate them. So we need place for the terminating 0-character (really value 0, not 48 for character '0'), so we need at least one character more.
Currently, due to the comparison n > 0, you consider negative values as equal to 0. Do you really intend this? If so, you might consider unsigned int as data type, otherwise, leave some comment, then I'll cover handling negative values later on.
With restriction to positive values, 16 + 1 as size is fine, assuming int has 32 bit on your system! However, C standard allows int to be smaller or larger as well. If you want to be portable, use CHAR_BIT * sizeof(int) / 2 (CHAR_BIT is defined in <limits.h>; drop division by 2 if you switch to unsigned int).
There is one special case not covered: integer value 0 won't enter the loop at all, thus you'd end up with an empty string, so catch this case separately:
if(n == 0)
{
binaryNum[i++] = '0';
}
else
{
while (n > 0) { /.../ }
}
// now the important part:
// terminate the string!
binaryNum[i] = 0;
Now you can simply do (assuming you changed p to char*):
written = fprintf(file, "%s\n", p);
// ^^ only if you want to have each number on separate line
// you can replace with space or drop it entirely, if desired
Be aware that the algorithm, as is, prints out least significant bits first! You might want to have it inverse, then you'd either yet have to revert the string or (which I would prefer) start with writing the terminating 0 to the end and then fill up the digits one by one towards front - returning a pointer to the last digit (the most significant one) written instead of always the start of the buffer.
One word about your original version:
written = fwrite(p, sizeof(int), sizeof(p), infile);
sizeof(p) gives you the size of a pointer; this one is system dependent, but will always be the same on the same system, most likely 8 on yours (if modern 64-bit hardware), possibly 4 (on typical 32-bit CPU), other values on less common systems are possible as well. You'd need to return the number of characters printed separately (and no, sizeof(binaryNum) won't be suitable as it always returns 17, assuming 32-bit int and all changes shown above applied).
You probably want this:
...
int main()
{
int decimal = 2000;
int *p = decToBinary(decimal);
for (int i = 0; i< 16; i++)
{
printf("%d", p[i]);
}
return 0;
}
The output goes to the terminal instead into a file.
For writing into a file use fopen as in your code, and use fprintf instead of printf.
Concerning the decToBinary there is still room for improvement, especially you could transform the number directly into an array of char containing only chars 0 and 1 using the << and & operators.

what is this "continue" does exactly?

I have this part of the code, I don't understand. I know "continue" in if, skips that statement. But why? It supposed to print out an array like " 073.45 * C". The i=2 is for the numbers, right? what does Temp_s[5-i}=result%10+0x30 do? Can someone explain this code please.
void Convert_data_to_temp(unsigned long data)
{
unsigned long result;
unsigned char i=0;
result=((33*1000*data)/4096)%100000;//rounding off to maximum 5 digits
Temp_s[0]=0x30;
Temp_s[3]='.';
for(i=0;i<6;i++)
{
if(i==2){continue;}
Temp_s[5-i]=(result%10)+0x30;
result=result/10;
}
Temp_s[i]=32;
Temp_s[i+1]=32;
Temp_s[i+2]='*';
Temp_s[i+3]=32;
Temp_s[i+4]='C';
Temp_s[i+5]=13;
Temp_s[i+6]=10;
}
Thanks
Well that's a nice mess for sure. Here's what this code does (assuming there's a Temp_s char array in scope that has at least 13 elements).
void Convert_data_to_temp(unsigned long data)
{
unsigned long result;
unsigned char i=0;
// Calculate... something.
// Apparently the calculation is done in fixed-point decimal,
// with 3 decimal places (hence `*1000`).
// Also, the comment is wrong: that's not rounding off, the result will wrap.
// In any case, we can be sure that 0 <= result < 100000.
result=((33*1000*data)/4096)%100000;//rounding off to maximum 5 digits
Temp_s[0]=0x30; // ASCII for '0'
Temp_s[3]='.';
// Now Temp_s looks like this (? represents an indeterminate value:
//
// 0 ? ? . ? ? ? ? ? ? ? ? ?
// Now we're filling Temp_s backwards from the 5th index,
// with the respective digits of `result`. The `continue` skips over
// index 3 so we don't overwrite the '.' we just put there.
for(i=0;i<6;i++)
{
if(i==2){continue;}
Temp_s[5-i]=(result%10)+0x30; // Again, 0x30 is just ASCII '0'.
result=result/10;
}
// Let's say that result was 12345. Now Temp_s looks like this:
//
// 1 2 3 . 4 5 ? ? ? ? ? ? ?
// And now we fill the rest of Temp_s with these hard-coded values.
// Note that we retrieve i at the value it was left by the for, i.e. 6.
Temp_s[i]=32; // 32 is an ASCII space
Temp_s[i+1]=32;
Temp_s[i+2]='*';
Temp_s[i+3]=32;
Temp_s[i+4]='C';
Temp_s[i+5]=13; // ASCII Carriage return
Temp_s[i+6]=10; // ASCII Line feed
// In the end, Temp_s looks like this:
//
// 1 2 3 . 4 5 [space] [space] * [space] C \r \n
}
Apparently the code is broken, too: the computation of result hints at 3-decimals fixed-point, but the representation ends up with only two decimals, and overwrites the '0' that was assigned at the very beginning.
I suggest you just throw that crazy code away and use the tried-and-true standard library:
snprintf(
Temp_s, sizeof Temp_s,
"%.3lu.%.2lu * C\r\n",
result / 100, result % 100
);
The code as a whole converts a 5-digit decimal number such as 54321 into "543.21 * C\r\n" — except that it doesn't ensure that the string is null terminated. However, if the target array Temp_s is a global variable and is big enough and is only written to by this function, then probably there is a null at the end already, but it is simpler and safer to make sure.
The assignment Temp_s[0]=0x30; could be dropped, and the loop could be written more clearly as:
for (i = 0; i < 6; i++)
{
if (i == 2)
Temp_s[5-i] = '.';
else
{
Temp_s[5-i] = (result % 10) + '0';
result /= 10;
}
}
strcpy(&Temp_s[6], " * C\r\n"); // Adds null termination
Frankly, though, it could (and maybe should) be written as a call to sprintf() (which also ensures that the string is null terminated):
int dp = result % 100;
int un = result / 100;
sprintf(Temp_s, "%.3d.%.2d * C\r\n", un, dp);
You could write instead (noting that result is an unsigned long, hence the change of format conversion specifier):
sprintf(Temp_s, "%.3lu.%.2lu * C\r\n", result / 100, result % 100);
It would be preferable to be able to use snprintf(), but it isn't clear how this global variable is declared, and using sizeof(Temp_s) might not be correct:
snprintf(Temp_s, sizeof(Temp_s), "%.3lu.%.2lu * C\r\n", result / 100, result % 100);
That's weird. Looks like you're iterating over that for loop, but you're not executing the code for i == 2. The continue statement sends you to the next iteration of the for loop before you do anything.
That'd the kind of code that'd really benefit from a well-placed comment..
Temp_s[5-i]=(result%10)+0x30;
Writes at index 5-i of the array Temp_s
The result modulo 10 + 48.
The continue skips the statements in the loop and goes back to the i++ statement and after that to the predicate of the loop. But only if i is equal to two.
All in all this should give you the result calculated before as a string representation.
The if i==2 preserves that you do not overwrite the '.'.

Writing binary in C

I am trying to write the value 0000 0100 (which is 4 in decimal) into a binary file in C. Here is my code:
FILE *fp = fopen("D:\\test.COM", "wb");
if (fp == NULL) {
printf("error creating file");
return -1;
}
int val = 100; // value 4
fwrite(&val, sizeof val, 1, fp);
fclose(fp);
return 0;
Can someone correct me? I don't want to assign 4 to val, I want to write actual binary in the code.
Thanks,
If you want the file to actually have the bits 0000 0010, then you want an 8-bit int, which is a char in C.
char val = (char) 4; // value 4
fwrite(&val, sizeof val, 1, fp);
Update: Based on the comments, it looks like the OP is asking how to convert a binary string of the form "00000010" into the bit representation. Yes, there is a way, but it requires you to do bit masking. The following should get you started.
char* input = "00000010";
char output = 0;
for (int i = 0; i < 8; i++)
if (input[i] == '1')
output |= (1 << (7-i)); // Set the appropriate sit of `output` to 1.
You can then use fwrite as in the first part of my answer.
Since BLUEPIXY did not write his own answer, I am incorporating his comment into this answer for completeness. While I think the above loop is instructive for a beginner, it is much faster to use the library function that he mentioned.
char val=strtol("00000100", NULL, 2);
You are trying to specify it in binary?
int val = 0b100; // value 4

keep getting ascii value where char is expected

When a coordinate is selected, it should be replaced with a "~". However, it's being replaced with the ascii value for the ~ instead (126). I tried a few different things, but I always get the 126 instead of the ~. Any ideas?
Thanks for the help!
int board_is_empty(int N, int board[ROWS][COLS])
{
int i = 0, j = 0;
for (i = 0; i < N; i++)
{
for (j = 0; j < N; j++)
{
if (board[i][j] != '~')
{
return 0;
}
}
}
return 1;
}
//updates the board to replace each selected coordinate with a ~.
//returns nothing
void update_board (int board[ROWS][COLS], int row_target, int column_target)
{
board[row_target][column_target] = '~';
}
int main(void)
{
int game_board[ROWS][COLS] = {0};
int rows, columns = 0;
int players_turn = 1, target_column = -1, target_row = -1, value = 0;
int row_selection = 0, column_selection = 0;
int i = 0;
initialize_game_board(game_board);
display_board(game_board);
generate_starting_point(game_board, &rows, &columns);
printf ("\nPlease hit <Enter> to continue.\n");
getchar ();
while (board_is_empty(ROWS, game_board) != 1)
{
select_target (&target_row, &target_column, players_turn);
value += game_board[target_row][target_column];
update_board (game_board, target_row, target_column); //should cause the coordinates at target_row && target_column to be replaced with a ~
display_board(game_board);
}
printf("\n%d", value);
}
'~' is a character and you have declared board as a two dimensional integer array.
so when you write board[row_target][column_target] = '~';
it convert '~' it into integer i.e into its ascii value which is 126
and there for it becomes board[row_target][column_target] = 126
I will suggest make board as two dimensional character array. Hopefully it will solve your problem.
And in case if you want it as integer only then consider 126 as a special no which means '~' by declaring
For storing your coordinates, you are using an integer array. When you execute
board[row_target][column_target] = '~'; tilde's ascii value (126) is assigned to LHS. There is no way you can assign a character to an integer value. I think you should use some special number rather than tilde. If I were you, I would use INT_MIN or INT_MAX.
There isn't a difference between the character '~' and the number 126 as far as the C language is concerned, '~' == 126.
(You used "~" which i would normally use for a string, but i assume you don't actually mean that).
If you want to display a value, you have to use the correct format string. %d is for decimal integers, %c would be for characters (the variable holding the value should also be a char)
In C, chars are just integers. At output time they are represented as characters but internally they hold just the ASCII code of that character.
Since your board is a matrix of int's, when you assign '~' you are effectively assigning the number 126 to a position of the board. If you check that position, the expected result is to get an int equal to 126.
However, if you want to see that value as a character, you can do it by casting that number into a char:
printf("%c", value);
Take a look:
#include <stdio.h>
int main()
{
int i = '~';
char c = '~';
printf("Integer: %d\n", i); /* outputs: 126 */
printf("Char: %c\n", c); /* outputs: ~ */
printf("Integer casted to char: %c\n", i); /* outputs: ~ */
}
That is, your value is right. You just need to get the representation you want. (If you want to be able to store the value 126 in the board and the character ~ at the same time, then you're out of luck because for C they are the same thing -you can use some other value that you know that the board isn't going to hold, like -1 or something like that).
Update:
So, if I didn't get it wrong what you're trying to do is to read numbers from a bidimensional matrix of random integers and mark each one as you go reading them.
If that is what you're trying to achieve, then your idea of using '~' to mark the read positions isn't going to work. What I meant before is that, in C, 126 and the character '~' are the exact same thing. Thus, you won't be able to differentiate those positions in which you have written a '~' character and those ones in which a random 126 is stored by chance.
If you happen to be storing positive integers in your array, then use -1 instead of '~'. That will tell you if the position has been read or not.
If you are storing any possible random integer, then there is nothing you can store in that array that you can use to mark a position as read. In this case a possible solution is to define your array like this:
typedef struct {
int value;
char marked;
} Position;
Position board[ROWS][COLS];
Thus, for each position you can store a value like this:
board[row][col].value = 23123;
And you can mark it as read like this:
board[row][col].marked = 'y';
Just, don't forget to mark the positions as not read (board[row][col].marked = 'n';) while you fill the matrix with random integers.

Resources