This code is meant to read the value from an image file into an array (I know the size is 16*8).
When I dynamically create the img array so I can have any size image it crashes when run, when I manually make it the correct size (char img[16][8];) it works.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main()
{
FILE *fin;
fin= fopen ("test.pgm","rb");
if (fin == NULL)
{
printf ("ERROR");
fclose(fin);
}
int i=0,j=0,u=16,v=8,d;
char test[20];
char k;
char c[10];
while((k=fgetc(fin))!='\n')
{
test[j]=k;
j=j+1;
}
char **img = (char**) calloc(u,sizeof(char*));
for ( i = 0; i < u; i++ )
{
img[i] = (char*) calloc(v,sizeof(char));
}
fread(img,1,(u*v),fin);
for (i=0; i<u; i++)
{
for (j=0; j<v; j++)
{
printf("%d ",img[i][j]);
}
printf("\n");
}
fclose(fin);
}
Since you are dynamically allocating 16 separate 8 byte arrays, you will then need to compute 16 individual reads into each of those arrays. (I have removed the unnecessary, and potentially bug prone, casts to calloc()).
char **img = calloc(u,sizeof(char*));
for ( i = 0; i < u; i++ )
{
img[i] = calloc(v,sizeof(char));
fread(img[i],1,v,fin);
}
/*fread(img,1,(u*v),fin);*/
The single fread() call you had works for char img[16][8], because in that case, img consists of contiguous memory sized at 16 * 8 bytes. But, that call will not work for the way you have created your dynamically allocated array, since img is now an array of pointers, and so the fread() call you have will overwrite those pointer values with data from the file.
If you want to do a single call to fread(), then you can change your dynamic allocation (and combine with VLA)
char (*img)[v];
img = malloc(u * sizeof(*img));
fread(img,1,(u*v),fin);
This declares img to be a pointer to an array v of char (v was initialized to 8). It then allocates u (ie, 16) many of array v of char in a contiguous allocation for img. Now, img can be used for the single fread() call like you had for char img[16][8], and also preserves the same "2D" addressing of img as well.
The answer by jxh correctly diagnoses the trouble with the original code, which this answer does not (in part because of that). It also demonstrates the power of variable length arrays, VLAs, which were added to C99. It is really neat and should be accepted.
If you are stuck with C89 (perhaps because you work on Windows with MSVC), then you can still do the single read if you allocate the space contiguously. However, if you're also going to use the double index notation, you still need the array of pointers, or you will need to use the notation img[i*v+j] (and a different type for img). This code implements the extra array of pointers, and also includes a variety of other minor bug fixes to the original code (the most important being that it returns after failing to open the file, rather than reporting 'ERROR' and continuing as if nothing had gone wrong, including attempting to fclose() a null pointer, which is good for a crash).
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
const char *filename = "test.pgm";
FILE *fin = fopen(filename, "rb");
if (fin == NULL)
{
fprintf(stderr, "ERROR opening file %s\n", filename);
return(1);
}
int i;
int j = 0;
int u=16;
int v=8;
char test[20];
int k;
while ((k = fgetc(fin)) != '\n')
test[j++] = k;
test[j] = '\0';
printf("test: %s\n", test);
char **img = (char**) calloc(u,sizeof(char*));
char *space = (char *)calloc(u*v, sizeof(char));
for (i = 0; i < u; i++)
img[i] = &space[v*i];
if (fread(img[0], 1, (u*v), fin) != (size_t)(u*v))
{
fprintf(stderr, "Error: short read\n");
return(1);
}
for (i = 0; i < u; i++)
{
for (j = 0; j < v; j++)
printf("%3d ", img[i][j]);
printf("\n");
}
fclose(fin);
free(img[0]);
free(img);
return(0);
}
Note that the loop reading into test is not properly error checked; it could overflow, and it doesn't detect EOF, either.
Input data:
abcdefghij
aaaaaaa
bbbbbbb
ccccccc
ddddddd
eeeeeee
fffffff
ggggggg
hhhhhhh
iiiiiii
jjjjjjj
kkkkkkk
lllllll
mmmmmmm
nnnnnnn
ooooooo
ppppppp
Output data:
test: abcdefghij
97 97 97 97 97 97 97 10
98 98 98 98 98 98 98 10
99 99 99 99 99 99 99 10
100 100 100 100 100 100 100 10
101 101 101 101 101 101 101 10
102 102 102 102 102 102 102 10
103 103 103 103 103 103 103 10
104 104 104 104 104 104 104 10
105 105 105 105 105 105 105 10
106 106 106 106 106 106 106 10
107 107 107 107 107 107 107 10
108 108 108 108 108 108 108 10
109 109 109 109 109 109 109 10
110 110 110 110 110 110 110 10
111 111 111 111 111 111 111 10
112 112 112 112 112 112 112 10
You fread into your array of pointers but they point to various places in memory so that will not work.
In order for it to work set pointers to point to the same block but at different offsets
so instead of
char **img = calloc(u,sizeof(char*));
for ( i = 0; i < u; i++ )
{
img[i] = calloc(v,sizeof(char));
}
do
char **img = calloc(u,sizeof(char*));
char *block = calloc(u*v,sizeof(char);
for ( i = 0; i < u; i++ )
{
img[i] = block + v*i;
}
then
fread(block,1,(u*v),fin);
Related
I have the code below that can produce
[p18d541#csci112 program1]$ ./main 17 < inp17.txt
12 25 110 168
35 64 113 134
91 158 183 217
102 129 130 146
26 116 215 223
0 78 81 162
19 25 204 222
124 138 157 245
137 183 201 249
61 67 106 236
60 71 106 236
63 81 106 240
14 27 111 168
17 27 111 168
26 116 215 220
111 137 202 249
111 137 202 246
from an input of
168.12.110.25
64.113.134.35
217.158.91.183
102.130.129.146
215.116.26.223
81.162.78.0
19.204.25.222
245.124.138.157
137.249.183.201
106.61.236.67
106.71.236.60
106.81.240.63
168.14.111.27
168.17.111.27
215.116.26.220
137.249.111.202
137.246.111.202
so my code scans in the input stores the values in network
and then I need to arrange them by the column from least to greatest starting at the first number and working its way to the right. an example of a the first few would be
0 78 81 162
12 25 110 168
14 27 111 168
.
.
.
111 137 202 246
111 137 202 249
.
.
.
.
//declare libraries
#include <stdio.h>
#include <stdlib.h>
//declare other functions/files to be used in the program
void print_fun(void);
int sort_fun(int arg, unsigned char networks[arg][4]);
void read_fun(void);
//read command line input and store the information
int main(int argc, char** argv){
//declar variable
int arg = 0;
//make argv into an int
arg = atoi(argv[1]);
//assign size to networks
unsigned char networks[arg][4];
//assign input to networks
for (int j =0; j<1; ++j){
if(argc == 1)
{
printf("ERROR ERROR, you messed up\n");
}
else
{
// hold network addresses in a 2-d array, with 4 nsigned char
for(int k = 0; k<arg; k++){
for (int i =0; i<4; i++){
scanf("%hhu.", &networks[k][i]);
//checks to see if scanf was working roperly
// printf(" %hhu",networks[k][i]);
}
//printf("\n");
}}}
sort_fun(arg, networks);
//sort array
//count networks
//print info about the array
return(0);
}
int sort_fun(int arg, unsigned char networks[arg][4]){
//declaring variabes
//sorting by comlumn p
for (int k = 0; k < arg; k++){
for( int i = 0; i < 4; i++){
for (int j = i+1; j<4; ++j){
if (networks[k][i] > networks[k][j]) {
int swap = networks[k][i];
networks[k][i] = networks[k][j];
networks[k][j] = swap;
}
}
}
}
for (int i =0; i<arg; i++){
for (int j =0; j < 4; j++){
printf(" %hhu", networks[i][j]);
}
printf("\n");
}
return(0);
}
I have tried switching around the variables in my for loop and messing with the values, but I cannot seem to figure out how to change my code to work in columns instead of rows.
and by the way each value is stored in a separate array element but they need to stick together like in the input, so when one number moves the whole line moves with it. please let me know what you think. thank you.
I have the code below that can produce
[p18d541#csci112 program1]$ ./main 17 < inp17.txt
12 25 110 168
35 64 113 134
91 158 183 217
102 129 130 146
26 116 215 223
0 78 81 162
19 25 204 222
124 138 157 245
137 183 201 249
61 67 106 236
60 71 106 236
63 81 106 240
14 27 111 168
17 27 111 168
26 116 215 220
111 137 202 249
111 137 202 246
from an input of
168.12.110.25
64.113.134.35
217.158.91.183
102.130.129.146
215.116.26.223
81.162.78.0
19.204.25.222
245.124.138.157
137.249.183.201
106.61.236.67
106.71.236.60
106.81.240.63
168.14.111.27
168.17.111.27
215.116.26.220
137.249.111.202
137.246.111.202
so my code scans in the input stores the values in network
and then I need to arrange them by the column from least to greatest starting at the first number and working its way to the right. an example of a the first few would be
0 78 81 162
12 25 110 168
14 27 111 168
.
.
.
111 137 202 246
111 137 202 249
.
.
.
.
//declare libraries
#include <stdio.h>
#include <stdlib.h>
//declare other functions/files to be used in the program
void print_fun(void);
int sort_fun(int arg, unsigned char networks[arg][4]);
void read_fun(void);
//read command line input and store the information
int main(int argc, char** argv){
//declar variable
int arg = 0;
//make argv into an int
arg = atoi(argv[1]);
//assign size to networks
unsigned char networks[arg][4];
//assign input to networks
for (int j =0; j<1; ++j){
if(argc == 1)
{
printf("ERROR ERROR, you messed up\n");
}
else
{
// hold network addresses in a 2-d array, with 4 nsigned char
for(int k = 0; k<arg; k++){
for (int i =0; i<4; i++){
scanf("%hhu.", &networks[k][i]);
//checks to see if scanf was working roperly
// printf(" %hhu",networks[k][i]);
}
//printf("\n");
}}}
sort_fun(arg, networks);
//sort array
//count networks
//print info about the array
return(0);
}
int sort_fun(int arg, unsigned char networks[arg][4]){
//declaring variabes
//sorting by comlumn p
for (int k = 0; k < arg; k++){
for( int i = 0; i < 4; i++){
for (int j = i+1; j<4; ++j){
if (networks[k][i] > networks[k][j]) {
int swap = networks[k][i];
networks[k][i] = networks[k][j];
networks[k][j] = swap;
}
}
}
}
for (int i =0; i<arg; i++){
for (int j =0; j < 4; j++){
printf(" %hhu", networks[i][j]);
}
printf("\n");
}
return(0);
}
I have tried switching around the variables in my for loop and messing with the values, but I cannot seem to figure out how to change my code to work in columns instead of rows.
and by the way each value is stored in a separate array element but they need to stick together like in the input, so when one number moves the whole line moves with it. please let me know what you think. thank you.
I'm reading a .pgm file (like the lines below) with "fgetc(file)". When getting only the numbers with a loop in which I avoid the spaces in between (it seems it treats each space, no matter how big it is, as a single character), it joints the last number of a line and the first one from the following line (ex, 146 last number and 105 first number, it gives 146105).
113 116 97 124 146
105 100 112 98 88
100 117 98 87 126
131 101 87 137 161
When simply printing the contents of the file, I get a lot of spaces on the change of line in the console, like this:
113 116 97 124 146
105
When printing the contents, each character on a single line, i get this other output:
9
7
//one line
1
2
4
//one line
1
4
6
//change of linne in the file, two lines here!!!!
1
0
5
//one line
1
0
0
Any ideas about how I should treat this part of the file?
Here is my code:
int get_number(int current[4], int n)
{
int final_number, index = 0, max = n;
while (index < max)
{
final_number += current[index] * pow(10, (n-1));
index++;
n --;
}
return final_number;
}
file = fopen("baboon.pgm", "r");
int info = fgetc(file), n;
while (info != EOF)
{
n = 0;
while (info != ' ' || info != ' ' || info != ' ' || info != ' ')
{
printf("%c", info);
int current_number[4];
n++;
}
if (current_number[0] != 0)
{
printf("%d ", get_number(current_number, n));
}
info = fgetc(file);
}
I think that with this piece of the code you can get an idea. If need more, say it. I also leave you here a link to download the image file if you want: https://drive.google.com/file/d/1ZYIU6fcUOnhRND2zph5MUr8545P6U8bX/view?usp=sharing
I have a program that outputs a huge array of integers to stdout, each integer in a line. Ex:
103
104
105
107
I need to write another program that reads in that array and fill up the spaces where the number isn't an increment of 1 of the previous number. The only different between numbers is going to be 2 (105,107), which makes it easier.
This is my code to do that logic:
printf("d",num1);
if ((num2-num1) != 1)
numbetween = num1 + 1;
printf("%d", numbetween);
printf("%d", num2);
else(
printf("%d",num2);
)
So the output of this program will now be:
103
104
105
106
107
My issue is reading the numbers. I know I can do while (scanf("%hd", &num) != EOF) to read all the lines one at a time. But to do the logic that I want, I'm going to need to read two lines at a time and do computation with them, and I don't know how.
You could always just read the first and last numbers from the file, and then print everything in between.
int main( void )
{
// get the first value in the file
int start;
if ( scanf( "%d", &start ) != 1 )
exit( 1 );
// get the last value in the file
int end = start;
while ( scanf( "%d", &end ) == 1 )
;
// print the list of numbers
for ( int i = start; i <= end; i++ )
printf( "%d\n", i );
}
Read first num then add missing if needed when you read next int
#include <stdio.h>
#include <stdlib.h>
int main()
{
int previous = 0;
int num;
scanf("%hd", &previous);
while (scanf("%hd", &num) != EOF) {
for (int i = previous; i < num; i++) {
printf("%d\n" , i);
}
previous = num;
}
printf("%d\n" , previous);
return 0;
}
this input
100
102
103
105
107
110
returns this output
100
101
102
103
104
105
106
107
108
109
110
While you can read the first and last, to fill the range, what you are really doing is finding the min and max and printing all values between them inclusively. Below the names are left first and last, but they represent min and max and will cover your range regardless whether the values are entered in order. Taking that into consideration, another approach insuring you cover the limits of the range of int would be:
#include <stdio.h>
int main (void) {
int num = 0;
int first = (1U << 31) - 1; /* INT_MAX */
int last = (-first - 1); /* INT_MIN */
/* read all values saving only first (min) and last (max) */
while (scanf (" %d", &num) != EOF) {
first = num < first ? num : first;
last = num > last ? num : last;
}
/* print all values first -> last */
for (num = first; num <= last; num++)
printf ("%d\n", num);
return 0;
}
Input
$ cat dat/firstlast.txt
21
25
29
33
37
41
45
49
53
57
61
65
69
73
77
81
85
89
93
97
101
Output
$ ./bin/firstlast < dat/firstlast.txt
21
22
23
24
25
26
27
28
29
<snip>
94
95
96
97
98
99
100
101
Note: you can change the types to conform to your expected range of data.
I have to copy the elements of one array of structure to blank elements of a new array of structures (all dynamically allocated). Every element of the array of structures I have, structure 'a', has only two columns, left_column and right_column. Some of the right column entries of each element of structure a (say, i'th structure element) matches the left column entry of the next (viz., i+1 th) structure element of the same structure a. I am attempting to find such matching entries and I am attempting to copy the entire left and right column of the matching elements one-by-one to a smaller, conserved structure, structure b. The problem is the code is compiling, but it is not getting into the all-important matching part, viz., the if part. It is getting into the while loop.
Kept below are the information and sample data. This code has come to this stage due to 'PlerumCodeExperientia', I thank him. Please suggest how to copy these matching elements.
Thanking you, Dan.
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char* args[])
{
struct a
{
int left_line;
int right_line;
};
struct b
{
int conserved_left;
int conserved_right;
};
FILE *fp100; // Output File
fp100 = fopen("Conserved_Elements.txt", "a");
struct a *ptr1;
int structACapacity = 3; // Only 3 such comparison files are being worked with, there are >1000 comparison files
ptr1 = malloc(structACapacity*sizeof(struct a));
struct b *ptr2;
int structBCapacity = 1000;
ptr2 = malloc(structBCapacity*sizeof(struct b));
int structure_ctr;
int number_of_line_comparison_files = 3; // Only 3 for the time being
int knt;
int left, right;
for (structure_ctr=0; structure_ctr < number_of_line_comparison_files; structure_ctr++) {
knt = 0;
while (((ptr1+knt) < (ptr1+structACapacity-1)) && (knt < 500)) {
fprintf(fp100, "Getting Into While\n");
// finding the matching entries between right column of knt and left column of (knt+1)
if ((ptr1+knt)->right_line == (ptr1+(1+knt))->left_line) {
fprintf(fp100,"\tGetting Into the If\n");
// copying matching values to the struct b
left = (ptr2+knt)->conserved_left = (ptr1+knt)->left_line;
right = (ptr2+knt)->conserved_right = (ptr1+knt)->right_line;
//fprintf(fp100,"C-Left:%d\tC-Right:%d\tLeft%d\tRight%d\n",(ptr2+knt)->conserved_left,(ptr2+knt)->conserved_right,left,right);
// left, right are there for convinience only - easier to see, same values
fprintf(fp100,"C-Left:%d\tC-Right:%d\n", left,right);
}
++knt;
} // end of while
} //end of for
}
The files look:
A fragment of the first structure element looks like:
17 216
26 119
28 16
29 122
59 124
60 116
62 114
63 112
66 61
69 54
70 51
71 62
91 40
99 38
A fragment of the Second element looks like:
321 25
110 45
116 49
216 110
56 117
54 131
32 167
31 178
8 188
12 199
39 239
60 244
121 263
124 275
A fragment of the 3rd element looks like:
75 223
61 248
45 278
31 290
10 291
111 311
117 324
128 338
139 347
148 365
167 376
178 381
191 394
193 397
etc..., there are many such elements. All of them contain such unformatted two columns of integers.
In case if you are interested to see how the content of the original file was loaded into 'structure_a', the next piece is given. It works fine.
for(q=0; q < number_of_line_comparison_files; q++) // going through the total number of files
{
// File Name Etc ..
while (fgets(file_line,99,line_comparison_file)!= NULL)
{
++number_of_lines ; // Integer
for(j=0;j<6;j++)
string_left_line[j]=file_line[j];
for(j=0;j<6;j++)
string_right_line[j]=file_line[6+j];
left_line = atoi(string_left_line);
right_line = atoi(string_right_line);
*(&(ptr1+q)->left_line) = left_line;
*(&(ptr1+q)->right_line) = right_line;
fprintf(fp100,"Left:%d\tRight:%d\n",(ptr1+q)->left_line,(ptr1+q)->right_line);
} // END OF THE 'WHILE'
fprintf(fp100,"\n\n\t================================== ================================\n\n");
} // End of For
Dan
I must say that, there should be a little more information, for the question to be completely clear.
With the given data, this is my answer. At least the part of what I assume is asked.
I hope it helps.
// copy_pointer_struct.c
#include<stdio.h>
#include<stdlib.h>
int main(int argc, char* args[])
{
struct a
{
int left_line;
int right_line;
};
struct b
{
int conserved_left;
int conserved_right;
};
FILE *fp100;
fp100 = fopen("struct_file.txt", "a");
struct a* ptr1;
int structACapacity = 3;
ptr1=(struct a*)malloc(structACapacity*sizeof(struct a));
struct b *ptr2;
int structBCapacity = 1000;
ptr2=(struct b*)malloc(structBCapacity*sizeof(struct b));
// for writing test values to ptr1 array
int i;
for ( i = 0; i < structACapacity; i++ )
{
ptr1[i].left_line = i;
(ptr1+i)->right_line = i+1;
}
int structure_ctr,
number_of_line_comparison_files = 10,
knt;
// This outer for is neccessary only if you are getting structs form another source - a file for example or another structure.
//for(structure_ctr=0; structure_ctr < number_of_line_comparison_files; structure_ctr++)
{
// this inner for would be neccessary if you had an 2 dimensional array of structs or a pointer to a pointer to struct.
//for(knt=0; knt<500; knt++)
{
knt = 0;
// in your while condition there is no changing value, (change being made inside cycle or condition itself),
// which results in an infinite (for condition true) cycle or 0 cycles (for condition false)
// this particular condition works until we have reached 500th element or the end of array,
// whichever has lower value.
// Of course in case of use of outer for ( && knt < 500) wouldn't be used, depending of the goal you have.
while( (ptr1+knt) < (ptr1+structACapacity-1) && knt < 500 )
{
if( (ptr1+knt)->right_line == (ptr1+1+knt)->left_line ) // comment line for file test
{
// copying duplicate values to the struct b
int left = (ptr2+knt)->conserved_left = (ptr1+1+knt)->left_line;
int right = (ptr2+knt)->conserved_right = (ptr1+knt)->right_line;
// here you can write those values to a file as 2 integers, for example
fprintf(fp100,"%d %d\n", left, right);
}
++knt;
} // while
}//
} //for structure_ctr
fclose(fp100);
}
Perhaps this addition helps:
// copy_pointer_struct.c
#include<stdio.h>
#include<stdlib.h>
typedef struct a
{
int left_line;
int right_line;
} structA;
typedef struct b
{
int conserved_left;
int conserved_right;
} structB;
int fillColumnPtr(FILE* source, structA* ptr);
int main(int argc, char* args[])
{
FILE *fp100;
fp100 = fopen("struct_file.txt", "w");
structA* ptr1;
int structACapacity = 1000;
ptr1=(structA*)malloc(structACapacity*sizeof(struct a));
printf("kapacitet ptr1: %d\n", sizeof ptr1);
structB *ptr2;
int structBCapacity = 1000;
ptr2=(struct b*)malloc(structBCapacity*sizeof(struct b));
char *filename = "columns_file4.txt";
FILE *cfile1 = fopen(filename, "r");
printf("Loading values from file: %s . . . \n", filename);
int number_of_lines = fillColumnPtr(cfile1, ptr1);
fclose(cfile1);
printf("Done.\n\n");
printf("Values loaded to ptr1(total lines %d):\n", number_of_lines);
int i;
for ( i = 0; i < number_of_lines; i++ )
{
printf("left: %6d, right: %6d\n", ptr1[i].left_line, ptr1[i].right_line);
}
printf("\nProcessing...\n");
int structure_ctr,
number_of_line_comparison_files = 10,
knt;
knt = 0;
while( (ptr1+knt) < (ptr1+structACapacity-1) && knt < number_of_lines )
{
if( (ptr1+knt)->right_line == (ptr1+1+knt)->left_line ) // comment line for file test
{
// copying duplicate values to the struct b
int left = (ptr2+knt)->conserved_left = (ptr1+1+knt)->left_line;
int right = (ptr2+knt)->conserved_right = (ptr1+knt)->right_line;
// here you can write those values to a file as 2 integers, for example
fprintf(fp100,"%d %d\n", left, right);
printf("%d %d\n", left, right);
}
++knt;
} // while
fclose(fp100);
}
// function: transfers data from a source file to pointer to struct
int fillColumnPtr(FILE* source, structA* ptr)
{
char file_line[20],
*str_left_line = calloc(sizeof(char), 6),
str_right_line[6];
int left_line, right_line, j, line_counter = 0, i = 0;
while ( fgets(file_line, 19, source) != NULL )
{
printf(">> fileline: %s", file_line);
for(j=0;j<6;j++)
{
str_left_line[j]=file_line[j];
str_right_line[j]=file_line[6+j];
}
left_line = atoi(str_left_line);
right_line = atoi(str_right_line);
printf(" left right: %-3d %6d\n", left_line, right_line);
ptr[i].left_line = left_line;
ptr[i].right_line = right_line;
++i;
++line_counter;
}
return line_counter;
}
Note: I examined few of your source values, that are supposed to be in a file - non of them satisfies the condition inside if, resulting in an empty pointer.
The additional posted, I have tested with altered values and it works.
For this method check the spacing in rows.
Contents of the "columns_file4.txt":
321 25
25 45
116 49
216 110
110 117
54 131
32 167
31 178
178 188
12 199
199 239
60 244
121 263
124 275
// End of file
In this file there are equal values for example:
(row 1 col right)25 == (row 2 col left )25, 110 , 178, 199.
If this is not what you are looking for, then alter the if condition.
Good luck.
Hope this help.