Why does the array keep reverting to 0 - arrays

I have a 1 dimensional array in which ive initialized as 0 but for some reason when i go inside a loop and try to increase its contents by one the value at position 0 keeps reverting to 0 even after i increase it by 1.
#include <stdio.h>
#include <stdlib.h>
#define TOTAL_V 3
#define NUM_CANDIDATES 7
int hex_age(unsigned short hex){
unsigned short age = hex >> 9;
if (age >18 && age <101)
return age;
else return 0;
}
int hex_gender(unsigned short hex){
unsigned short gender = hex >> 7 & 3;
return gender;
}
int hex_vote(unsigned short hex){
unsigned short vote, tmp = hex & 0x7f , count = 0;
if (tmp == 0)
return 7;
for (int i = 0 ; i<7; i++){
if (tmp & 1 == 1){
count++;
vote = i;
}
tmp = tmp >> 1;
}
if (count > 1)
return 7;
return vote;
}
int main() {
int s_votes = 0, f_votes = 0, v_count[NUM_CANDIDATES] = {0};
unsigned short **v_info, hex_v_info , age , gender , vote;
FILE *fp;
fp = fopen("data1.dat" , "r");
if (fp == NULL){
fprintf(stderr ,"apotuxe o anoigmos tou arxeiou");
exit(-1);
}
if (feof(fp)){
fprintf(stderr, "to arxeio einai adeio");
exit(-1);
}
while (fscanf(fp ,"%x", &hex_v_info) != EOF){
age = hex_age(hex_v_info);
if(age == 0)
f_votes++;
else {
gender = hex_gender(hex_v_info);
if (gender == 0)
f_votes++;
else{
vote = hex_vote(hex_v_info);
if (vote == 7)
f_votes++;
else{
if (s_votes == 0){
v_info = malloc(sizeof(int *));
v_info[s_votes] =malloc(sizeof(int)* TOTAL_V);
}
else{
v_info = realloc(v_info , sizeof(int *)*(s_votes+1));
v_info[s_votes] = malloc(sizeof(int)*TOTAL_V);
}
v_info[s_votes][0] = age;
v_info[s_votes][1] = gender;
v_info[s_votes][2] = vote;
v_count[vote]++;
s_votes++;
}
}
}
}
fclose(fp);
for (int i = 0; i<s_votes; i++)
free(v_info);
return 0;
}
and for some reason when i use calloc to create the array it doesnt have that problem. Does anyone know why that happens

You declare unsigned short hex_v_info (2 bytes on my system), then read data from with fscanf(fp ,"%x", &hex_v_info) where the format string %x expect the address of an int (4 bytes on my system). This will certainly overwrite data unexpectedly.
unsigned short **v_info but you store an array of int [s_votes]. If your pointers are not uniform this will be a problem.
realloc(NULL, 1) is well defined so just use instead of malloc() of the first element. You need to assign the result of realloc()` to e temporary variable, however, to be able handle NULL. Otherwise you lose data & leak memory.
free(v_info); results in a double free if s_votes > 1, and you still leak the memory you allocate at v_info[i].
#include <stdio.h>
#include <stdlib.h>
#define TOTAL_V 3
#define NUM_CANDIDATES 7
// 0x1111 1110 0000 0000
int hex_age(unsigned short hex){
unsigned short age = hex >> 9;
if (age >18 && age < 101)
return age;
return 0;
}
// 0x0000 0001 1000 0000
int hex_gender(unsigned short hex){
unsigned short gender = hex >> 7 & 3; // bit 7 and 6
return gender;
}
// 0x0000 0000 0111 1111
int hex_vote(unsigned short hex){
unsigned short vote, tmp = hex & 0x7f , count = 0; // bit 11 through 0
if (tmp == 0)
return 7;
for (int i = 0 ; i<7; i++){
if ((tmp & 1) == 1){
count++;
vote = i;
}
tmp = tmp >> 1;
}
if (count > 1)
return 7;
return vote;
}
int main() {
int s_votes = 0, f_votes = 0, v_count[NUM_CANDIDATES] = {0};
unsigned short hex_v_info;
int **v_info = NULL;
FILE *fp = fopen("data1.dat" , "r");
if (!fp){
fprintf(stderr ,"apotuxe o anoigmos tou arxeiou");
exit(-1);
}
for(;;) {
int rv = fscanf(fp ,"%hx", &hex_v_info);
if(rv == EOF) break;
if(rv != 1) {
printf("err\n");
return 1;
}
unsigned short age = hex_age(hex_v_info);
if(!age) {
f_votes++;
continue;
}
unsigned short gender = hex_gender(hex_v_info);
if (!gender) {
f_votes++;
continue;
}
unsigned short vote = hex_vote(hex_v_info);
if (vote == 7) {
f_votes++;
continue;
}
int **tmp = realloc(v_info, sizeof *tmp * (s_votes + 1));
if(!tmp) {
// handle error: free v_info[i] and v_info?
return 1;
}
v_info = tmp;
v_info[s_votes] = malloc(sizeof **v_info * TOTAL_V);
v_info[s_votes][0] = age;
v_info[s_votes][1] = gender;
v_info[s_votes][2] = vote;
v_count[vote]++;
s_votes++;
}
fclose(fp);
printf("f_votes: %d\n", f_votes);
for(size_t i = 0; i < s_votes; i++) {
printf("%zu: %d %d %d\n",
i,
v_info[i][0],
v_info[i][1],
v_info[i][2]
);
}
for (int i = 0; i< s_votes; i++)
free(v_info[i]);
free(v_info);
return 0;
}
and with input file file:
a081
a082
it appears to process the info data correctly:
f_votes: 0
0: 80 1 0
1: 80 1 1

Related

C struct value resetting to NULL

I'm working on a school project where I have to store PPM data into structs. I have an issue with an array of strings inside the struct.
typedef struct {
char **comments;
} PPM;
I have 3 functions that uses this struct.
PPM *getPPM() is used to get all the PPM data from file and store it into the struct
void showPPM(PPM * img) to show the image data in terminal
PPM *encode(PPM *img) which is used to change the LSB of the RGB values of the image
The problem is that getPPM works as intended and gets all the comments into the comments array in getPPM. It displays them fine if I do it like this:
PPM *p = getPPM(fin);
showPPM(p);
But if I try to call it with the encode function like this:
PPM *p = getPPM(fin);
PPM *g = encode(p);
showPPM(g);
the debugger shows that as soon as the program enters the encode function, the comments value resets to NULL even though this function doesn't even touch comments. Is the way I am calling these functions wrong or is there something wrong with my code? I will try to provide the minimal code if the problem is not the way the functions are being called, as the code is big and everything is dependent on one another.
I'm very new to C language. I tried understanding the problem for hours but can't find a solution anywhere. Any help would be greatly appreciated.
EDIT: This is as small as I could make it.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//Structures
typedef struct {
int r, g, b;
} pixels;
typedef struct {
char format[3];
char **comments;
int width, height, maxColors, commentCounter;
pixels **pixelValues;
} PPM;
// Functions declarations
PPM *getPPM(FILE * f);
PPM *encode(PPM *im, char *message, unsigned int mSize, unsigned int secret);
void showPPM(PPM * im);
static int *decimalToBinary(const char *message, unsigned int length);
// Main method
int main(int argc, char **argv) {
FILE * fin = fopen(argv[1], "r");
if(fin == NULL) {
perror("Cannot open file");
exit(1);
}
PPM *p = getPPM(fin);
PPM *g = encode(p, "test", 5, 1);
showPPM(g);
return 0;
}
/*
* This function is used to get the image data from a file and populate
* our strutures with it.
*/
PPM *getPPM(FILE * f) {
// Allocate the memory for structure and check if it was successful
PPM *pic = (PPM *) malloc(sizeof(PPM));
if(!pic) {
perror("Unable to allocate memory for structure");
exit(1);
}
char line[100]; // Expecting no more than 100 characters per line.
pic->commentCounter = 0; // This is the counter to keep size if there are more than one comments
int pixelsCounter = 0; // Counter for pixels' array
pic->comments = malloc(sizeof(char *));
pic->pixelValues = malloc(sizeof(PPM));
int lineCounter = 0;
if((pic->comments) == NULL) {
perror("Unable to allocate memory for pixels");
exit(1);
}
while(fgets(line, sizeof(line), f)) {
// Reference: https://stackoverflow.com/questions/2693776/removing-trailing-newline-character-from-fgets-input
size_t length = strlen(line);
if(length > 0 && line[length-1] == '\n') {
line[--length] = '\0';
}
// Assigning the file format
if(line[0] == 'P') {
pic->format[0] = line[0];
pic->format[1] = line[1];
pic->format[2] = '\0';
}
//Populate comments into struct PPM
if(line[0] == '#') {
// Reallocate/allocate the array size each time a new line of comment is found
if(pic->commentCounter != 0) {
pic->comments = realloc(pic->comments, (pic->commentCounter+1) * sizeof(char *));
}
// Allocate the memory for the string
pic->comments[pic->commentCounter] = malloc(100 * sizeof(char));
// Write the at commentCounter position of the array; character by character
int i = 0;
while(line[i] != '\0') {
pic->comments[pic->commentCounter][i] = line[i];
i++;
}
pic->comments[pic->commentCounter][i] = '\0';
pic->commentCounter++;
}
/*
* Loading the max color property of the file which is gonna be 3 letters (Usually 255)
* and checking if we previously got maxColors in our construct or not. If we didn't
* then we load this value into the consturct and the condition will never validate
* throughout the iterations
*/
if(strlen(line) == 3 && pic->maxColors == 0 && line[0] != '#') {
pic->maxColors = atoi(line);
continue;
}
/*
* Check if the length of string > 3, which means it is going to be a
* number, potentially RGB value or a comment. But since width & height
* comes before RGB values, our condition will fail once we have found
* the width/height for the next iteration. That's why this condition
* only checks if it is a comment or a numbered value of length > 3
*/
if((strlen(line) > 3) && (pic->width == 0) && (line[0] != '#')) {
char *width = strtok(line, " ");
char *height = strtok(NULL, " ");
pic->width = atoi(width);
pic->height = atoi(height);
continue;
}
/*
* If the width/height and maxColors have been found, that means every
* other line is either going to be the RGB values or a comment.
*/
if((pic->width != 0) && (pic->maxColors != 0) && (line[0] != '#')) {
// length(line) > 3 means all the RGB values are in same line
if(strlen(line) > 3) {
char *val1 = strtok(line, " ");
char *val2 = strtok(NULL, " ");
char *val3 = strtok(NULL, " ");
// pixelsCounter = 0 means it's the first element.
if(pixelsCounter != 0) {
// Reallocate memory each time a new R G B value line is found
pic->pixelValues = realloc(pic->pixelValues, (pixelsCounter + 1) * sizeof(PPM));
}
pic->pixelValues[pixelsCounter] = malloc(12 * sizeof(pixels));
pic->pixelValues[pixelsCounter]->r = atoi(val1);
pic->pixelValues[pixelsCounter]->g = atoi(val2);
pic->pixelValues[pixelsCounter]->b = atoi(val3);
pixelsCounter++;
} else if(strlen(line) <= 3) {
/*
* If each individual RGB values are in a separete lines, we will
* use a switch case and a line counter to keep track of where the
* values were inserted and when to know when we got RGB values for
* one pixel
*/
if(pixelsCounter != 0 && lineCounter == 0) {
// Reallocate memory each time a new R G B value line is found
pic->pixelValues = realloc(pic->pixelValues, (pixelsCounter + 1) * sizeof(PPM));
}
switch(lineCounter) {
case 0 :
pic->pixelValues[pixelsCounter] = malloc(12 * sizeof(pixels));
pic->pixelValues[pixelsCounter]->r = atoi(line);
lineCounter++;
continue;
case 1 :
pic->pixelValues[pixelsCounter]->g = atoi(line);
lineCounter++;
continue;
case 2 :
pic->pixelValues[pixelsCounter]->b = atoi(line);
lineCounter=0;
pixelsCounter++;
continue;
default:
continue;
}
}
}
}
pic->pixelValues[pixelsCounter] = NULL;
fclose(f);
return pic;
}
void showPPM(PPM * im) {
printf("%s\n",im->format);
int k = 0;
while(k < im->commentCounter) {
printf("%s\n", im->comments[k]);
k++;
}
printf("%d %d\n", im->width, im->height);
printf("%d\n",im->maxColors);
int j = 0;
while(im->pixelValues[j] != NULL) {
printf("%d %d %d\n", im->pixelValues[j]->r, im->pixelValues[j]->g, im->pixelValues[j]->b);
j++;
}
}
PPM *encode(PPM *im, char *message, unsigned int mSize, unsigned int secret) {
int *binaryMessage = decimalToBinary(message, mSize);
int i, j = 0, lineCounter = 0;
for(i = 0; i < 40; i++) {
switch(lineCounter) {
case 0 :
im->pixelValues[j]->r |= binaryMessage[i] << 0;
lineCounter++;
continue;
case 1 :
im->pixelValues[j]->g |= binaryMessage[i] << 0;
lineCounter++;
continue;
case 2 :
im->pixelValues[j]->b |= binaryMessage[i] << 0;
lineCounter=0;
j++;
continue;
default:
continue;
}
}
return im;
}
/*
* Converts a string into binary to be used in encode function. It
* first converts each letter of the string into ascii code. Then
* finds and stores each of the 8 bits of that int (ascii code of
* the letter) sequentially in an array.
*/
static int *decimalToBinary(const char *message, unsigned int length) {
/*
* malloc is used here instead of [] notation to allocate memory,
* because defining the variable with [] will make its scope
* limited to this function only. Since we want to access this
* array later on, we use malloc to assign space in the memory
* for it so we can access it using a pointer later on.
*/
int k=0, i, j;
unsigned int c;
unsigned int *binary = malloc(8 * length);
for(i = 0; i < length; i++) {
c = message[i];
for(j = 7; j >= 0; j--,k++) {
/*
* We check here if the jth bit of the number is 1 or 0
* using the bit operator &. If it is 1, it will return
* 1 because 1 & 1 will be true. Otherwise 0.
*/
if((c >> j) & 1)
binary[k] = 1;
else
binary[k] = 0;
}
}
return binary;
}
PPM file:
P3
# CREATOR: GIMP PNM Filter Version 1.1
# Amazing comment 2
# Yet another amazing comment
400 530
255
0 0 0
0 0 0
0 0 0
0 0 0
0 0 0
0 0 0
0 0 0
0 0 0
0 0 0
0 0 0
0 0 0
0 0 0
0 0 0
0 0 0
0 0 0
0 0 0
in decimalToBinar
unsigned int *binary = malloc(8 * length);
must be
unsigned int *binary = malloc(8 * length * sizeof(int));
new code is :
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//Structures
typedef struct {
int r, g, b;
} pixels;
typedef struct {
char format[3];
char **comments;
int width, height, maxColors, commentCounter;
pixels **pixelValues;
} PPM;
// Functions declarations
PPM *getPPM(FILE * f);
PPM *encode(PPM *im, char *message, unsigned int mSize, unsigned int secret);
void showPPM(PPM * im);
static int *decimalToBinary(const char *message, unsigned int length);
// Main method
int main(int argc, char **argv) {
FILE * fin = fopen(argv[1], "r");
if(fin == NULL) {
perror("Cannot open file");
exit(1);
}
PPM *p = getPPM(fin);
PPM *g = encode(p, "test", 5, 1);
showPPM(g);
free(p->comments);
free(p);
return 0;
}
/*
* This function is used to get the image data from a file and populate
* our strutures with it.
*/
PPM *getPPM(FILE * f) {
// Allocate the memory for structure and check if it was successful
PPM *pic = (PPM *) malloc(sizeof(PPM));
if(!pic) {
perror("Unable to allocate memory for structure");
exit(1);
}
char line[100]; // Expecting no more than 100 characters per line.
pic->commentCounter = 0; // This is the counter to keep size if there are more than one comments
int pixelsCounter = 0; // Counter for pixels' array
pic->comments = malloc(sizeof(char *));
pic->pixelValues = malloc(sizeof(PPM));
int lineCounter = 0;
if((pic->comments) == NULL) {
perror("Unable to allocate memory for pixels");
exit(1);
}
pic->width = 0;
pic->height = 0;
pic->maxColors = 0;
while(fgets(line, sizeof(line), f)) {
// Reference: https://stackoverflow.com/questions/2693776/removing-trailing-newline-character-from-fgets-input
size_t length = strlen(line);
if(length > 0 && line[length-1] == '\n') {
line[--length] = '\0';
}
// Assigning the file format
if(line[0] == 'P') {
pic->format[0] = line[0];
pic->format[1] = line[1];
pic->format[2] = '\0';
}
//Populate comments into struct PPM
if(line[0] == '#') {
// Reallocate/allocate the array size each time a new line of comment is found
if(pic->commentCounter != 0) {
pic->comments = realloc(pic->comments, (pic->commentCounter+1) * sizeof(char *));
}
// Allocate the memory for the string
pic->comments[pic->commentCounter] = malloc(100 * sizeof(char));
// Write the at commentCounter position of the array; character by character
int i = 0;
while(line[i] != '\0') {
pic->comments[pic->commentCounter][i] = line[i];
i++;
}
pic->comments[pic->commentCounter][i] = '\0';
pic->commentCounter++;
}
/*
* Loading the max color property of the file which is gonna be 3 letters (Usually 255)
* and checking if we previously got maxColors in our construct or not. If we didn't
* then we load this value into the consturct and the condition will never validate
* throughout the iterations
*/
if(strlen(line) == 3 && pic->maxColors == 0 && line[0] != '#') {
pic->maxColors = atoi(line);
continue;
}
/*
* Check if the length of string > 3, which means it is going to be a
* number, potentially RGB value or a comment. But since width & height
* comes before RGB values, our condition will fail once we have found
* the width/height for the next iteration. That's why this condition
* only checks if it is a comment or a numbered value of length > 3
*/
if((strlen(line) > 3) && (pic->width == 0) && (line[0] != '#')) {
char *width = strtok(line, " ");
char *height = strtok(NULL, " ");
pic->width = atoi(width);
pic->height = atoi(height);
continue;
}
/*
* If the width/height and maxColors have been found, that means every
* other line is either going to be the RGB values or a comment.
*/
if((pic->width != 0) && (pic->maxColors != 0) && (line[0] != '#')) {
// length(line) > 3 means all the RGB values are in same line
if(strlen(line) > 3) {
char *val1 = strtok(line, " ");
char *val2 = strtok(NULL, " ");
char *val3 = strtok(NULL, " ");
// pixelsCounter = 0 means it's the first element.
if(pixelsCounter != 0) {
// Reallocate memory each time a new R G B value line is found
pic->pixelValues = realloc(pic->pixelValues, (pixelsCounter + 1) * sizeof(PPM));
}
pic->pixelValues[pixelsCounter] = malloc(12 * sizeof(pixels));
pic->pixelValues[pixelsCounter]->r = atoi(val1);
pic->pixelValues[pixelsCounter]->g = atoi(val2);
pic->pixelValues[pixelsCounter]->b = atoi(val3);
pixelsCounter++;
} else if(strlen(line) <= 3) {
/*
* If each individual RGB values are in a separete lines, we will
* use a switch case and a line counter to keep track of where the
* values were inserted and when to know when we got RGB values for
* one pixel
*/
if(pixelsCounter != 0 && lineCounter == 0) {
// Reallocate memory each time a new R G B value line is found
pic->pixelValues = realloc(pic->pixelValues, (pixelsCounter + 1) * sizeof(PPM));
}
switch(lineCounter) {
case 0 :
pic->pixelValues[pixelsCounter] = malloc(12 * sizeof(pixels));
pic->pixelValues[pixelsCounter]->r = atoi(line);
lineCounter++;
continue;
case 1 :
pic->pixelValues[pixelsCounter]->g = atoi(line);
lineCounter++;
continue;
case 2 :
pic->pixelValues[pixelsCounter]->b = atoi(line);
lineCounter=0;
pixelsCounter++;
continue;
default:
continue;
}
}
}
}
pic->pixelValues[pixelsCounter] = NULL;
fclose(f);
return pic;
}
void showPPM(PPM * im) {
printf("%s\n",im->format);
int k = 0;
while(k < im->commentCounter) {
printf("%s\n", im->comments[k]);
k++;
}
printf("%d %d\n", im->width, im->height);
printf("%d\n",im->maxColors);
int j = 0;
while(im->pixelValues[j] != NULL) {
printf("%d %d %d\n", im->pixelValues[j]->r, im->pixelValues[j]->g, im->pixelValues[j]->b);
j++;
}
}
PPM *encode(PPM *im, char *message, unsigned int mSize, unsigned int secret) {
int *binaryMessage = decimalToBinary(message, mSize);
int i, j = 0, lineCounter = 0;
for(i = 0; i < 40; i++) {
switch(lineCounter) {
case 0 :
im->pixelValues[j]->r |= binaryMessage[i] << 0;
lineCounter++;
continue;
case 1 :
im->pixelValues[j]->g |= binaryMessage[i] << 0;
lineCounter++;
continue;
case 2 :
im->pixelValues[j]->b |= binaryMessage[i] << 0;
lineCounter=0;
j++;
continue;
default:
continue;
}
}
free(binaryMessage);
return im;
}
/*
* Converts a string into binary to be used in encode function. It
* first converts each letter of the string into ascii code. Then
* finds and stores each of the 8 bits of that int (ascii code of
* the letter) sequentially in an array.
*/
static int *decimalToBinary(const char *message, unsigned int length) {
/*
* malloc is used here instead of [] notation to allocate memory,
* because defining the variable with [] will make its scope
* limited to this function only. Since we want to access this
* array later on, we use malloc to assign space in the memory
* for it so we can access it using a pointer later on.
*/
int k = 0, i, j;
unsigned int c;
unsigned int *binary = malloc(8 * length * sizeof(int));
for(i = 0; i < length; i++) {
c = message[i];
for(j = 7; j >= 0; j--,k++) {
/*
* We check here if the jth bit of the number is 1 or 0
* using the bit operator &. If it is 1, it will return
* 1 because 1 & 1 will be true. Otherwise 0.
*/
if((c >> j) & 1)
binary[k] = 1;
else
binary[k] = 0;
}
}
return binary;
}

How to check the condition of individual bytes stored in an address?

#include <stdio.h>
int main(){
int x = 2271560481; // 0x87654321
for (size_t i = 0; i < sizeof(x); ++i) {
unsigned char byte = *((unsigned char *)&x + i);
printf("Byte %d = %u\n", i, (unsigned)byte);
}
return 0;
}
For example I have this code right here displaying an output of :
Byte 0 = 33
Byte 1 = 67
Byte 2 = 101
Byte 3 = 135
How do I check the condition to see if the value is stored in the address?
Your code is loading one byte at a time into byte , its not a pointer so you cannot index off it. Do
unsigned char *bytePtr = ((unsigned char *)&x);
for (size_t i = 0; i < sizeof(x); ++i) {
printf("Byte %d = %u\n", i, bytePtr[i]);
}
now you can do your test function using bytePtr
Your byte will hold last value. If you want to store all the values you need array.
Consider below example.
#include <stdio.h>
int main(){
int x = 2271560481; // 0x87654321
size_t i =0;
unsigned char byte[sizeof x];
for (i = 0; i < sizeof(x); ++i) {
byte[i] = *((unsigned char *)&x + i);
printf("Byte %d = %u\n", i, (unsigned)byte[i]);
}
if (byte[0] == 33 && byte[1] == 67 && byte[2] == 101 && byte[3] == 135)
{
return 1;
}
return 0;
}

How do I convert from unsigned char to long

I have a problem to convert from unsigned char into long.
The mission: I have 25 in (unsigned char) ptr->studentArr[i].subjectStatus when i = 0, I go into the function unsigned char fromDecToBinary(unsigned char tmpSubjectStatus), and I want in that function to get unsigned long 11001 into variable ret and then fprintf it into output.txt file.
Expectation: to fprintf into the file 11001 when i = 0, problem: it prints 25 instead(if I use fromDecToBinary function, it prints 0).
Please, just look at the 2 functions: outPutStudents and fromDecToBinary, other functions work properly, and those other functions just get the information and store the info. into structures which are then used to print the details into output.txt, most of them work, except the binary thingy.
input.txt file:
Nir 32251 99.80 11001
Ely 12347 77.89 01111
Moshe 45321 50.34 11111
Avi 31456 49.78 00011
*NOTE: this is the output without using the function fromDecToBinary
output.txt file:
Student 1: Nir 32251 99.80 25
Student 2: Ely 12347 77.89 15
Student 3: Moshe 45321 50.34 31
Student 4: Avi 31456 49.78 3
Code:
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
typedef struct Student{
char* studentName; //Dyn. alloc. of stud. name
long id; // ID Number
float mark; // mark
unsigned char subjectStatus;
}Student;
typedef struct University{
Student* studentArr; // Dync. Alloc(Realloc) of students
int numOfStudents; //num of students
}University;
void getStudents(University *ptr);
unsigned char stringToBinary(unsigned char tmpSubjectStatus[]);
void outPutStudents(University *ptr);
unsigned char fromDecToBinary(University *ptr);
void main()
{
printf("Please enter details of student: (a)");
University uni;
getStudents(&uni); //Send address of structure University, because we want to change it not make a local copy of it
outPutStudents(&uni);
getch();
}
void getStudents(University *ptr)
{
FILE *op;
char tmpStudentName[20];
long tmpId;
float tmpMark;
char tmpSubjectStatus[6];
ptr->numOfStudents = 0;
if ((op = fopen("input.txt", "r")) == NULL)
{
printf("Failed to open file.");
}
ptr->studentArr = (Student*)malloc(sizeof(Student));
if (ptr->studentArr == NULL){
printf("Error: memory was not allocated.");
exit(1);
}
while (fscanf(op, "%s %ld %f %s", tmpStudentName, &tmpId, &tmpMark, tmpSubjectStatus) == 4)
{
ptr->numOfStudents++;
ptr->studentArr = (Student*)realloc(ptr->studentArr, sizeof(Student) * ptr->numOfStudents); /*Additional code for Realloc fails - we didn't study!*/
ptr->studentArr[ptr->numOfStudents - 1].studentName = (char*)malloc(sizeof(char)* strlen(tmpStudentName));
if (!(ptr->studentArr[ptr->numOfStudents - 1].studentName)) //if we failed to allocate memory for studentName
{
while (ptr->numOfStudents > 0)
{
free(ptr->studentArr[ptr->numOfStudents - 1].studentName); //free student name
ptr->numOfStudents--; // decrease numOfStudents by one
}
free(ptr->studentArr); //if all student names are free, we need to free the array
printf("Student name was not allocated.");
exit(1);
}
strcpy(ptr->studentArr[ptr->numOfStudents - 1].studentName, tmpStudentName);
ptr->studentArr[ptr->numOfStudents - 1].id = tmpId;
ptr->studentArr[ptr->numOfStudents - 1].mark = tmpMark;
ptr->studentArr[ptr->numOfStudents - 1].subjectStatus = stringToBinary(tmpSubjectStatus); //atoi: from "11001"(string) to 11001(int),then casting to unsigned char
}
fclose(op);
}
void outPutStudents(University *ptr)
{
int i;
FILE *fp;
unsigned char tmpSubjectStatus;
long val;
if ((fp = fopen("output.txt", "w")) == NULL)
{
printf("Couldn't open output file.");
exit(1);
}
for (i = 0; ptr->numOfStudents != i; i++){
tmpSubjectStatus = ptr->studentArr[i].subjectStatus;
val = fromDecToBinary(tmpSubjectStatus);
fprintf(fp, "Student %d: %s %ld %.2f %ld \n", i + 1, ptr->studentArr[i].studentName, ptr->studentArr[i].id, ptr->studentArr[i].mark, tmpSubjectStatus);
}
fclose(fp);
}
unsigned char stringToBinary(char tmpSubjectStatus[])
{
unsigned char tmpBinaryCh = 0;
int i;
for (i = 0; i < 5; i++){
if (tmpSubjectStatus[i] == '1') tmpBinaryCh += 1 << (4 - i);
}
return tmpBinaryCh;
}
unsigned char fromDecToBinary(unsigned char tmpSubjectStatus)
{
int i;
long ret;
char arrBinary[6];
for (i = 0; i < 5; i++){
arrBinary[4 - i] = tmpSubjectStatus % 2;
tmpSubjectStatus /= 2;
}
arrBinary[5] = '/0';
ret = strtol(arrBinary, NULL, 10);
return ret;
}
You have several errors in the fromDecToBinary function:
Replace the '/0' with '\0'.
Store '0' + tmpSubjectStatus % 2 in the array.
Add proper error handling to the strtol call.
Change the return type to long.
If you want to print some binary using numbers use this.
#include <stdio.h>
#include <stdlib.h>
void print_bin(uint64_t num, size_t bytes) {
int i = 0;
for(i = bytes * 8; i > 0; i--) {
(i % 8 == 0) ? printf("|") : 1;
(num & 1) ? printf("1") : printf("0");
num >>= 1;
}
printf("\n");
}
int main(void) {
int arg = atoi("25");
print_bin(arg, 1);
return 0;
}
It also prints a vertical bar every 8 bits to make the bytes easier to read but you can just remove that.
If you want to specify how many bytes you want use this
#include <stdio.h>
#include <stdlib.h>
void print_bin(uint64_t num, size_t bytes) {
int i = 0;
for(i = bytes * 8; i > 0; i--) {
(i % 8 == 0) ? printf("|") : 1;
(num & 1) ? printf("1") : printf("0");
num >>= 1;
}
printf("\n");
}
int main(void) {
print_bin(16000, 3);
return 0;
}
#include <stdio.h>
int main()
{
unsigned char tmpSubjectStatus=25;
long quotient = tmpSubjectStatus;
long remainder;
long binary=0;
long multiplier=1;
while(quotient!=0){
remainder=quotient % 2;
binary=binary+(remainder*multiplier);
multiplier=multiplier*10;
quotient = quotient / 2;
}
printf("%ld",binary);
return 0;
}
Try this.
In the function it will be like this
long fromDecToBinary(unsigned char tmpSubjectStatus)
{
long quotient = tmpSubjectStatus;
long remainder;
long binary=0;
long multiplier=1;
while(quotient!=0){
remainder=quotient % 2;
binary=binary+(remainder*multiplier);
multiplier=multiplier*10;
quotient = quotient / 2;
}
return binary;
}
In here return type is changed to long.

Add one to a binary representation with padding of 0

I have a character representation of a binary number, and I wish to perform arithmetic, plus 1, on it. I want to keep the padding of 0.
Right now I have :
int value = fromBinary(binaryCharArray);
value++;
int fromBinary(char *s) {
return (int)strtol(s, NULL, 2);
}
I need to transform the value++ to binary representation and if I have 0 to pad I need to pad it.
0110 -> 6
6++ -> 7
7 -> 0111 <- that's what I should get from transforming it back in a character representation
In my problem it will never go above 15.
This is what I have so far
char *toBinary(int value)
{
char *binaryRep = malloc(4 * sizeof(char));
itoa(value, binaryRep, 2);
if (strlen(binaryRep) < 4)
{
int index = 0;
while (binaryRep[index] != '1')
{
binaryRep[index] = '0';
index++;
}
}
return binaryRep;
}
Try this
#include <stdio.h>
int main(void)
{
unsigned int x;
char binary[5]; /* You need 5 bytes for a 4 character string */
x = 6;
for (size_t n = 0 ; n < 4 ; ++n)
{
/* shift right `n' bits and check that the bit is set */
binary[3 - n] = (((x >> n) & 1) == 1) ? '1' : '0';
}
/* nul terminate `binary' so it's a valid c string */
binary[4] = '\0';
fprintf(stderr, "%s\n", binary);
return 0;
}
char *binaryRep = malloc(4* sizeof(char));
binaryRep[4] = '\0';
for (int i = (sizeof(int)) - 1; i >= 0; i--) {
binaryRep[i] = (value & (1 << i)) ? '1' : '0';
}
return binaryRep;
This does what I need.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
/*___________________________________________________________
*/
int from_bin(char *buff){
int d=0;
while(*buff){
d<<=1;
d+=(*buff=='1')?1:0;
buff++;
}
return d;
}
/*___________________________________________________________
*/
int to_bin(int d,char *buff,int len){
int ret=0;
if(len<4)return -1;
if(d & ~0xf){
ret=to_bin(d>>4,buff,len-4);
if(ret==-1) return -1;
buff+=ret;
}
buff[4]=0;
buff[3]=((d & 0x1)?'1':'0');
d>>=1;
buff[2]=((d & 0x1)?'1':'0');
d>>=1;
buff[1]=((d & 0x1)?'1':'0');
d>>=1;
buff[0]=((d & 0x1)?'1':'0');
d>>=1;
return ret+4;
}
/*___________________________________________________________
*/
int main(void){
int n;
char buff[33]="0011";
n=from_bin(buff);
n+=1;
if(to_bin(n,buff,8)==-1){
printf("ERROR: buffer too small\n");
}else{
printf("bin of %d= '%s'\n",n,buff);
}
return 0;
}

Bit shifting results in negative number

I'm working on an assignment that deals with compression and decompression. More specifically, a variation of run-length encoding (9-bit blocks). The issue I am having deals with the sign of the "type" bit. I am able to acquire the desired bit, however, in the cases that the bit should be a 1, my printf returns -1. This would lead me to believe that I am not doing something correct in my bit shifting, but I am unaware as to what that might be.
void bitShift(char * mostFreq, unsigned char * byteBuf, int byteCount) {
char type;
int typels = 0;
int typers = 7;
int i = 0;
for(i = 0; i < byteCount - 1; i++) {
type = byteBuf[i];
printf("type before = %d\t", (unsigned int)type);
type = type << typels;
type = type >> typers;
typels++;
printf("type after = %d\n", (unsigned int)type);
}/*End for i*/
for(i = 0; i < byteCount; i++)
byteBuf[i] = 0;
}/*End bitShift*/
void decompressFile(char * mostFreq) {
unsigned char byteBuf[9] = { 0 };
int num, byteCount, i;
num = 0; byteCount = 0; i = 0;
unsigned char buf;
while((num = read(0,&buf, 1)) > 0) {
byteBuf[byteCount] = buf;
byteCount++;
if(byteCount == 9) {/*Flush bytes if buffer is full*/
bitShift(mostFreq, byteBuf, byteCount);
for(i = 0; i < 9; i++) {
byteBuf[i] = 0;
}/*End for i*/
byteCount = 0;
}/*End if*/
}/*End while*/
if(num == 0) {/*If EOF*/
if(byteCount != 0) {/*Bits have not been flushed*/
bitShift(mostFreq, byteBuf, byteCount);
}/*End if*/
} else if(num < 0) {
perror("Read error");
exit(1);
}/*End else if*/
}/*End decompressFile*/
You problem is that you declared type as a plain char that, in your system seems to be a signed type.
So when you have for example 0x80, it is actually -128, a negative number, and when it is shifted to the right the sign bit is extended: 1 bit: 0xC0 (-64), 2 bits: 0xE0 (-32), ... 7 bits: 0xFF (-1).
Change it to unsigned char and done!

Resources