I have a segmentation fault...i'm not sure what's causing it. Also, when passing the member pname into the function get_names, am I doing this correctly, or is there a better way of doing this?
#include <stdio.h>
#define MAX_NAME 20
#define MAX_PLAYRS 16
typedef struct {
char pname[MAX_NAME];
int runs;
char how_out;
} Team_t;
Team_t player[MAX_PLAYRS];
Team_t *player_ptr[MAX_PLAYRS];
void get_names (int count, char *str);
int main (void) {
int i;
for (i = 0; i < MAX_PLAYRS; i++) {
get_names(i, &(*player[i].pname));
printf("Player: %s\n", player[i].pname);
}
}
void get_names (int count, char *str) {
FILE *inp;
char status;
inp = fopen("teamnames.rtf", "r");
status = fscanf(inp, "%s", str);
if (status == EOF) {
count = MAX_PLAYRS;
}
}
With your code unchanged, I get a segmentation fault if the file can't be opened properly (i.e. it's unreadable due to permissions, or it simply does not exist).
Here's a modified version of you function get_names():
void get_names(int count, char *str)
{
FILE *inp;
inp = fopen("teamnames.rtf", "r");
if (inp == NULL) {
perror("Failed");
return;
}
fgets(str, MAX_NAME, inp);
fclose(inp);
}
This would still read the first name 16 times, but it would tell you why it didn't manage to open the file. To read the next name from the file (rather than repeatedly the first name), open (and close) the file in the main() function instead.
Also, you might as well call get_names() like so:
get_names(i, player[i].pname);
No need to do that &(*...) thing you're doing.
And, finally, I hope that the teamnames.rtf file is not actually an RTF file, but a simple text file with a name on each line.
The problem comes from this line:
get_names(i, &(*player[i].pname));
Understanding pointers and dereferencing is one of the biggest adjustments to learning C if you are switching from another language. You're doing it wrong, and I think you should seek out a tutorial on the subject. Try http://www.cplusplus.com/doc/tutorial/pointers/ as a starting point.
Get a debugger to tell you what is wrong. Compile the code with debugging enabled (see you man page for your compiler) and run something like this:
gdb a.out core
Then you should be able to see which line made the code core dump. You could use idb as well, if you have the intle compiler installed. This is, of course, on *nix. If you are talking windows, use the VS debugger.
In addition do NOT use fscanf as it is unsafe. Use fgets instead.
There are many strange things. First thing is, it seems like the names are in a file, but what you are doing is in every iteration of your for loop, you call get_names which opens the file again, that is goes to the beginning of the file and you read the same name over and over again.
That is if you closed the file. Since you haven't closed the file, the file is already open and you keep reopening it (which could be the cause of your problem)
Another thing is, how can
if (status == EOF) {
count = MAX_PLAYRS;
}
Give you the current count? Regardless of the count of the players in the file, you are just setting it to MAX_PLAYERS.
Another thing is that count is an input to the function that is not a pointer, so setting it does not change the value outside the function (which is what I assumed you wanted).
Here is how I would do it with minimum change to your code:
#include <stdio.h>
#define MAX_NAME 20
#define MAX_PLAYRS 16
typedef struct {
char pname[MAX_NAME];
int runs;
char how_out;
} Team_t;
Team_t player[MAX_PLAYRS];
Team_t *player_ptr[MAX_PLAYRS];
void get_names (int count, char *str, FILE *inp);
int main (void) {
FILE *inp;
int i;
int count;
inp = fopen("teamnames.rtf", "r");
for (i = 0; i < MAX_PLAYRS; i++) {
get_names(&count, player[i].pname, inp);
printf("Player: %s\n", player[i].pname);
}
}
void get_names (int *count, char *str) {
char status;
status = fscanf(inp, "%s", str);
if (status == EOF) {
*count = MAX_PLAYRS;
}
}
Here is how I would do it more concisely:
#include <stdio.h>
#define MAX_NAME 20
#define MAX_PLAYRS 16
typedef struct {
char pname[MAX_NAME];
int runs;
char how_out;
} Team_t;
Team_t player[MAX_PLAYRS];
Team_t *player_ptr[MAX_PLAYRS];
int get_names (Team_t *team);
int main (void) {
get_names(player);
}
int get_names (Team_t *team) {
int i = 0;
FILE *inp;
inp = fopen("teamnames.rtf", "r");
while (i < MAX_PLAYRS && !feof(inp) {
fscanf(inp, "%s", team[i].pname);
printf("Player: %s\n", player[i].pname);
}
}
Note that the problems with fscanf, checking array boundaries etc are not the concern of this solution, but this rather gives you the idea of what to do not a code for you to copy-paste.
Related
I'm pretty new to C, and I'm not sure what is wrong with this piece of code I have written. It is supposed to open (or create if needed) a file using a name specified and in that file write a bunch of signs taken from the /dev/urandom file. I need a precise amount of elements each one of a specified length. I need to be able to later edit that created file, but I wanted to focus on creating this generator part first. It doesn't show any errors when compiling or when I try to execute it, but still nothing happens - the file still doesn't exist anywhere. What's wrong with it?
int main(){
void generate(char str[], int a, int b);
}
void generate(char str[], int a, int b){
int n=0;
char fname[128];
strcpy(fname,str);
strcpy(fname, ".txt");
FILE *myFile = fopen(fname, "w");
FILE *randomiser = fopen("/dev/urandom", "r");
char bufor[a];
size_t result = fread (bufor, b, a, randomiser);
size_t end = fwrite (bufor, b, a, myFile);
fclose(myFile);
fclose(randomiser);
}
#edit
change the tile as someone suggested and changed a code a bit since im still trying to work it out
I forgot to mention that the whole point of this function is for it to be called in terminal as for example ./program generate data 100 100.
Here is the exact solution you asked for
There you go. I use open instead of fopen, read a certain amount of char out of /dev/urandom then write it to fd2 (the file created),
Be carefull the size of the buffer, be careful The NULL (\0) terminate the string
#include <sys/types.h>
#include <sys/uio.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
int generate(char **av)
{
int fd1 = open("/dev/urandom", O_RDONLY);
int fd2 = open(av[1], O_CREAT | O_RDWR, S_IRWXU);
int size = atoi(av[2]);
int row = atoi(av[3]);
int i = -1;
int j = -1;
if (fd1 == -1 || fd2 == -1 || size <= 0 || row <= 0 )
return (1);
char buf[size];
while (++i < row-1)
{
read(fd1, buf, size);
buf[size -1] = '\0';
write(fd2, buf, size -1);
while (++j < size)
buf[j] = '\0';
}
close(fd1);
close(fd2);
return (0);
}
int main(int ac, char **av)
{
int s;
if (ac < 4)
return (1);
generate(av);
return (0);
}
for 10 * 100 char into file 'blabla' Use with :
$~> gcc prog.c -o program
$~> ./program blabla 100 10
Will create / open the file "blabla" read 100 from /dev/uramdom and wirte to blabla
To explain what you did wrong here look :
This is a declaration of a function
void generate(int i, char *a);
This is a call to a function
generate(25, "Blablabla");
sometime when you declare a function you also instanciate it aswell
int generate(int i, char *a)
{
Operation;
operation;
return (0);
}
Declaration, and instanciation are different, let's assume i wrote funtion generate under function main in the above code example, function main would not know what is "generate" but if you declare it before main just like this it works
void generate(int i, char *a);
Here's what I made out of your source code with minimal changes
#include <stdio.h>
void generate(char basename[], size_t size);
int main(void) {
generate("foobar", 42);
}
void generate(char basename[], size_t size) {
char fname[128];
sprintf(fname, "%s.txt", basename);
FILE *myFile = fopen(fname, "w");
FILE *randomiser = fopen("/dev/urandom", "r");
char bufor[size];
size_t result = fread(bufor, 1, size, randomiser);
fwrite(bufor, 1, result, myFile);
fclose(myFile);
fclose(randomiser);
}
The problem is that your program never calls the generate() function, as #fredrik pointed out in comments. This:
void generate(char str[], int a, int b);
is a function declaration, not a call. Although it is legal to put such a declaration inside a function, it is much more conventional to put it outside and preceding the function(s) that will be doing the calling. And in this case, you could avoid using a separate declaration at all by just moving the main() function to the end, after the definition of generate().
But that still doesn't get around the fact that you need to call the function if you want it to do anything. And to call it, you will need to provide arguments. For example,
generate("random_data", 10, 4);
From your description, you'll want to use arguments determined from evaluation of command-line parameters, but that aspect would be a separate question.
so i am supposed to create a program that analyzes said text file and when i first ran it, i didn't have the text file created, but once i created it and tried to run the program i got a seg fault error and now i don't know how to fix it.
#include <stdio.h>
#include <string.h>
#define FILENAME "poems.txt"
int getWords(int maxWord, char words[][maxWord], FILE*);
int countLetters(char str_letter[]);
int countLowerCase(char str_lower[]);
int countVowels(char str_vowel[]);
int main()
{
int maxWord=50;
int numWord=0;
char words[numWord][maxWord];
char str_letter[75];
char str_lower[75];
char str_vowel[75];
FILE* fp;
int numLetter;
int numLower;
int numVowel;
fp=fopen(FILENAME, "r");
if(fp==NULL) {
printf ("poems.txt could not be found!\n");
}
else {
getWords(maxWord, words, fp);
countLetters(str_letter);
countLowerCase(str_lower);
countVowels(str_vowel);
printf ("There are %d letters in your file.\n", numLetter);
printf ("There are %d lower case letters in your file.\n", numLower);
printf ("There are %d vowels in your file.\n", numVowel);
fclose(fp);
}
return 0;
}
int getWords(int maxWord, char words[][maxWord], FILE* inFILE)
{
int numWord=0;
char poem;
while(fscanf(inFILE, "%s", &poem)==1){
words[numWord][maxWord]=poem;
numWord++;
}
numWord++;
return numWord;
}
int countLetters(char str_letter[])
{
int numLetter=0;
for(int i=0; i<strlen(str_letter); i++) {
if((str_letter[i]>'a' && str_letter[i]<'z')||(str_letter[i]>'A' && str_letter[i]<'Z'));
numLetter++;
}
return numLetter;
}
int countLowerCase(char str_lower[])
{
int numLower=0;
for(int i=0; i<strlen(str_lower); i++) {
if(str_lower[i]>'a' && str_lower[i]<'z');
numLower++;
}
return numLower;
}
int countVowels(char str_vowel[])
{
int numVowel=0;
for(int i=0; i<strlen(str_vowel); i++) {
if(str_vowel[i]=='a'||str_vowel[i]=='e'||str_vowel[i]=='i'||str_vowel[i]=='o'||str_vowel[i]=='u')
{
numVowel++;
}
else if(str_vowel[i]=='A'||str_vowel[i]=='E'||str_vowel[i]=='I'||str_vowel[i]=='O'||str_vowel[i]=='U')
{
numVowel++;
}
}
return numVowel;
}
You are making so many mistakes on your code, so i need to ask, you understands how dynamic memory allocation and pointers works in C? Is not like other languajes, you need to allocate memory before you access to them.
If you dont have a text file, your code works and the output is:
poems.txt could not be found!
So up to here everithings seems to work fine, but it doesn't.
Lets go to the line where you declare:
int maxWord=50;
int numWord=0;
char words[numWord][maxWord];
Here you are saying "SAVE ME AN ARRAY OF 0 POSITIONS AS COLUMNS AND 50 POSITIONS OF ROWS" so when you execute the following code in the function getWords, your code breaks.
while(fscanf(inFILE, "%s", &poem)==1){
words[numWord][maxWord]=poem;
numWord++;
}
Because the position:
words[1][maxWord]
isn't allocated.
You got two ways of allocate memory in C as far as i know, dynamic and static memory allocation.
I believe you came from learning another languaje like python or javascript where this types of things "works" but not in C.
If you want to solve this problems take a look to dynamic memory allocation and how C pointers works, you can make your code unstopable!
I have written a program which read values from a the file. The data in the file is in following format.
100 Full Name SomeDetails.
234 Full Name SomeDetails
Following is the program which i wrote.
#include <stdio.h>
#include <stdlib.h>
#include<string.h>
#define MAX 10
struct student
{
int rollno;
char name[20];
char course[25];
};
int main()
{
FILE *fptr;
fptr=fopen("records.txt","r");
struct student s[10];
int i=0,tstudent=0;
char che;
char line[100];
//SECTION : 1.1 -> READING NUMBER OF LINES
while(!feof(fptr))
{
che=fgetc(fptr);
if(che=='\n')
{
tstudent++;
}
}
printf("Total Lines in File = %d\n",tstudent);
fclose(fptr);
//SECTION : 1.2 -> READING RECORDS FROM FILE
fptr=fopen("records.txt","r");
char newString[20][20];
int ii,j,ctr;
j=0;
ctr=0;
for(i=0; i<tstudent; i++)
{
fgets(line,100,fptr);
printf("Value of Line %d = %s",i,line);
for(ii=0; ii<=(strlen(line)); ii++)
{
// if tab or NULL found, assign NULL into newString[ctr]
if(line[ii]=='\t'||line[ii]=='\0')
{
newString[ctr][j]='\0';
ctr++; //for next word
j=0; //for next word, init index to 0
}
else
{
newString[ctr][j]=line[ii];
j++;
}
}
}
for(ii=0; ii < ctr; ii++)
{
printf("\n%s",newString[ii]);
}
printf("Value of ctr = %d",ctr);
fclose(fptr);
}
Above code is working fine, BUT all the code is in main function, but i want to make a separate function which can be called from main file and return me every data of file in two dimensional or one dimensional array as return value.
Any help/suggestions would be appreciated.
I tried following CODE as a separate function.. NOT WORKING.
#include <stdio.h>
#include <stdlib.h>
#include<string.h>
char readfile(int tstudent,FILE* filename)
{
//FUNCTION TO READ RECORDS FROM FILE.
FILE *fptr;
int i,k;
char line[100];
char newString[20][20];
int j=0,ctr=0;
fptr=fopen("records.txt","r");
for(i=0; i<tstudent; i++)
{
fgets(line,100,fptr);
printf("Value of Line %d = %s",i,line);
for(k=0; k<=(strlen(line)); k++)
{
// if tab or NULL found, assign NULL into newString[ctr]
if(line[k]=='\t'||line[k]=='\0')
{
newString[ctr][j]='\0';
ctr++; //for next word
j=0; //for next word, init index to 0
}
else
{
newString[ctr][j]=line[k];
j++;
}
}
}
return newString;
}
I defined a new variable char results[] in main function.. and tried to called the function as follows
results[]=readfile(tstudent,fptr)
but when trying to read results.. its showing garbage
char readfile(int tstudent,FILE* filename)
...
char newString[20][20];
...
return newString;
That can't be a good thing, right? You define readFile to return one single character (not a pointer, just one byte) and then return an array instead. We should not be surprised the compiler complained.
If you "fix" that be redefining the return type, you still have a problem because newString is an automatic local variable. The storage (memory) it defines is undefined outside the function.
The easiest way for a function to populate a structure (or array) in C is for the caller to pass it as a function parameter. So you wind up with something more like:
int readfile( FILE* input, char newString[][20], int tstudent )
where newString is defined the same way as you have it, but by the caller, not in readfile. Cf. the stdio functions like fgets; most of them require the caller to define the buffer they read into.
I'll just point out a few more mistakes.
Whenever you call a function -- especially an I/O function -- check for errors. You may want to read tstudent records, but how many are there? If you ask for 5 and find only 1, what then? Your read loop must test for end-of-file, and readfile must return the number of records read, else the caller will never know. Compare with how fread(3) works. Those Unix guys knew a thing or two about how to define a function!
Now your function looks something like this:
int readfile( FILE* input, char newString[][20], int tstudent ) {
char line[100], *s;
int i=0;
for( ; i < tstudent && (s = fgets(line, sizeof(line), input)) != NULL; i++ ) {
/* do stuff with line */
}
/* check for EOF/error if s is NULL, and report */
return i;
}
I'm writing a program that should handle some data stored inside a file and it runs perfectly when I run it in debug mode inside codeblocks but crashes whenever I try to make it run differently (either by clicking on the exe or try running the release mode) I tried everyhing and I think there shouldn't be out of bounds accesses or uninitialized pointers this is just an abstract from the code since it stops on the function readCSV, the csv file contains 53 lines and the count rows is able to count them properly also on release, the printfs were ony to understand where it stops executing I hope there are some errors that I can't spot, thanks in advance for the help
typedef struct
{
char* codice;
char* nome;
char* album;
char* artista;
int track;
Durata durata;
Genere genere;
}Brano;
int countRowsCSV(const char* filename)
{ FILE* file=fopen(filename,"r");
char line[200];
int i=0;
if(file==NULL)
return -1;
while(!feof(file))
{if(fgets(line,sizeof(line),file)!=NULL)
i++;
}
fclose(file);
return i;
}
char* getString(char* line)
{
printf("%s",line);
char* a=NULL;
a=(char*)malloc(sizeof(char)*strlen(line));
strcpy(a,line);
return a;
}
void readCSV(Brano* catalogo)
{
FILE* file=fopen("brani.csv","r");
char line[200]="";
int i;
if(file==NULL)
return ;
for (i=0;(!feof(file));i++)
{
if(fgets(line,sizeof(line),file)!=NULL)
{
if(line[strlen(line)-1]!='\0')//I remove the final \n
line[strlen(line)-1]='\0';
printf("%s",line);
catalogo[i].codice=NULL;
catalogo[i].codice=getString(strtok(line,";"));
printf("%s\n",catalogo[i].codice);
catalogo[i].nome=NULL;
catalogo[i].nome=getString(strtok(NULL,";"));
printf("%s\n",catalogo[i].nome);
catalogo[i].album=NULL;
catalogo[i].album=getString(strtok(NULL,";")); //the program often crashes here with i=0
printf("%s\n",catalogo[i].album);
catalogo[i].artista=NULL;
catalogo[i].artista=getString(strtok(NULL,";"));
printf("%s\n",catalogo[i].artista);
catalogo[i].track=atoi(strtok(NULL,";"));
printf("%d\n",catalogo[i].track);
catalogo[i].durata.minuti=atoi(strtok(NULL,";"));
catalogo[i].durata.secondi=atoi(strtok(NULL,";"));
catalogo[i].genere=stringToGenere(strtok(NULL,";"));
}
}
fclose(file);
}
int main(void) {
int scelta=0,num_utenti=0,size_catalogo=countRows("brani.csv");
int size_publicP=0;
if(size_catalogo<0)
{ MessageBox(NULL,"Failed to open \"brani.csv\" ","ERROR MESSAGE",MB_ICONERROR|MB_ICONSTOP);
return -1;
}
Brano* catalogo=NULL;
catalogo=(Brano*)malloc(sizeof(Brano)*size_catalogo);
Brano** pCatalogo=NULL;
Playlist** publicPlaylists=NULL;
Utente* loggedUser=NULL;
pCatalogo=(Brano**)malloc(sizeof(Brano*)*size_catalogo);
Utente* utenti=NULL;
readCSV(catalogo);
}
Your getstring() is wrong. It does not account for the terminating NUL character.
char* getString(char* line)
{
printf("%s",line);
char* a=NULL;
a=(char*)malloc(sizeof(char)*strlen(line));
strcpy(a,line);
return a;
}
should be
char *getString(char *line)
{
printf("%s",line);
char* a=malloc(1 + strlen(line));
strcpy(a,line);
return a;
}
Note that 1 + strlen() to account for the terminating NUL character.
Note also that sizeof(char) is always one by definition, and that you don't have to cast a void * in C.
Also, see strdup().
I newer in C language. I could not solve my problem. I have a input file, let's say input.txt. We know there are 4 column on every line. Nevertheless, we do not know how many lines are there. I give you sample input.txt:
Student,James,12,65
Teacher,Jane,23,60
Teacher,Michael,30,75
Student,Erric,15,73
First column can be 2 different things like student or teacher. 2nd column will be unique. No repeated names. 3rd column will be ages of the person's. 4th column will be weights. Also, I am trying to make 2D array. So, my goal is:
arrName = {{Student, James, 12, 65}, {Teacher,Jane,23,60}, {Teacher,Michael,30,75}, {Student, Erric, 15,73}}
I am trying to create like this array. The array must be dynamically. because we do not know how many lines are there. I could not split the every line by commas. I have tried strdot. how can I parse the lines with comma, and add them into 2D array? Also, I got confused about pointers. While creating 2D array, do we have to use like char **arrPtr;? Or using like *arrPtr is enough for creating 2D array?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define COLUMN 4 //We know that there are 4 column in chars.txt file.
int main(int argc, char const *argv[]) {
char *arrName;
int nameLines;
arrName = (char *) malloc( sizeof( char ) );
FILE *FileName;
FileName = fopen(argv[1], "r");
if (FileName == NULL) {
printf("The Name file could not open!\n");
exit(0);
}
else{
char c;
while ( (c == fgetc(FileName)) != EOF ) {
if (c == '\n') {
nameLines++;
}
}
printf("%d\n", nameLines);
}
return 0;
}
I could not continue after else statement. Can you help me?
You got a bunch of errors in your code like this for example.
while ( (c == fgetc(FileName)) != EOF ) { -> Comparison of constant -1 with boolean expression is always true
So let's start fresh. This is how I would read a comma separated file and dynamically allocate memory to an array of ´read´ objects. It's actually less lines of code then you would expect.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define COLUMNS 4
#define MAX_STRING_LENGTH 100 //Enter the maximum characters allowed as profession and name
typedef struct theDAta{
char type[MAX_STRING_LENGTH+1];
char name[MAX_STRING_LENGTH+1];
unsigned int age;
unsigned int weight;
}theData;
int main(int argc, char const *argv[]) {
theData* allDataPtr=malloc(1); //Pointer to all entries
theData currentData; //The current read data
int currentBlock=0; //the index currently 'active'
FILE *fp = fopen(argv[1], "r");
if (!fp) {
printf("The file you provided can't be read!\n");
exit(EXIT_FAILURE);
}
while (fscanf(fp, "%[^,],%[^,],%d,%d\n", currentData.type, currentData.name,¤tData.age,¤tData.weight) == COLUMNS) {
allDataPtr=realloc(allDataPtr, sizeof(theData)*(currentBlock+1));
if (!allDataPtr) {exit(EXIT_FAILURE);} //Memory allocation failure. Ok so here i lost my pointer to the previous memory.. However we let the OS garbage collect us.
memcpy(allDataPtr+currentBlock++, ¤tData, sizeof(currentData));
}
for (int x=0; x<currentBlock; x++) {
printf("Profession: %s\nName: %s\nAge: %d\nWeight: %d\n\n",allDataPtr[x].type,allDataPtr[x].name,allDataPtr[x].age,allDataPtr[x].weight);
}
fclose(fp);
free(allDataPtr);
return 0;
}
So what I do is to create a struct containing the stuff I want to populate from the file. Then I populate that object and extend the memory with the size of that object and then copy the read data to the end of that memory block.. That's basically it... Hope you get great grades :) !!
/Anders
EDIT
Was a bit bored this evening, so let's shave the code... And humm, well. This is not part of my official answer :-) but you could bling it like this (it's actually also skipping one layer of memory copy :) and the engine is 3 lines of C code if you define a line of C code delimiter as ';'->
typedef struct j{
char t[MAX_STRING_LENGTH+1];
char n[MAX_STRING_LENGTH+1];
unsigned int a;
unsigned int w;
}j;
int main(int argc, char const *argv[]) {
j* g;
int l=0;
FILE *h;
if((!(h=fopen(argv[1],"r"))||(!(g=malloc(sizeof(j))))))exit(-1);
while(fscanf(h,"%[^,],%[^,],%d,%d\n",g[l].t,g[l].n,&g[l].a,&g[l].w)==COLUMNS)if(!(g=realloc(g,sizeof(j)*(++l+1))))exit(-1);
for(int x=0;x<l;x++)printf("Profession: %s\nName: %s\nAge: %d\nWeight: %d\n\n",g[x].t,g[x].n,g[x].a,g[x].w);
fclose(h);
free(g);
return 0;
}