Writing to a file(fprintf) - c

Im trying to add some bindings to ARP table in Linux, in C. Im opening a file with "a" (append, right?) and then trying to write some addresses, but I always get segmentation fault. I believe there is something wrong with ARP_table[i].IPaddr, ARP_table[i].MACaddr, ARP_table[i].ARPstatus
struct ARP_entry
{
char IPaddr[16];
char MACaddr[18];
char ARPstatus;
int timec;
};
static struct ARP_entry ARP_table[ARP_table_vel];
void copyZIS()
{
int i=0;
const char filename[] = "/proc/net/arp";
FILE *file = fopen(filename, "a");
for (i; i< i+j; i++)
{
fprintf(file, "%c %c %c", ARP_table[i].IPaddr, ARP_table[i].MACaddr, ARP_table[i].ARPstatus);
}
}

You are not checking the return value of fopen. I am pretty sure you are not allowed to write to that file.
FILE *file = fopen(filename, "a");
if (NULL == file) {
perror("fopen");
/* return / exit */
}
Here is /proc/net/arp on my system
[cnicutar#aiur ~]$ ls -l /proc/net/arp
-r--r--r-- 1 root root 0 Jun 8 16:29 /proc/net/arp

Well for one thing, i<i+j will always be true, as long as j (which you haven't shown) is positive.
Then you're trying to display strings with %c, which should be %s.
As for the segmentation fault, your ARP_table is most likely 0 or garbage, but since you don't actually show how it's created, best of luck with that.
As an aside, I feel I need to point out that that's some horrible looking code. Basic questions like "what are those variables?" should never be asked if you have the full function code and type definition. Instead of being globals they should be passed as parameters from functions better equipped to handle them.

You can't write to /proc/net/arp , it's for reading only. (and changing the arp table otherwise is non trivial, you're better off running the external ip or arp command with proper arguments.
Check the return value of fopen, it might fail.
Where's ARP_table and j defined ? Perhaps there's something wrong there.
The condition i > i+j looks weird, are you sure this is the proper condition, and that you shouldn't just stop when i < j ?
Does ARP_table[i].IPaddr contain something sensible ?
"%c %c %c" would be wrong. %c prints a single character. It sounds like the two first should be strings, so use "%s %s %c"

Where is j?
If j is a strict positive constant, you will run into an infinite loop,
because i is always smaller then i + [someting positive]. This will probably cause the error, because your array has only an finite number of elements.
If j is variable and gets negative, you will not run into an infinite loop, but you will produce an i bigger then the number of elements in your array ARP_table.

Related

how to read multiple files from a 2d array in C

i have to write a program that reads multiple files in a for loop and counts the words, sentences, and syllables of that file. My code in the function CountWords looks like this: (filenames is a 2d array with the names of the 17 files stored in it)
for (i = 0; i < 17; ++i) {
inputfile = fopen(filenames[i], "r");
if (inputfile == NULL) {
printf("File cannot be found, verify %s is in the correct location.\n", filenames[i]);
}
int c;
while (c != EOF) {
c = getc(inputfile);
//code to count words/syllables/sentences
}
fclose(inputfile);
While it successfully counts it for the file in the 0th element, the rest of them come out as zero words, zero sentences, zero syllables. Is there something I am doing wrong? thank you for your insight
You might try 'getc' rather than fscanf for reading single characters (if you're not reading UTF-8?) however I don't think that's the issue in this case.
If your current code is stopping after 2 files, perhaps the file doesn't exist or is not readable, in which case I believe the fopen would return null and set an error value in errno.
Your code (unless you've simplified it for the post) doesn't check for a failure result from the fopen, so it might crash with a segfault at that point.
To find out what's going on I'd suggest checking that all the filenames exist and are readable,
and in the code, add a check for the value of pInputFile
it's been a long time since I used C but something like this:
#include <errno.h>
pInputFile = fopen(inputFile,"r');
if(!pInputFile)
{
fprintf(STDERR, "Failed opening %s [error %d]",inputFile,errno());
return -1;
}
and then in your loop, check for the return value < 0
eg:
int count=0;
for (i = 0; i < 18; ++i) {
count = CountWords(filenames[i]);
if(count < 0)
{
//discard the result
}
else
{
// do something with the result
}
}
good luck
and as Hurlu pointed out, you've hard-coded the number of files in the loop as 18. perhaps that doesn't match the size of your array.
the usual convention in C would be to also pass to your function a number of items that are in the array, and use that in your for loop instead of the fixed number '18'
Also if your array of filenames is being populated by some other function,
it could have put an invalid name or null value into the array.
I can see two problems in the code you showed us here :
First, the way you cycle through your file names is hazardous, as you could very well run into a part of the 2D array that isn't initialized. Prefer filenames[i] != NULL as a stopping condition, and make sure the array is correctly initialized:
for (i = 0; filenames[i] != NULL; ++i) {
CountWords(filenames[i]);
}
Second, and that's the most important point, you are not checking your system call to fopen. Which means, your fscanf could very well be reading from a NULL pointer (what fopen returns in case the open failed).
If you get problems with your loops, try using printf to check your index, your fd, or whatever it is that could cause you problems; it is a good practice that will be useful to you in future debugging ;)

reading multiple variable types from single line in file C

Alright I've been at this all day and can't for the life of me get this down, maybe you chaps can help. I have a file that reads as follows
1301,105515018,"Boatswain","Michael R.",ABC, 123,="R01"
1301,103993269,"Castille","Michael Jr",ABC, 123,="R03"
1301,103993267,"Castille","Janice",ABC, 123,="R03"
1301,104727546,"Bonczek","Claude",ABC, 123,="R01"
1301,104731479,"Cruz","Akeem Mike",ABC, 123,="R01"
1301,105415888,"Digiacomo","Stephen",ABC, 123,="R02"
1301,106034479,"Annitto Grassis","Susan",ABC, 123,="R04"
1301,106034459,"Als","Christian",ABC, 123,="R01"
And here is my code...
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_NAME 15
#define MAX_SUBSEC 3
#define N 128
//void printArr(struct *students);
struct student{
int term;
int id;
char lastname[MAX_NAME];
char firstname[MAX_NAME];
char subjectname[MAX_SUBSEC];
int catalog;
char section[MAX_SUBSEC];
}students[10];
int main(){
int term;
int id;
char lastname[MAX_NAME];
char firstname[MAX_NAME];
char sub[MAX_SUBSEC];
int cat;
char sec[MAX_SUBSEC];
char fname[N];
FILE *inputf;
printf("Enter the name of the text file: ");
scanf("%123s",fname);
strcat(fname,".txt");
inputf = fopen(fname,"r");
if (inputf == NULL){
printf("I couldn't open the file for reading.\n");
exit(0);
}
//TROUBLE HERE!
fscanf(inputf, "%d,%d,%[^,]s", &students[0].term, &students[0].id,students[0].lastname);
printf("%d\n", students[0].term);
printf("%d\n", students[0].id);
printf("%s\n", students[0].lastname);
/*for (j = 1 ; j <= 10-1 ; j++){
for(k = 0 ; k <= 10-2 ; k++){
if(students[k] > students[k+1]){
temp = students[k];
students[k] = students[k+1];
students[k+1] = temp;
}
}
}*/
fclose(inputf);
system("pause");
return 0;
}
void printArr(int a[], int tally){
int i;
for(i = 0 ; i < tally ; i++){
printf("%d ", a[i]);
}
printf("\n");
}
My objective is to take each one of those values in the text file and input it to where it belongs in the struct and subsequently the struct array, but I can't get passed the first 2 ints.
Getting the lastname string, because it is a max of 15 characters, it spills over into the first name string right after it and takes what remaining characters it needs in order to fill up the lastname char array. Obviously I do not want this. As you can see I have tried strtok but it doesnt do anything, not sure what I have to do though as I have never used it before. Also have tried just including all the variables into fscanf statement, but I either get the same output, or it becomes a mess. As it is, I am extremely lost, how do I get these values into the variables they belong?!
EDIT: updated my code, I have gotten a little farther but not much. I can now print out just the last name but can not more farther from there, I cant get to the firstname string or any of the variables beyond it.
What you have there is a CSV file with quoted strings, and so I would recommend you use a CSV parser (or roll your own) rather than trying to do it all with scanf (since scanf cannot deal with quotes, e.g. commas within quoted strings). A quick Google search turns up libcsv.c which you may be able to use in your project.
With the fscanf format string "%d,%d,\"%[^\"]\",\"%[^\"]\",%[^,],%d,=\"%[^\"]\"" we can read a whole line's data. Besides, you have to define
char lastname[MAX_NAME+1];
char firstname[MAX_NAME+1];
char subjectname[MAX_SUBSEC+1];
int catalog;
char section[MAX_SUBSEC+1];
— the +1 to account for the terminating '\0' character.
I have a question for you... If you want to know how to use a diamond cutter, do you try it and see, or do you consult the manual? The problem here isn't the result of your choice, but your choice itself. Believe it or not, I have answered these questions so often that I'm tired of repeating myself. The answer is all in the manual.
Read the POSIX 2004 scanf manual — or the POSIX 2008/2013 version — and the answer this question and you'll have some idea of what you're not doing that you should be. Even fscanf code should use assert as a debugging aid to ensure the number of items read was correct.
%[^,]s It seems as though there's a mistake here. Perhaps you meant %[^,]. The %[ format specifier is a different format specifier to the %s format specifier, hence in the presumably mistaken code there are two directives: %[^,] and s. The s directive tells scanf to read an 's' and discard it.
1.There is a syntax error in
while(result != NULL){
printf(".....);
......
}
}//error
fscanf(inputf, "%s", lastname); can't read a line ,fscanf will stop when it comes across an space
fscanf reads one line at a time, and you can easily capture the contents of each line because your file is formatted pretty nicely, especially due to the comma separation (really useful if none of your separated values contain a comma).
You can pass fscanf a format like you're doing with "%d" to capture an int, "%s" to capture a string (ends at white space, be weary of this when for example trying to find a name like "Annitto Grassis, which would require 2 %s's), etc, from the currently read line of the file. You can be more advanced and use regex patterns to define the contents you want captured as chars, such as "Boatswain", a sequence comprised chars from the sets {A-Z}, {a-z}, and the {"}. You'll want to scan the file until you reach the end (signified by EOF in C) so you can do such and capture the contents of the line and appropriately assign the values to variables like so:
while( fscanf(inputf, "%d,%d,%[\"A-Za-z ],%[\"A-Za-z .]", &term, &id, lastname, firstname) != EOF) {
.... //do something with term, id, lastname, firstname - put them in a student struct
}
For more about regex, Mastering Regex by Jeff Friedl is a good book for learning about the topic.

Appending an output file in C

I am solving a problem on USACO. In the problem, I have to take two strings as inputs and calculate the numerical values modulo 47. If the values are same, then GO is to be printed otherwise STAY has to be printed. The initial numerical value will be calculated by taking the product of the numerical values of the alphabets ( 1 for A and similarily 26 for Z ) and then the final number will be calculated by using modulo.
My program is being compiled withour any error and the first case is also a success. But the problem is in the second case and the way my file is being appended. The program is as follows:-
#include<stdio.h>
#include<malloc.h>
#include<string.h>
#define MAX 6
main()
{
int cal(char *ptr);
int a,b;
char *comet,*group;
FILE *fptr;
comet=malloc(6*sizeof(char));
group=malloc(6*sizeof(char));
scanf("%s",comet);
a=cal(comet);
scanf("%s",group);
b=cal(group);
fptr=fopen("ride.out","a+"); (1)
//fptr=fopen("ride.txt","a+"); (2)
if(a==b)
fprintf(fptr,"GO\n"); (3)
//printf("GO\n"); (4)
else
fprintf(fptr,"STAY\n"); (5)
//printf("STAY\n"); (6)
fclose(fptr);
return 0;
}
int cal(char *ptr)
{
int c,prod=1,mod;
while(*ptr)
{
c=(*ptr++)-'A'+1;
prod=prod*c;
}
mod=prod%47;
return mod;
}
OUTPUT:-
The first case is the set two strings:-
COMETQ
HVNGAT
and the second case is given in the error notification itself.
If I remove the comment symbols from (2) and put it on (1), then the program is working fine because I can see the contents of the file and they appear just as the grader system wants. It isn't happening for the actual statement of (1). The comments of line (4) and (6) are also fine but not the line (1). I am not able figure this out. Any help?
First a few notes:
main(): a decent main is either:
int main(void)
or
int main(int argc, char *argv[])
Using malloc() you should always check if it returns NULL, aka fail, or not.
Always free() malloc'ed objects.
Everyone has his/hers/its own coding style. I have found this to be invaluable when it comes to C coding. Using it as a base for many other's to. Point being structured code is so much easier to read, debug, decode, etc.
More in detail on your code:
Signature of cal()
First line in main you declare the signature for cal(). Though this works you would probably put that above main, or put the cal() function in entirety above main.
Max length
You have a define #define MAX 6 that you never use. If it is maximum six characters and you read a string, you also have to account for the trailing zero.
E.g. from cplusplus.com scanf:
specifier 's': Any number of non-whitespace characters, stopping at the first whitespace character found. A terminating null character is automatically added at the end of the stored sequence.
Thus:
#define MAX_LEN_NAME 7
...
comet = malloc(sizeof(char) * MAX_LEN_NAME);
As it is good to learn to use malloc() there is nothing wrong about doing it like this here. But as it is as simple as it is you'd probably want to use:
char comet[MAX_LEN_NAME] = {0};
char group[MAX_LEN_NAME] = {0};
instead. At least: if using malloc then check for success and free when done, else use static array.
Safer scanf()
scanf() given "%s" does not stop reading at size of target buffer - it continues reading and writing the data to consecutive addresses in memory until it reads a white space.
E.g.:
/* data stream = "USACOeRRORbLAHbLAH NOP" */
comet = malloc(szieof(char) * 7);
scanf("%s", buf);
In memory we would have:
Address (example)
0x00000f comet[0]
0x000010 comet[1]
0x000011 comet[2]
0x000012 comet[3]
0x000013 comet[4]
0x000014 comet[5]
0x000015 comet[6]
0x000016 comet[7]
0x000017 /* Anything; Here e.g. group starts, or perhaps fptr */
0x000018 /* Anything; */
0x000019 /* Anything; */
...
And when reading the proposed stream/string above we would not read USACOe in to comet but we would continue reading beyond the range of comet. In other words (might) overwriting other variables etc. This might sound stupid but as C is a low level language this is one of the things you have to know. And as you learn more you'll most probably also learn to love the power of it :)
To prevent this you could limit the read by e.g. using maximum length + [what to read]. E.g:
scanf("%6[A-Z]", comet);
| | |
| | +------- Write to `comet`
| +-------------- Read only A to Z
+---------------- Read maximum 6 entities
Input data
Reading your expected result, your errors, your (N) comments etc. it sound like you should have a input file as well as an output file.
As your code is now it relies on reading data from standard input, aka stdin. Thus you also use scanf(). I suspect you should read from file with fscanf() instead.
So: something like:
FILE *fptr_in;
char *file_data = "ride.in";
int res;
...
if ((fptr_in = fopen(file_data, "r")) == NULL) {
fprintf(stderr, "Unable to open %s for reading.\n", file_data);
return 1; /* error code returned by program */
}
if ((res = fscanf(fptr_in, "%6[A-Z]%*[ \n]", comet)) != 1) {
fprintf(stderr, "Read comet failed. Got %d.\n", res);
return 2;
}
b = cal(comet);
if ((res = fscanf(fptr_in, "%6[A-Z]%*[ \n]", group)) != 1) {
fprintf(stderr, "Read group failed. Got %d.\n", res);
return 2;
}
...
The cal() function
First of, the naming. Say this was the beginning of a project that eventually would result in multiple files and thousand of lines of code. You would probably not have a function named cal(). Learn to give functions good names. The above link about coding style gives some points. IMHO do this in small projects as well. It is a good exercise that makes it easier when you write on bigger to huge ones. Name it e.g. cprod_mod_47().
Then the mod variable (and might c) is superfluous. An alternative could be:
int cprod_mod_47(char *str)
{
int prod = 1;
while (*str)
prod *= *(str++) - 'A' + 1;
return prod % 47;
}
Some more general suggestions
When compiling use many warning and error options. E.g. if using gcc say:
$ gcc -Wall -Wextra -pedantic -std=c89 -o my_prog my_prog.c
This is tremendous amount of help. Further is the use of tools like valgrind and gdb invaluable.

fprintf isn't writing to file

I am trying to use the following C code to print out an array that I have passed in. It should output the text in hexadecimal format one on each line and I have no problems opening the file. When I first wrote it, I had no problems with it working I opened the output file and my array was there. I changed the fileOutName parameter and now I can't get it to print out anything I have tried changing it back and to a few other things and nothing seems to work. Also when I debug it seems like pOutfile is a bad pointer, but like I said it still creates the file it just won't write anything in it. Any help would be appreciated. Thanks
printoutput(int output[], char * fileOutName){
int i = 0;
FILE * pOutfile;
pOutfile = fopen( fileOutName, "w" );
while(output[i] != 0){
fprintf( pOutfile, "0x%0.4X\n", output[i] );
i++;
}
}
Always clean up after yourself. You're missing an fclose(pOutfile).
It should output the text in hexadecimal format one on each line ...
This line
fprintf( pOutfile, "0x%0.4X\n", 5 );
always formats the same number - 5. It probably should be
fprintf( pOutfile, "0x%0.4X\n", output[i] );
You're counting on the element beyond the bounds of the array to be 0, which may not be the case unless you're explicitly setting it. If you are, that's okay. Usually, pass arrays along with their size; this is safer, easier to read, and more portable.
printoutput(int output[], int size, char * fileOutName){
int i=0;
FILE * pOutfile;
pOutfile = fopen( fileOutName, "w" );
while(i!=size){
fprintf( pOutfile, "0x%0.4X\n", output[i] );
++i;
}
fclose(pOutfile)
}
Also, I HIGHLY recommend getting used to using the pre-increment operator instead of post-increment. In situations like this, it probably won't make a difference, but for large inputs or complex types, it can reduce execution time. Hence, ++i instead of i++.

Simple count how many integers are in file in C

Im currently learning C through random maths questions and have hit a wall. Im trying to read in 1000 digits to an array. But without specifiying the size of an array first i cant do that.
My Answer was to count how many integers there are in the file then set that as the size of the array.
However my program returns 4200396 instead of 1000 like i hoped.
Not sure whats going on.
my code: EDIT
#include <stdio.h>
#include <stdlib.h>
int main (void)
{
FILE* fp;
const char filename[] = "test.txt";
char ch;
int count = 0;
fp = fopen(filename, "r");
if( fp == NULL )
{
printf( "Cannot open file: %s\n", filename);
exit(8);
}
do
{
ch = fgetc (fp);
count++;
}while (ch != EOF);
fclose(fp);
printf("Text file contains: %d\n", count);
return EXIT_SUCCESS;
}
test.txt file:
731671765313306249192251196744265747423553491949349698352031277450632623957831801698480186947885184385861560789112949495459501737958331952853208805511
125406987471585238630507156932909632952274430435576689664895044524452316173185640309871112172238311362229893423380308135336276614282806444486645238749
303589072962904915604407723907138105158593079608667017242712188399879790879227492190169972088809377665727333001053367881220235421809751254540594752243
525849077116705560136048395864467063244157221553975369781797784617406495514929086256932197846862248283972241375657056057490261407972968652414535100474
821663704844031998900088952434506585412275886668811642717147992444292823086346567481391912316282458617866458359124566529476545682848912883142607690042
242190226710556263211111093705442175069416589604080719840385096245544436298123098787992724428490918884580156166097919133875499200524063689912560717606
0588611646710940507754100225698315520005593572972571636269561882670428252483600823257530420752963450
Any help would be great.
You forgot to initialize count, so it contains random garbage.
int count = 0;
(But note that with this change it's still not going to work, since %d in a scanf format means read as many digits as you find rather than read a single digit.)
Turn on your compiler's warnings (-Wall), it will tell you that you didn't initialize count, which is a problem: it could contain absolutely anything when your program starts.
So initialize it:
int count = 0;
The other problem is that the scanfs won't do what you want, at all. %d will match a series of digits (a number), not an individual digit. If you do want to do your counting like that, use %c to read individual characters.
Another approach typically used (as long as you know the file isn't being updated) is to use fseek/ftell to seek to the end of the file, get the position (wich will tell you its size), then seek back to the start.
The fastest approach though would be to use stat or fstat to get the file size information from the filesystem.
If you want number of digits thin you tave to do it char-by-char e.g:
while (isdigit(fgetc(file_decriptor))
count++;
Look up fgetc, getc and scanf in manpages, you don't seem to understand whats going on in your code.
The way C initializes values is not specified. Most of the time it's garbage. Your count variable it's not initialized, so it mostly have a huge value like 1243435, try int count = 0.

Resources