I would expect the code below to produce a file named stackexchangeiscool.txt and write
Hello!
I changed my mind: 17291729
But it doesn't. It produces a file named stackexchangeiscool.txt that contains the text
Hello!
I changed my mind: 17293748407
This code sure doesn't make sense; it is part of a larger code where I have strange problems.
#include <stdlib.h>
#include <stdio.h>
int main(void)
{
FILE * file = NULL;
file = fopen("stackexchangeiscool.txt","w");
int n = 1729;
char myFirstString[] = "This is a string.";
fprintf(file, "Hello!\n");
sprintf(myFirstString, "I changed my mind: %d", n);
fprintf(file, "%s", myFirstString);
fprintf(file, "%d", n);
fclose(file);
return(0);
}
EDIT: A comment below suggested that the problem might come from the fact that myFirstString is too short to contain the new string with the integer in it. However, when I remove the
fprintf(file, "%d", n);
I get
Hello!
I changed my mind: 1729
So myFirstString seems to be able to contain the string and the integer.
The problem is, myFirstString only has enough room for 18 characters, but you're attempting to copy ~23 characters in. This means you're writing off the end of the array. I think what's happening is n is stored directly after myFirstString in memory, and by writing off the end of the array, you're "clobbering" n.
Make sure the array is large enough ahead of time so that everything can fit:
char myFirstString[100] = "This is a string.";
Here, I'm making it an arbitrarily large 100 length. You can either set it to an arbitrary fixed-length like this, or calculate the length you need and malloc it. Either way, you need to ensure that you have enough memory to work with before attempting to copy data.
Related
I am kind of new when it comes to C. Took a class on it in college but I just don't practice it much. Well my issue that I'm having is that I'm trying to take an text file and convert it into an array. I have been able to get the text file and print it into the console but when I save run the while statement to read each line, my whole array gets overwritten. For instance if my last line on my text file is 19, my array[0] gets over written to what should be on array[18].
I know the indentations are off a off, coding is a mess, and forgive me on the printf commands, I'm only using them to troubleshoot my code. The text file will have IP address on each line.
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <string.h>
#define MAX_LINE_LENGTH 16
int main()
{
int lineCntPOSlist = 0;
int lineCnt = 0;
int i = 0;
FILE *textfile;
char line[MAX_LINE_LENGTH];
char* posList[50];
textfile = fopen("pos-list.txt", "r");
if(textfile == NULL)
{
int posListExist = 0;
system("cls");
printf("File Exist %d\n", posListExist);
fprintf(stderr, "**File open failed\n Make sure there is a pos-list.txt file");
return 1;
}
system("cls");
while(fgets(line, MAX_LINE_LENGTH, textfile))
{
printf("Line %d: %s",lineCnt , line);
posList[lineCnt] = line;
printf("posList[%d] = %s\n", lineCnt, posList[lineCnt] );
printf("posList[0] = %s\n", posList[0] );
lineCnt = ++lineCnt;
lineCntPOSlist = ++lineCntPOSlist;
}
fclose(textfile);
return 0;
}
This:
posList[lineCnt] = line;
simply sets posList[lineCnt] to point at the line buffer in line, it copies zero characters of actual data. In higher-level languages where strings have a bit more presence, this would make sense, but in C it doesn't.
Since there is only one line buffer, it will always hold the characters making up the most recently loaded line, and thus it will act as if previous lines are being "overwritten".
There are several solutions, here are a few:
Make posList into a proper array of strings, but that requires you to decide max length in advance and will waste the space for shorter lines.
Use something like strdup() to allocate copies on the heap of each line, and store pointers to those.
Use a more "proper" reallocating array for the storage and store line pointers (or offsets, which might be better suited due to the reallocating) in the array for easier access.
I have read a lot of questions on this, and using them I have altered my code and have created code which I thought would work.
I think it's my understanding of C, which is failing me here as I can't see where I'm going wrong.
I get no compilation errors, but when I run i receive 'FileReader.exe has stopped working' from the command prompt.
My code is :
void storeFile(){
int i = 0;
char allWords [45440][25];
FILE *fp = fopen("fileToOpen.txt", "r");
while (i <= 45440){
char buffer[25];
fgets(buffer, 25, fp);
printf("The word read into buffer is : %s",buffer);
strcpy(allWords[i], buffer);
printf("The word in allWords[%d] is : %s", i, allWords[i]);
//allWords[i][strlen(allWords[i])-1] = '\0';
i = i + 1;
}
fclose(fp);
}
There are 45440 lines in the file, and no words longer than 25 char's in length. I'm trying to read each word into a char array named buffer, then store that buffer in an array of char arrays named allWords.
I am trying to get this part working, before I refactor to return the array to the main method (which I feel won't be a fun experience).
You are trying to allocate more than a megabyte (45440*25) worth of data in automatic storage. On many architectures this results in stack overflow before your file-reading code even gets to run.
You can work around this problem by allocating allWords statically, like this
static char allWords [45440][25];
or dynamically, like this:
char (*allWords)[25] = malloc(45440 * sizeof(*allWords));
Note that using buffer in the call to fgets is not required, because allWords[i] can be used instead, without strcpy:
fgets(allWords[i], sizeof(*allWords)-1, fp);
Also note that an assumption about file size is unnecessary: you can continue calling fgets until it returns NULL; this indicates that the end of the file has been reached, so you can exit the loop using break.
I'm relatively new to this concept for parsing. And here is a simple, yet for me, it's mindbreaking, example.
I have a text file containing a series of numbers and letters. In each line of the text there are three elements. a letter, another letter, and a number. Consider the first as the source, the second as the destination and the number as size. The read them and put them into a structure array and be able to arrange them according to size. "a, b, 1" for the first line. "q, s, 5" for the 2nd, etc. And lastly, printing them in an arranged format (which is according to size)
Mind giving me a clues or starting points?
Update:
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
int main(){
FILE *fp;
fp= fopen("file.txt", "O");
int i;
struct arrangement{
char source;
char dest;
int cost;
};
struct arrangement rng[22];
for(i=0; i<22 ; i++){
fscanf(fp, "%c, %c, %d", rng[i].source, rng[i].dest, rng[i].cost);
printf("%c, %c, %d", rng[i].source, rng[i].dest, rng[i].cost);
}
getch();
return 0;
}
will this be able to "store all elements in the array?I still don't have any idea how I will arrange these according to size/cost without the source and destination being left out.
fscanf requires pointers to the variables, not the variables themselves. Your code may result in strange results, depending on compiler (gcc may emit a warning/error) and platform.
You also should break the loop if reaching EOF. i may then provide the last used entry (which may be partially valid or not, depending on the input).
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.
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.