C - Error with function parameters when it is being called - c

When I am trying to call a function, the parameters that I have tried so far have just resulted in the terminal saying that 'too few arguments to function' and what I can tell that what it wants written there is the parameters from when it was declared. I have read a few different documents about this and what the calling parameters are and the different between calling by value or by reference but I am still not able to figure out the problem.
Below is the main section of code that has the call functions in it along with some variables.
int main(int argc, char *argv[])
{//main()
char *listwords;
processfile(listwords); //<- this is the line that is causing the problem
WordList mylist;
initialiselist(&mylist);
addword(&mylist, createfillednode(listwords));
printlist(&mylist);
}//main()
Below here is the processfile() function:
//process the file
void processfile(WordList *wordList, int argc, char *argv[])
{//process file
//file pointer
FILE *f;
//open the file
f = fopen(argv[1], "r");
//check it opened correctly
if(f == NULL)
{//if statement
printf("cannot read file\n");
}//if statement
fseek(f, 0, SEEK_END);
//declare variables
char *listwords;
long size = ftell(f);
char *token;
//seek beginning of file
fseek(f, 0, SEEK_SET);
//set the size of array to the file size
listwords = (char*)malloc(size+1);
listwords[size] = '\0';
//reads the data from the file
fread(listwords, size, 1, f);
int i;
for(i=0; (token = strsep(&listwords, " ")); i++)
{//for loop replace certain characters with spaces
if (token != ".")
{
//pointer from the token to the dictionary
wordList->token;
}else if (wordList->token != "!")
{
wordList->token;
}else if (token != "?")
{
wordList->token;
}else if (token != "\"")
{
wordList->token;
}else if (token != ","){
wordList->token;
}else
{
wordList->token;
}
//increment token to the next word
token++;
}//for loop replace certain characters with spaces
fclose(f);
return;
}//process file
Thanks.

You've declared processfile to take three arguments.
void processfile(WordList *wordList, int argc, char *argv[])
But you're only giving it one.
processfile(listwords);
And it's also the wrong type. It should be a WordList, but instead it's a string (char *).
char *listwords;
In C, you have to give a function exactly the right number of arguments and of the right type (C can do some type casting, but it's strictly defined and usually about numbers).
With one exception. Variadic arguments let you pass an undefined number of arguments. This is how functions like printf work. In general you should avoid variadic functions as much as possible, they add complexity and defeat type checking.
In your case, processfile only needs two arguments: a list of words, and a filename to open. argc is never used, and knowing that the filename is coming from argv[1] puts an unnecessary restriction on the function.
void processfile(WordList *wordList, char *filename)
Then it can be called with...
WordList *wordList = ...generate the wordlist somehow...
processfile(wordList, argv[1]);

The processfile() function takes three arguments according to your definition:
void processfile(WordList *wordList, int argc, char *argv[])
However, in your main() function you're only passing a single argument:
processfile(listwords)
To make this work like you'd want it to, you'd have to pass all three arguments; your listwords, as well as the counter and vector for arguments:
processfile(listwords, argc, argv)
However, in general, this is usually not a great idea programatically speaking as far as I know. A function should typically take some sort of specialized input and return a relevant value, and not the input from the command line - that should be parsed far ahead of the function actually being called. Check out getopt or argparse to process arguments correctly, determine what parameters you really want to pass to processfile() and pass only the arguments that would be relevant to the file in which you're attempting to process. From reading your code, probably just the file descriptor, which should be opened in main() after some argument-parsing error correction:
void processfile(WordList *wordList, FILE *f)
{
fseek(f, 0, SEEK_END);
//declare variables
char *listwords;
long size = ftell(f);
char *token;
fseek(f, 0, SEEK_SET);
listwords = (char*)malloc(size+1);
listwords[size] = '\0';
fread(listwords, size, 1, f);
- - - - - - - - - 8< - - - - - - - - -
This way, you can open your file elsewhere, and re-use processfile() on any open file called in any context, making it a more robust function.

Related

"Invalid argument" when creating a file

Could you help me with the creation of a text file as right now the *fp pointer to the file is returning NULL to the function fopen ?
Using the library errno.h and extern int errno I get "Value of errno: 22".
if (!fp)perror("fopen") gives me "Error opening file: Invalid argument".
In my main function I enter the name of the file:
void main()
{
float **x;
int i,j;
int l,c;
char name_file[30];
FILE *res;
/* some lines omitted */
printf("\nEnter the name of the file =>");
fflush (stdin);
fgets(name_file,30,stdin);
printf("Name of file : %s", name_file);
res=creation(name_file,l,c,x);
printf("\nThe created file\n");
readfile(res,name_file);
}
The function to create the text file:
FILE *creation(char *f_name,int l, int c, float **a) // l rows - c colums - a array
{ FILE *fp;
int i,j;
fp = fopen(f_name,"wt+"); // create for writing and reading
fflush(stdin);
/* The pointer to the file is NULL: */
if (!fp)perror("fopen"); // it's returning Invalid argument
printf("%d\n",fp); //0 ??
if(fp==NULL) { printf("File could not be created!\n"); exit(1); }
fflush(stdin);
for(i=0;i<l;i++)
{
for(j=0;j<c;j++)
{
fprintf(fp,"%3.2f",a[i][j]); // enter every score of the array in the text file
}
fprintf(fp,"\n");
}
return fp;
}
Function to read the file and check if it is correct:
**void readfile(FILE *fp,char *f_name)**
{
float a;
rewind(fp);
if(fp==NULL) { printf("File %s could not open\n",f_name); exit(1); }
while(fscanf(fp,"%3.2f",&a)!= EOF)
printf("\n%3.2f",a);
fclose(fp);
}
There are quite a few wrong things your code.
1.
The correct signatures of main are
int main(void);
int main(int argc, char **argv)
int main(int argc, char *argv[])
See What are the valid signatures for C's main() function?
2.
The behaviour of fflush(stdin) is undefined. See Using fflush(stdin).
fflush works with output buffers, it tells the OS that is should write
the buffered content. stdin is an input buffer, flushing makes no sense.
3.
Use fgets like this:
char name_file[30];
fgets(name_file, sizeof name_file, stdin);
It's more robust using sizeof name_file because this will give you always
the correct size. If you later change the declaration of name_file to
an char array with less than 30 spaces, but forget to change the size parameter in fgets, you
might end up with a buffer overflow.
4.
You are passing to creation the uninitialized pointer p that is pointing
to nowhere. In said function you cannot read nor write with the pointer a.
You need to allocate memory prior to the call of creation. At least judging
from the code you posted.
5.
fgets preserves the newline ('\n') character, so
name_file is containing the newline character. I really don't know if newline
is allowed in file names. I did a google search but found conflicting answers.
I don't think that you want to have newlines in your file names, anyway. It's
best to remove it before passing it to fopen (which might be the reason for
the error 22):
char name_file[30];
fgets(name_file, sizeof name_file, stdin);
int len = strlen(name_file);
if(name_file[len - 1] == '\n')
name_file[len - 1] = 0;

Program containing fscanf fails to compile

As someone who is pretty new to C, I'm still trying to wrap my head around the massive amount of functions.
One in particular is giving me a lot of problems.
I'm trying to use fscanf but I keep getting a strange error:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char **argv)
{
FILE *dict = fopen(argv[1], "r");
// skim through every word in a dictionary
while (fscanf(dict, "%s", word) != EOF)
{
// iterate through every chracter in the word
for (int i = 0, int j = strlen(word); i < j; i++)
{
printf("%c", word[i]);
}
printf("\n");
}
return 1;
}
I'm trying to create a loop that skims through every single word in a file that is just a series of words.
I'm assuming that the code I've written does just that, storing each word in a string called "word".
Unfortunately, I keep getting this error:
error: format specifies type 'char *' but the argument has type
'<dependent type>' [-Werror,-Wformat]
error: use of undeclared identifier 'word'
Even if I try to initialize a char * variable "word", some other error just keeps popping up. Maybe I don't fully understand how fscanf works, could anyone provide some clearance?
How can I make the above program compile?
Because you are using C, this answer does not care about infamous "buffer overflow error" but please keep in mind that.
You need to declare 'word' variable before you use 'fscanf'. It looks like...
const size_t MAX_WORD_LEN=256;
char word[MAX_WORD_LEN];
then, you can.
while (fscanf(file, "%s", word) != EOF)
{
}
Here, the maximum 'word' length is 255 characters (without terminating NULL character). So in your file one single word length cannot be over 255 characters (in most cases, it should be fine).
The whole program most likely be as follow:
#include <stdio.h>
const char* const usage_msg = "Usage: program_name input-file\nInput file contains words in English or some languages. \n";
const char* const fopen_err = "\nUnable to open file: ";
const size_t MAX_WORD_LEN = 256;
int main(int argc, char *argv[]) {
if (argc != 2) {
fprintf(stderr, "%s", usage_msg);
return -1;
}
else {
/* if argv[1] contains something that is not supposed to be, it will be infamous buffer overflow. */
/* any validation on argv[1] is welcomed here */
FILE *pf = fopen(argv[1], "r");
char word[MAX_WORD_LEN];
if (pf == NULL) {
fprintf(stderr, "%s%s", fopen_err, argv[1]);
return -2;
}
/* overflow can be avoided by specifying width 255 to %s */
while (fscanf(pf, "%255s", word) != EOF) {
printf("%s\n", word);
}
}
return 0;
}

Creating a File to array function

Currently I have the argc, argv and temp pieces placed in to be passed, and when I compile it returns no errors, but when I call the function later in the program and pass it a char array. It returns a stack dump. From what I have learned so far arrays cannot be passed back from a function and that is why I have passed the pointers.
int In2File(int argc, char *argv[], char *temp[] ){
if (argc == 2) { //open file
FILE *user_file;
user_file = fopen(argv[1], "r");
if (user_file == NULL) {
printf("No data was found.\nEnd(Error 1)");
exit(2);
}
else {
int g = 0;//temp counter to load
char c = 0;
while ((c = fgetc(user_file)) != EOF && g <= tmplng - 1) { //Used Fgetc instead of fgets because Fgetc allows me to read
*temp[g] = c; //until the end of the file and read each character. Even if there is an \n character.
g++; // The second g < tmplng-1 is used to make sure that the \0 can be placed into the array.
}
printf("%s\n", temp);
fclose(user_file);//Closed the txt file that was loaded by user in args(1)
printf("\nFile Loaded.\n");
}
}
else if (argc > 2) { // Will exit if arguments are greater than 2.
printf("Format: %s 'filename'", argv[0]);
exit(1);
}
else {
printf("File not provided. Enter information:\n");//If the user doesnt provide a file allow manual input.
fgets(*temp, tmplng, stdin);
}
}
In2File(argc,argv,temp);
Anyone have an idea as to where I went wrong with this function? I read a few similar posts but they were for C++ and Python. Which I havent learned C++ as yet and python is different to this beast called C.
Edit:
const int tmplng = 1000; //The only variables needed
char temp[tmplng]; //
char temp2[tmplng]; //
printf("Starting....\n"); //Used for testing debugging.
The third parameter to the function doesn't match what the function is expecting. You're passing in a char [] (which decays to a char *), while the function expects char *[] (equivalently char ** as a function parameter).
The definition of the third parameter doesn't match how you intend to use it, which is as a character array.
Get rid of the extra level of indirection on the parameter, and adjust the function accordingly.
int In2File(int argc, char *argv[], char temp[] ){
...
while ((c = fgetc(user_file)) != EOF && g <= tmplng - 1) {
temp[g] = c;
g++;
}
This declaration of temp:
char temp[tmplng];
... does not go with this call ...
In2File(argc,argv,temp);
... to this function ...
int In2File(int argc, char *argv[], char *temp[] );
The function expects its third argument to be a pointer to a pointer to char *, but what it receives is a pointer to char. When it then tries to assign the character read ...
*temp[g] = c;
That attempts to interpret the gth element of temp (itself interpreted as a char **) as a char *, to dereference that pointer, and to assign c to that location. That is highly unlikely to be a valid memory access.
It looks like you want to declare the third argument of In2File as either char *temp or char temp[], which are equivalent, and to write to it as temp[g] = c.
ALSO, as an aside, note that your
printf("%s\n", temp);
is problematic because you do not ensure that temp is null-terminated. And inasmuch as you support reading up to the very last byte, you don't have room to terminate it.
As numerous folks are pointing out in the comments, your code would be much easier to understand if you employed "early exit" for your error conditions.
It would also be a better separation of concerns to have main deal with the program arguments and let In2File just deal with a file pointer.
int main( int argc, char *argv[] ) {
FILE *fp;
if( argc == 2 ) {
fp = fopen(argv[1], "r");
if ( fp == NULL ) {
fprintf(stderr, "Couldn't open %s: %s", argv[1], strerror(errno));
exit(2);
}
}
else if( argc > 2 ) {
fprintf(stderr, "Usage: %s <optional filename>", argv[0]);
exit(1);
}
else {
fp = stdin;
}
char *lines = In2File(fp);
printf("%s\n", lines);
free(lines);
}
Note that stdin is a file pointer just like anything you opened with fopen. I've also used strerror and errno to provide the reason the file didn't open.
Now In2File just takes a file pointer. Also note that I have it returning the content, not passing in a preallocated array. This is because when reading from input you never know how much input you're going to get. You either must stop reading before you run out of space, or allocate more memory. You can't reallocate stack memory, so it's best to let In2File control allocating memory. It also avoids having to pass around a global variable.
Once that's done, In2File becomes much simpler.
static char *In2File( FILE *fp ){
size_t read_size = 1024;
/* Don't forget space for null */
char *content = calloc( read_size + 1, sizeof(char) );
fread( content, sizeof(char), read_size, fp );
return content;
}
Rather than step through a character at a time, I've used fread to read a block from the file not larger than the amount I've allocated. Memory reallocation is a topic for another time.

Storing line by line from text file into char array using char pointer

Hello I writing a program to execute commands from the text file. The code below is used to store line by line into char array first.
So I expect it to do something like
args[0]= The first line of text file
args[1]= The second line of text file
... and so on
In my code, all of the arrays would be covered by the last array. And I can't figure out why.
Can anyone help me fix this and tell me why my code does that. Also I need to keep char *args[]. cos I would use it with execvp() later.
int main(int argc, const char * av[]) {
FILE *fp;
fp = fopen(av[1],"r");
int n_lines=0;
char in[100],*args[16];
int size=sizeof(in);
while(fgets(in, size, fp)!=NULL){
args[n_lines] = in;
printf("Args[0] is %s\n",args[0]);
n_lines++;
}
printf("Now Args[0] is %s\n",args[0]);
}
Output
zacks-MacBook-Pro:prac2 zack$ ./a.out test
Args[0] is ./addone
Args[0] is ./add
Now Args[0] is ./add
int n_lines=0;
char in[100],*args[16];
int size=sizeof(in);
while(fgets(in, size, fp)!=NULL){
args[n_lines] = in;
printf("Args[0] is %s\n",args[0]);
n_lines++;
}
The value of in is overwritten on each iteration, you need to reserve space (using malloc->strcpy or strdup if available):
char in[100], *args[16];
while (fgets(in, sizeof in, fp) != NULL) {
args[n_lines] = strdup(in);
...
n_lines++;
}
Or use a 2D array (an adjust of sizeof is required in fgets):
char in[16][100];
while (fgets(in[n_lines], sizeof in[0], fp) != NULL) {
...
n_lines++;
}
And as pointed out by #MichaelWalz in comments: you'll run into problems if your file has more then 16 lines.
Change to
while (fgets(in[n_lines], sizeof in[0], fp) != NULL) {
...
if (++n_lines == (sizeof in / sizeof in[0])) break;
}

Why am I segfaulting?

I'm very new to C, I am attempting to read the contents of one file character by character and output them to the stream. But even with my fopen() command commented out I receive segfault (core dumped).
I must run a command: ./a.out < testWords.in > myOut.txt to execute my file properly.
Here is what I have so far:
#include <stdio.h>
void main(char *fileName[])
{
printf("filename is %s.\n",fileName[0]);
//Get file based on a string inputed
FILE *fp=fopen(fileName[0],"r"); //Fetches our file as read only
char ch;
int lineCount = 0;
int wordCount = 0;
int charCount = 0;
//Failed to find/open file. NULL character.
if (fp == 0) printf("Woops! Couldn't open file!\n");
//While not at end of file, grab next char.
else while( (ch=fgetc(fp)) != EOF)
{
if (ch == '\n') //on newline
{
//Prints (charCount,wordCount)\n lineCount:
printf("(%d,%d)%c%d:",charCount,wordCount,ch,lineCount);
charCount = 0;
lineCount += 1;
}
else printf("%c",ch); //mirrors char.
}
fclose(fp); //Closes file (gotta be tidy!)
}
You can't just invent a way to call main. You need to use one of the standard ways, like this:
int main(int argc, char *argv[])
{
if (argc < 2) {
fprintf(stderr, "Missing filename\n");
return -1;
}
FILE *fp = fopen(argv[1], "r");
// ...
}
And note that argv[0] contains the program name (if available; if not it contains an empty string).
Your program segfaulted because you received the int argc argument into your char *filename[] parameter. If you ran the program with a single command line parameter, the value passed in as the first argument would have been 2, which is not a valid pointer value. The expression filename[0] dereferences that address and causes a segfault.
Any time you get a segfault in C, you should smell a bad pointer or address in an argument list. In this particular case., the signature of main is always int main(int argc, char** argv). Yours isn't.
What you want is
int main(int argc, char ** argv) {
...
FILE * fp = fopen(argv[1]); // Quiz: why argv[1]? What's argv[0]?
You're getting away with it in the compiler because, basically, luck.
I also notice in your example call, there's actually no argument in the argument list, because you're using redirection.
Use:
int main(int argc, char* argv[])
And use argv[1] as fileName.
Main function must receive always that two parameters.

Resources