Adding and Printing elements of an array in C - arrays

This is a function that is trying to perform the first step of converting a CFG to Chromsky Normal From by adding 0->S as a rule to the end of the list of rules. My rules are an array of characters. For some reason it will only print the array the first time and not any time after that. I want it to print the input and then result once the array has been edited. I cannot figure out why it won't print. The output is just the original input and then blank spaces.
UPDATE: It will now print both times, but the output of the second print is the same as the first. It is not registering that I added ',','0','>','S' as elements to the array. Am I adding the elements wrong?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//global variables
char stringCFG[200];
//a program to convert CFG to Chromsky Normal Form
int main(int argc, char *argv[]){
//intialize instance variables
FILE *CFG;
FILE *output;
char ch;
int RHS= 0;
int isThereS= 0;
int howManyItems= 0;
CFG= fopen(argv[1], "r");
output= fopen(argv[2], "w");
for (int i=0; i<200; i++){
fscanf(CFG, "%c", &stringCFG[i]);
howManyItems++;
fprintf(output,"%c", stringCFG[i]);
}
printf("\n");
for(int i=0; i<200; i++){
if(stringCFG[i] == '>'){
RHS= 1;
}
if(stringCFG[i] == ','){
RHS= 0;
}
if(RHS== 1){
if(stringCFG[i] == 'S'){
isThereS=1;
}
}
}
if(isThereS==1){
stringCFG[howManyItems]= ',';
howManyItems++;
stringCFG[howManyItems]='0';
howManyItems++;
stringCFG[howManyItems]='>';
howManyItems++;
stringCFG[howManyItems]='S';
howManyItems++;
}
for(int i=0; i<200; i++){
fprintf(output,"%c",stringCFG[i]);
}
fclose(CFG);
fclose(output);
}

The problem seems to be here:
for (int i=0; i<200; i++){
fscanf(CFG, "%c", &stringCFG[i]);
howManyItems++;
fprintf(output,"%c", stringCFG[i]);
}
This loop always executes 200 times regardless of what is in the file. In other words - the value of howManyItems will be 200 when the loop is done.
You can check that simply by printing howManyItems after the loop, i.e.
printf("After loop, howManyItems=%d\n", howManyItems);
Since you have:
char stringCFG[200];
then
stringCFG[howManyItems]= ','; // bad.. writing to stringCFG[200]
howManyItems++;
stringCFG[howManyItems]= '0'; // bad.. writing to stringCFG[201]
howManyItems++;
...
will write outside of the array. That is undefined behavior.
You need to stop the first loop once the whole file has been read. Something like:
for (int i=0; i<200; i++){
if (fscanf(CFG, "%c", &stringCFG[i]) != 1)
{
// No more data
break;
}
howManyItems++;
fprintf(output,"%c", stringCFG[i]);
}
and all the following loops must then use howManyItems as the upper limit.
Like
for(int i=0; i<howManyItems; i++){
if(stringCFG[i] == '>'){
RHS= 1;
}
...
}
BTW: Since you want to be able to add 4 extra chars, you probably should do:
char stringCFG[200]; --> char stringCFG[200 + 4];
BTW: Hard-coding the value 200 over and over again is bad practice. Instead use a define like:
#define MAX_CHARS 200
and replace all the hard-coded 200 with MAX_CHARS. Then you can adjust the maximum simply by editing one line instead of multiple lines.

Related

i am trying to read a file in c language the file structure is in array and i have to seperate it into array x[] and y[]

My code is to find line number and then print all element in it but it is throwing garbage value and main thing to do is to seperate front one as x and y respectively plese help me seperate x[] = [60,15,62.....] and y[] = [229,221,59,....]
Dataset is
60,229
15,221
62,59
96,120
16,97
41,290
52,206
...
#include <stdio.h>
#include <stdlib.h>
int main(){
FILE *myFile;
myFile = fopen("datasetLR1.txt", "r");
int count=0;
char c;
for (c = getc(myFile); c != EOF; c = getc(myFile)) {
if (c == '\n'){
count = count + 1;
}// Increment count if this character is newline
}
int numberArray[count*2];
int i;
if (myFile == NULL){
printf("Error Reading File\n");
exit (0);
}
for (i = 0; i < count*2; i++){
fscanf(myFile, "%d,", &numberArray[i] );
}
for (i = 0; i < count*2; i++){
printf("Number is: %d\n\n", numberArray[i]);
}
fclose(myFile);
return 0;
}
After you count the number of lines in the file with your first for loop, you should use rewind(myFile);. This puts you back to the beginning of the file. Without this, you are reading off the end of the file, which is producing the garbage values. Other than that, your code works fine.
You should also look at doing fscanf("%d,%d\n", &x, &y);, which should read off both numbers at once (and the newline) and assign them to x and y respectively. This should simplify your code significantly, however, your code works fine without it.

C program prints garbage characters

I have an assignment to write a program in C that functions similarly to the bash sed 's/oldstring/newstring/g' but only using stdio.h and string.h. We cannot use malloc s we have not yet covered it in class. The program has to continue to take user input until the user enters ^D. We're using GCC so I have it set up to use variable length arrays and I've managed to get the program to find and replace a single instance of oldstring in the user input. However, on occasion the program will output some garbage characters and I am not sure why. I assume it is a memory allocation error or the program is reading past where I want it to read. The code is below:
#include <stdio.h>
#include <string.h>
int isMatch(char * os, char * us){
int i;
char temp[strlen(os)];
for(i=0; i<strlen(us); i++){
int k=0;
for(int j=i; j<i+strlen(os); j++){
temp[k]=us[j];
k++;
}
if(strcmp(temp, os)==0){
return 1;
}
else{
return 0;
}
}
}
void replace(char * os, char * us, char * ns, int loc){
char out[strlen(us) - (strlen(os) - strlen(ns))];
int i;
for(i=0; i<loc; i++){
out[i]=us[i];
}
int k=0;
for(i=loc; i<loc+strlen(ns); i++){
out[i]=ns[k];
k++;
}
k=0;
for(i=loc+strlen(ns); i<strlen(us)-(strlen(os)-strlen(ns)); i++){
out[i]=us[loc+strlen(os)+k];
k++;
}
printf("%s\n", out);
}
int main(int argc, char * argv[]){
char input[100];
int i;
char c;
int match;
while(1){
if(scanf("%c", &c)==EOF){
break;
}
if((input[0]=c) != '\n'){
for(i=1; i<100; i++){
scanf("%c", &input[i]);
if(input[i]=='\n'){
break;
}
}
}
for(i=0; i<100; i++){
match = isMatch(argv[1], &input[i]);
if(match == 1){
replace(argv[1], input, argv[2], i);
}
if(input[i]=='\n'){
break;
}
}
}
}
I call the program with ./a.out aa b for example.
I then enter helaalo and the program spits out helblo which is correct. I then enter libraary and the program outputs librbry followed by some random characters on new lines. I then enter caar and the program outputs cbr followed by even more random letters on new lines. A screenshot of this behavior is included.
Since you can't use malloc, you can force to add terminating \0 for the end of input string and end of out string,
// input
for(i=1; i<100; i++){
scanf("%c", &input[i]);
if(input[i]=='\n'){
input[i] = '\0'; // add terminating \0 for input
break;
}
}
// out
for(i=loc+strlen(ns); i<strlen(us)-(strlen(os)-strlen(ns)); i++){
out[i]=us[loc+strlen(os)+k];
k++;
}
int len = strlen(us)-(strlen(os)-strlen(ns));
out[len] = '\0'; // for out termiante \0
printf("%s\n", out);
The problem is coming from your the way you are filling your input buffer. You don't add a \0 at the end of the string.
There is also an other "problem", when you declare you array out if you want a dynamic size you need to use a malloc. how you are declaring it will not have a dynamic size , the size of the array will be calculated at compilation time. Just to keep it in mind.

C program to generate pseudolanguage - global 3D array is too large (segmentation fault)?

I am supposed to write a program which prints a text in pseudo-English by parsing an existing English text and looking at the last two letters printed to determine what the next one will probably be (the first to are imagined as '.' and ' '). For that task, I came up with the following code:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
short characters[256][256][256];
int main(int argc, char* argv[]){
if(argc<2){
printf("In addition to the input file and maybe output file, please enter the number of output sentences as a command line argument.\n");
return 1;
}
/*Different approach where I malloced the array instead, same result*/
/*short ***characters=malloc(256 * sizeof(short**));
for(int i=0; i<256; i++){
*characters[i]=malloc(256 * sizeof(short*));
for(int i2=0; i2<256; i++){
characters[i][i2]=malloc(256 * sizeof(short**));
}
}*/
/*Read text*/
char a='.', /*pre-previous character*/
b=' ', /*previous character*/
c; /*current character*/
int n=0;
while((c=getchar())!=EOF){
characters[a][b][c]++;
a=b;
b=c;
n++;
}
/*Check how many sentences should be printed*/
int sentences=0, multiplier=1;
for(int i=0; i<sizeof(argv[1])/8; i++){
sentences+=argv[1][i]*multiplier;
multiplier*=10;
}
/*Print text*/
int currentsentences=0, random, p1, p2;
a='.';
b=' ';
while(currentsentences<sentences){
int uninitialized;
srand(time(0)+p1+p2+uninitialized); /*adds a bit of entropy*/
random=rand()%n;
p1=0;
for(int i=0; ; i++){
p2=p1+characters[a][b][i];
if(random>p1 && random<=p2){
c=characters[a][b][i];
p1+=characters[a][b][i];
break;
}
}
putchar(c);
if(c=='.' || c=='?' || c=='!')
currentsentences++;
a=b;
b=c;
}
return 0;
}
It compiles without errors or warnings, however, when I try to run this program, it always returns a segfault before printing anything, unless I do not enter enough command line arguments, in which case it enters the first if clause. This is why I think it has to do something with the 3D array, as it seems not being able to even enter the first loop (if I let it print something before that, it won't). It is needed to be that large, as the structure is the following: [pre-previous letter][previous letter][current letter]=how often did this constellation occur. As I probably would not need higher ASCII and the range of char would probably have been enough, I tried char instead of short and an array of 128*128*128 - same result. Running it as root did not change much and the same goes for increasing ulimit. However, aren't global variabloes saved in the heap? The use of malloc(), which I commented out above, did not change anything as well. I have tried this on two machines, one OS: X, 64 Bit and 8GB DDR3, the other one Linux Mint 19.1, 64 Bit and 32GB DDR4. Both the same result, again (MacOS said segmentation fault: 11, Linux said segmentation fault (core dumped)). As the used memory of that array is about 33 MB, my RAM cannot be the problem either. So why is there a segfault? Do I need to allocate more RAM to the heap (I do not think this is even possible)? Is it maybe something that has not to do with the array and/or its size as all?
This is the latest version of the program; still showing the same behavior:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
short characters[256][256][256];
int main(int argc, char* argv[]){
/*Check if number of sentences was given*/
if(argc<2){
printf("In addition to the input file and maybe output file, please enter the number of output sentences as a command line argument.\n");
return 1;
}
/*Different approach with malloc*/
/*short ***characters=malloc(256 * sizeof(short**));
for(int i=0; i<256; i++){
*characters[i]=malloc(256 * sizeof(short*));
for(int i2=0; i2<256; i++){
characters[i][i2]=malloc(256 * sizeof(short**));
}
}*/
/*Read input text*/
int a='.', /*pre-previous character*/
b=' ', /*previous character*/
c; /*current character*/
int n=0;
for(; (c=getchar())!=EOF; n++){
characters[a][b][c]++;
a=b;
b=c;
}
/*Check how many sentences should be printed*/
int sentences=0, multiplier=1;
for(int i=strlen(argv[1])-1; i>=0; i--){
sentences+=(argv[1][i]-'0')*multiplier;
multiplier*=10;
}
/*Print text*/
int currentsentences=0, random, p1=0, p2=0;
a='.';
b=' ';
srand(time(0));
while(currentsentences<sentences){
random=(rand()+p1+p2)%n;
p1=0;
for(int i=0; i<256; i++){
p2=p1+characters[a][b][i]; /*Determine range for character*/
if(random>p1 && random<=p2){ /*Cheack if random number is in range of character*/
c=characters[a][b][i];
p1+=characters[a][b][i];
break;
}
}
putchar(c);
if(c=='.' || c=='?' || c=='!')
currentsentences++;
a=b;
b=c;
}
return 0;
}
UPDATE: An interesting behavior it shows is that, if you add something like printf(„here“) to the very beginning of the of the program, it will output that „here“ if the first if statement if entered. However, if it is not, the program will return a segfault before printing anything.
UPDATE 2: Interestingly, if you do not give an input file and enter everything manually, it will not return a segfault, but also never finish as well.
UPDATE 3: The program now works, see below. Sorry for all the problems I caused and thank you for helping me.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
unsigned int characters[128][128][128];
int main(int argc, char* argv[]){
/*Check if input file was given*/
if(argc<2){
printf("Please enter an input file as command line argument.\n");
return 1;
}
/*Check for input file, open it*/
FILE *fp=NULL;
fp=fopen(argv[1], "r");
if(!fp){
printf("Error 404: Input file not found.\n");
return 404;
}
/*Read input text*/
int a='.'; /*pre-previous character*/
int b=' '; /*previous character*/
int c; /*current character*/
while((c=fgetc(fp))!=EOF){
if(c<127 && c>='\t'){ /*All characters from higher ASCII and system codes ignored. Still uses letters, digits and typical special characters and formatting characters.*/
characters[a][b][c]++;
a=b;
b=c;
}
}
fclose(fp);
/*Check how many sentences should be printed*/
unsigned int sentences;
printf("How many sentences do you want to be printed? ");
scanf("%d", &sentences);
/*Print text*/
unsigned int currentsentences=0, random, p1=0, p2=0, n;
a='.';
b=' ';
srand(time(0));
while(currentsentences<sentences){
n=0;
for(int i='\t'; i<127; i++){
n+=characters[a][b][i];
}
random=(rand()+p1+p2+sentences+currentsentences+clock())%n;
p1=0;
for(int i='\t'; i<127; i++){
p2=p1+characters[a][b][i]; /*Determine range for character in combination with line 58*/
if(random>=p1 && random<p2 && characters[a][b][i]!=0){ /*Check if random number is in range of character and that character occured in that combination*/
c=i;
printf("%c", c);
characters[a][b][c]++; /*Experimental, language will change over time pseudo-randomly*/
break;
}
p1+=characters[a][b][i];
}
if(c=='.' || c=='?' || c=='!')
currentsentences++;
a=b;
b=c;
}
printf("\n");
return 0;
}
The main problem is in this part of the code:
p1=0;
for(int i=0; ; i++){
p2=p1+characters[a][b][i];
if(random>p1 && random<=p2){
c=characters[a][b][i];
p1+=characters[a][b][i];
break;
}
}
Here you keep incrementing i without checking for out of bounds access. You should have something like:
if (i >= 255) { // error handling ....};
Also notice that p1 in the loop is always zero.
In this part
random=(rand()+p1+p2)%n;
p1 and p2 is uninitialized so you may end up with a negative number which obviously means that you never hit the break statement. In other words - an endless loop where you keep incrementing i (which leads to out of bounds access).
As an example I changed the code like:
for(int i=0; ; i++){
printf("random=%d p1=%d a=%c b=%c i=%d", random, p1, a, b, i);
and got output like:
...
random=-3 p1=0 a=. b= i=42484 p2=0
random=-3 p1=0 a=. b= i=42485 p2=0
random=-3 p1=0 a=. b= i=42486 p2=0
random=-3 p1=0 a=. b= i=42487 p2=0
...
Notice that random is negative so the loop can never terminate.
Warnings, Errors and some very good suggestions are pointed out in the comments under your post. nota bene.
The following comment statement seems clear enough,
/*Check how many sentences should be printed*/
but it was not clear to me what was being done in the following snippet of your code to accomplish that:
int sentences=0, multiplier=1;
for(int i=0; i<sizeof(argv[1])/8; i++){
sentences+=argv[1][i]*multiplier;
multiplier*=10;
}
So the following short snippet is a suggestion for a different approach:
// assume at minimum input of one legal filespec,
// eg: .\\filename.txt (Windows) or ./filename.txt (Linux)
int main(int argc, char *argv[])
{
FILE *fp = NULL;
int c = 0;
int sentences = 0;
if(argc<2)
{
printf("Minimum command line usage: <name>.exe [pathFileName]. Program exiting.");
getchar();
return 0;
}
fp = fopen(argv[1], "r");
if(fp)
{
c = fgetc(fp);
while(c) // will exit upon EOF (-1) Note c is int, not char
{
if( (c=='.') || (c=='?') || (c=='!') )
{
sentences++;
}
}
fclose(fp);
}
else return 0; //error, file not opened.
/* rest of your code here */
return 0;
}
The entire logic for selecting the next character is wrong:
After the loop iterating i to examine characters[a][b][i], the code sends c to output. At that point, c is either left over from some previous code or is characters[a][b][i] for some i, which means it is a count of triples that were seen during analysis—it is not a code for the character that should be printed.
The code for preparing p1 and p2 and comparing them to a random number is nonsensical. The code ought to pick a random number in [0, N), where N is the sum of characters[a][b][i] for all character codes i and then select the character code c such that c is in [p1, p2), where p1 is the sum of characters[a][b][i] for 0 ≤ i < c and p2 is p1 + characters[a][b][c].

C: issue with printing 2d array

I'm working on my C code, and got a problem with printing my 2d array. Instead of printing one string at the time, it prints the entire array from the asked point.
As an example, the input is, "Dog", "Cat", "Hat". Then it would print out:
DogCatHat
CatHat
Hat
This is what my code is suppsoed to do: It reads from a file. It creates an array of char arrays. Where each char array has 30 chars in them, read from file one char at the time. Then it prints out one char array per line.
This is what the code looks like:
char fname[] = "folder/text.txt";
char arry[30][30];
FILE *file;
file = fopen(fname, "r");
for(int x=0; x<30; x++){
for(int i=0; i<30; i++){
arry[x][i] = fgetc(file);
}
}
fclose(file);
for(int i=0; i<30; i++){
printf("%s\n", arry[i]);
}
Most likely I have just made an obvious mistake, but I'm not able to find it. So please help.
I think strings in file are not null terminated. So you need to put null character at the last character of the array.
char arry[30][30]
for(int x=0; x<30; x++){
for(int i=0; i<29; i++){ //You can write 29 characters + '\0'
arry[x][i] = fgetc(file);
}
arry[x][29] = '\0';
}
for(int i=0; i<30; i++){
printf("%s\n", arry[i]);
}

Bubble sort with file in C

I want to implement bubble sort with writing to the file. I think that sorting is implemet good, but something wrong is with writing to file.
int main(int argc, char *argv[])
{
FILE *fp;
int tab[] = {3,5,1,2,4};
int i, j, temp;
if ((fp=fopen("test.txt", "w"))==NULL) {
printf ("Error!\n");
exit(1);
}
for(i =0; i<5;i++)
{
for(j=0; j<4; j++)
{
if(tab[j] > tab[j+1])
{
temp = tab[j+1];
tab[j+1] = tab[j];
tab[j] = temp;
}
}
}
fprintf (fp, "%d", tab);
fclose (fp);
return 0;
}
Can you help me?
Since %d format string instructs printf() to print a single integer what the code tries to do is writing a pointer to an array of integers as if it was an integer.
Simply loop over your array and print one int in every iteration. You will also need to decide on a separator you want to use or else all the integers will be written side by side preventing the reader from making sense of them.

Resources