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
Related
I've seen this previous post, but this one doesn't work for my situation.
My situation is below:
1 { 87 36 135 }
2 { 100 156 167 43 92 174 149 21 }
3 { 144 7 58 149 127 189 5 54 57 }
4 { 128 61 30 4 165 72 117 }
5 { 158 104 196 156 151 162 198 }
6 { 87 98 14 }
My goal is to put these integers between curly brackets into a 2D array. Then, I can manipulate them.
I also tried it in the C version. My idea is to go to the left curly bracket to save the number and go to the next line when it meets the right curly bracket.
However, my idea doesn't work for the above situation because the integers my two or three characters.
char str1;
int count = 1;
int no;
char c;
FILE *filepointer;
// filepointer = fopen("~", "r");
filepointer = fopen(argv[1], "r");
printf("\n The content of the file %s is :\n", argv[1]);
c = fgetc(filepointer);
while (c != EOF)
{
if(c == '{'){
int adj = 1;// may be careful
while (c != '}')
{
while (isspace(c = fgetc(filepointer)))
;
if(c == '}')
break;
int returnNumber = 0;
returnNumber = returnNumber * 10 + (c - '0');
nets[count][adj] = returnNumber;
adj++;
}
count++;
}
// printf("%c", c);
c = fgetc(filepointer);
}
no = count;
printf("\n\n");
fclose(filepointer);
for (int i = 1; i < no;i++){
for (int j = 1; j < MAX_ADJCENT_SIZE;j++){
printf("%d ", nets[i][j]);
}
printf("\n");
}
What can I try next?
You could read all characters that are digits before saving the number and moving on to the next:
int returnNumber = 0;
if (isdigit(c)) {
do {
returnNumber = returnNumber * 10 + (c - '0');
c = fgetc(filepointer));
} while (isdigit(c));
nets[count][adj] = returnNumber;
adj++;
}
I'm at a very basic level of C programming: I can print out an ASCII table.
The problem is printing out 10 of the ASCII characters per line, e.g.:
characters 1-10 (newline)
characters 10-20...
and so on up to 255
int main() {
int i;
while (i <= 255) {
printf("%c", i);
i = i + 1;
}
exit(0);
}
the following proposed code
cleanly compiles
performs the desired functionality
also labels each line
makes use of isprint() from ctype.h to determine if outputs current character or outputs a '.'
And now, the proposed code:
#include <stdio.h>
#include <ctype.h>
int main( void )
{
for( int i = 0; i<256; i++ )
{
if( !( i%10 ) )
{
printf( "\n%3d thru %3d ", i, i+9 );
}
if( isprint( i ) )
{
putchar( i );
}
else
{
putchar( '.' );
}
}
}
The output from the above code is:
000 thru 009 ..........
010 thru 019 ..........
020 thru 029 ..........
030 thru 039 .. !"#$%&'
040 thru 049 ()*+,-./01
050 thru 059 23456789:;
060 thru 069 <=>?#ABCDE
070 thru 079 FGHIJKLMNO
080 thru 089 PQRSTUVWXY
090 thru 099 Z[\]^_`abc
100 thru 109 defghijklm
110 thru 119 nopqrstuvw
120 thru 129 xyz{|}~...
130 thru 139 ..........
140 thru 149 ..........
150 thru 159 ..........
160 thru 169 ..........
170 thru 179 ..........
180 thru 189 ..........
190 thru 199 ..........
200 thru 209 ..........
210 thru 219 ..........
220 thru 229 ..........
230 thru 239 ..........
240 thru 249 ..........
250 thru 259 ......
You may want to modify the proposed code, such that:
it does not output an initial blank line
it stops the last label at 255 rather than 259
does not print leading '0's
does not print the labels
Amending the previous answer it is not good to print non ascii chars as the console (terminal) behaviour can be weird. Print something else instead - for example dot,
#define MINCHAR 32
#define MAXCHAR 127
int main() {
int i = 0;
while(i<=255) {
putchar((i >= MINCHAR && i <= MAXCHAR) ? i : '.');
if(!(i % 10) && i) putchar('\n');
i = i + 1;
}
putchar('\n');
}
So if you want afte every 10 character a new line, this code should work.
int main() {
int i = 0;
while(i<=255) {
printf("%c", i);
if(i % 10 == 0)
printf("\n");
i = i + 1;
}
exit(0);
}
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 a string in the format:
char *sampleLine = "name1: 251 name2: 23 name3: -67 name4: 0.00 name5: 310 name6: 410 name7: 54001 name8: 332 name9: SOME_TEXT name10: 3 name1: 181 235 237 name11: 11 name12: 240 241 242 243 244 245 246 247 248 249 250 name13: 0 name14: 2 name15: 1 name16: 0 name17: 6 name18: 0 name19: 500 name20: 200 name21: 64 name22: 1 name23: 6 name24: 0 name25: 0";
One of the issues with the string is that some of the names are repeated but the basic pattern seemed to be name: value. So I wrote an algorithm that would take a name and return a value but it doesn't seem to work and does not take into account the issue with a name being repeated.
So for example: if I pass in name1, I would expect to get 251 ,etc.
Here is the code with a sample main:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
char* extractValue(char* name, char* buffer)
{
char* begining = strstr(buffer,name);
begining += strlen(name) + 2;
if (begining != NULL)
{
char* end = strstr(begining,":");
if (end != NULL)
{
end += 1;
for (int i=0; i < strlen(end); i++)
{
if (end[i] != ':')
{
i++;
} else {
char namevalue[200];
bzero(namevalue,200);
strncpy(namevalue,begining,i);
for (int x=strlen(namevalue); x>0; x--)
{
if (namevalue[x] == ' ')
{
char* value = (char*)malloc(200);
bzero(value,200);
strncpy(value,namevalue,strlen(namevalue) - (strlen(namevalue) - x));
return value;
}
}
break;
}
}
}
}
return NULL;
}
int main (int argc, char** argv)
{
char *sampleLine = "name1: 251 name2: 23 name3: -67 name4: 0.00 name5: 310 name6: 410 name7: 54001 name8: 332 name9: SOME_TEXT name10: 3 name1: 181 235 237 name11: 11 name12: 240 241 242 243 244 245 246 247 248 249 250 name13: 0 name14: 2 name15: 1 name16: 0 name17: 6 name18: 0 name19: 500 name20: 200 name21: 64 name22: 1 name23: 6 name24: 0 name25: 0";
char* value1 = extractValue("name1", sampleLine);
char* value3 = extractValue("name3", sampleLine);
char* value17 = extractValue("name17", sampleLine);
printf("value 1 = %s\n",value1);
printf("value 3 = %s\n",value3);
printf("value 17 = %s\n",value17);
return 0;
}
When I run it, I get:
$ gcc -Wall -std=c99 -o parse parse.c && ./parse
value 1 = 251 name2: 23
value 3 = -67 name4: 0.00
value 17 = 6 name18: 0 name19: 500 name20: 200 name21:
Instead of expected
value 1 = 251
value 3 = -67
value 17 = 6
Two subtle errors.
First,
if (end[i] != ':')
{
i++;
} else ..
By manually incrementing i here, you are skipping a character, as i already gets incremented by the for-loop. It appears to have no side effects, but only because ...
Second: the actual cause of your problem is you are measuring the length of the wrong string. You locate the beginning of the name value (begining) and then its end by scanning forward from that position for the next :. Then, you track backwards to find the previous space, which should be the end of the value. But ...
for (i=0; i < strlen(end); i++)
checks forwards from the (already determined) end of the string! Of course, for your test names, you are bound to find a colon somewhere further along--but its position has nothing to do with the string you are interested in, which is between begining and end.
Change your i loop to
for (i=0; i < end-begining; i++)
and change the : check to
if (begining[i] == ':')
{
char namevalue[200];
... (etc.)
(discarding the i++ line).
Loose notes
A slightly faster way to look for a single character is strchr:
char* end = strchr(begining,':');
You might want to find a better strategy for locating the name. If you are looking for name1, it could find name12 as well as noname1.
One way would be to split a string into tokens using strtok. Then anything ending with a : is a potential name, and the next token is the value you are looking for. Omitted, because it's a nice exercise in its own. (And if you are going to try this: strtok modifies the original string!)
Finally, you can do without all those loops :-)
char* extractValue(char* name, char* buffer)
{
char *start, *end, *ret_val;
int length;
char* begining = strstr(buffer,name);
if (!begining)
return NULL;
start = begining + strlen(name);
if (start[0] != ':')
return NULL;
start++;
// skip initial spaces, if any
while (*start == ' ')
start++;
// ptr points to the start of data. Find end.
end = start;
while (*end && *end != ' ')
end++;
// we have the correct string in start..end
length = end-start;
// it's a zero-terminated string so add 1 for the zero
ret_val = (char *)malloc(length+1);
strncpy (ret_val, start, length);
// put the zero where it belongs
ret_val[length] = 0;
return ret_val;
}
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);