I am scanning strings as input , i am using getline to do so e.g
char *lajna=NULL;
size_t dlzka=0;
getline(&lajna,&dlzka,stdin);
and i want to read first char using fgetc , i tried to do
test=fgetc(lajna);
but it throws error
cannot convert ‘char**’ to ‘FILE* {aka _IO_FILE*}’ for argument ‘1’ to
‘int fgetc(FILE*)’
ciarka=fgetc(&lajna);
i checked it up and found nothing how to read chars from buffer like this, what is the right way?
See the prototype of fgetc():
int fgetc(FILE *stream);
It takes a FILE* as argument but you are passing char*. Hence, the error. (The error message suggests you actually have it like: test=fgetc(&lajna);)
To read characters from lajna, you don't need to use any function or special mechanism. You can simply index into it:
char ch = lajna[0]; // first char
and so on.
Or you can use a loop to read all chars.
for(i=0; lajna[i]; i++) { //until the null terminator '\0'
char ch = lajna[i];
}
Related
I need to read a filename from a text file.
Then I have to use it as an argument for fopen .
Consequently , I need to read it as a const char* because this is the type fopen accepts as a first argument. How do I do this?
I tried something like:
FILE *a;
a=fopen("a.txt","r");
const char *filename
fgets(filename,100,a);
image=fopen(filename,"rb");
Something is be wrong as I receive a segmentation fault when I do this. I think that the variable filename is not well-received by the fopen function.
You may have seen that fopen() takes an argument of type (const char *), but you need to be able to modify your string before you pass it to the function. Also, you need to allocate space for your string, and you might consider allocating space for more than 100 chars. The stdio.h header file contains the macro FILENAME_MAX, which expands to an integer constant of the correct size for an array that will hold the longest possible file name string on a system. For example, you can use char filename[FILENAME_MAX];. When the identifier filename is encountered in the call to fopen(), it decays to a pointer to char, which is converted to a pointer to const char, as per the function prototype.
Furthermore, fgets() keeps the newline when if fetches a line of text, so you will need to remove that. You should check the result of fgets(), as it returns a NULL pointer in the event of an error or if it is called at end-of-file; otherwise it returns a pointer to the first char in filename[].
FILE *a;
a=fopen("a.txt","r");
char filename[FILENAME_MAX];
char *ch;
ch = fgets(filename,FILENAME_MAX,a);
/* Remove trailing newline */
if (ch) {
while (*ch != '\0' && *ch != '\n') {
++ch;
}
if (*ch == '\n') { // replace '\n' with '\0'
*ch = '\0';
}
image=fopen(filename,"rb");
}
First, your seg fault likely comes from trying to use memory that you do not own. i.e. by creating the variable:
const char *filename;
And not giving it any memory ([c][m]alloc) before trying to use it.
Regarding your statement:
Consequently , i need to read it as a const char*.
Not necessarily.
The first argument of the fopen prototype: "FILE *fopen(const char *filename, const char *mode)" simply guarantees that the argument passed in that position will be treated as a const char * within the fopen function.
The argument can be passed using a simple char *, eg. either of these forms:
char *filename = {"somefilename.txt"};
or
char filename[80];
strcpy(filename, "somefilename.txt");
And, as mentioned in comments, and other answers, remove the newline character, \n before passing as an argument.
My program needs these functionalities:
NOTE: I did not include the codes for the numbers 1,2 & 4 since I already finished them. The 3rd one is my problem.
The program should continuously allow input from the user as long the user still wants to. (Dynamically)
Get the final grade of a student (average of frst_grade, scnd_grade, fnl_grade)
Get the number of students per college.
Get student name by inputting s_id.
My problem is how to compare the search input to the user input in s_college to get the number of students. The only way I know is by using strcmp() but it gives me this error: invalid conversion from 'char' to 'const char*' [-fpermissive]
So how do I compare these two to get the number of students per college?
#include<stdio.h>
#include<string.h>
#include<conio.h>
int i,n,sum,search,num=0,ctr=0;
char answer,choice,choice2,search2;
struct record{
int s_id;
char s_name[100];
char s_course;
char s_college[5];
int s_scoress;
}id[100],name[100],course,college[100],scores;
struct s_scores{
int frst_grade;
int scnd_grade;
int fnl_grade;
}first,second,final;
void ADD();
void COLLEGE();
void ID();
void COLLEGE(){
printf("Enter college (abbreviation only)");
scanf("%s",&search2);
for(i=0;i<num;i++){
if(strcmp(college[i].s_college,search2)==0);
ctr++;
}
printf("The number of students in %s is %d",search2,ctr);
Lets take a look at these (partial) lines:
char ..., search2;
...
scanf("%s",&search2);
...
...strcmp(college[i].s_college,search2)...
The variable search2 is a single character. Trying to put a string into it will write at least two character: The string you read plus the string terminator. That means you will write out of bounds.
You then use the character variable as an argument to strcmp which converts the contents of search2 into a pointer and uses that pointer as a pointer to a string.
Both of these problems will lead to undefined behavior.
Is search2 supposed to be a string? Then declare it as an array, like
char ..., search2[100];
If search2 is supposed to be a single character then first you need to read a single character
scanf("%c", &search2); // Note the changed format to read a single character
And then you need to change your comparison to not use strcmp.
You cannot use strcmp with what is not a null-terminated string. You can write
if(college[i].s_college[0] == search2 && college[i].s_college[1] == '\0')
Don't forget to remove the junk semicolon to have the if statement work.
Your search2 is just a character. You need a string
Perhaps declare search2 as follows:
char search2[50];
Also read up about scanf to prevent buffer overruns:
scanf("%49s", search2); // Do not go past the end of search2[50]
Well compiler tells you error: Variable search2 is char while s_college[5]; is array of chars. Function strcmp requires two arrays/pointers in order to work.
If search2 is only one byte then you can create: char Search2[2]; that would hold that one char and terminal null. But this would work only if search2 is one byte. If you however have to compare two array of chars where search2 is more then one byte, then you should probably think about dynamic allocation or create a static array char search2[some_length];.
this is not a complete 'answer', however, it does fix some of the major problems in the code:
Define your struct's like this;
struct s_scores
{
int frst_grade;
int scnd_grade;
int fnl_grade;
};
struct record
{
int s_id;
char s_name[100];
char s_course;
char s_college[5];
struct s_scores s_scoress;
};
struct record records[100];
Then access the individual fields similar to:
if( 1 != scanf( "%4s", records[i].s_college ) )
{
perror( "scanf for college abbreviation failed" );
exit( EXIT_FAILURE )
}
// implied else, scanf successful
// validate the college abbreviation
for( size_t j=0; j< (sizeof(collegesAbbrevationsTable)/(sizeof( *collegeAbbreviationsTable ); i++ )
{
if( strncmp( collegeAbbreviationsTable[j], records[i].s_college, 4)
{ // then found matching abbreviation
break; // exit 'validation' loop
}
}
Note: perror() found in stdio.h. exit() and EXIT_FAILURE found in stdlib.h.
Note: In C, when referencing an array, the result is a pointer to the first byte of that array, so in the call to scanf() must not use & when referencing the array s_college[].
`
declae search2 as char search2[10]; or char * search2;
Reason : string2 is a character variable and college is a null terminating char array.
Signature of stncmp id int strcmp(const char* s1, const char*s2);
So the function to properly you need to passs char* or char array(which is again a char*).
So I'm not very good with C but I'm designing a GLUT application that reads in a file that is not case sensitive. To make it easier I want to convert my strings to all lower case. I made a function makeLower that is modifying a variable that was passed in by reference.
I have a While Loop in the method makeLower that seems to get through part of the first iteration of the while loop and then the EXE crashes. Any tips would be great, thanks!
Output:
C:\Users\Mark\Documents\Visual Studio 2010\Projects\Project 1\Debug>"Project 1.e
xe" ez.txt
Line is #draw a diamond ring
Character is #
Then error "project 1.exe has stopped working"
Code:
void makeLower(char *input[]){
int i = 0;
printf("Line is %s\n", *input);
while(input[i] != "\0"){
printf("Character is %c\n", *input[i]);
if(*input[i] >= 'A' && *input[i] <= 'Z'){
*input[i] = tolower(*input[i]);
}
i++;
}
}
int main(int argc, char *argv[]) {
FILE *file = fopen(argv[1], "r");
char linebyline [50], *lineStr = linebyline;
char test;
glutInit(&argc, argv);
while(!feof(file) && file != NULL){
fgets(lineStr , 100, file);
makeLower(&lineStr);
printf("%s",lineStr);
//directFile();
}
fclose(file);
glutMainLoop();
}
I see more problems now, so I extend my comments to an answer:
You allocate an array of 50 characters, but tell fgets to get up to 100 characters, which might be fatal as fgets will overwrite memory not in the string.
When passing a C string to a function, you don't have to pass the address of the pointer to the string (&lineStr), the actual pointer or array is okay. This means you can change the makeLower function to void makeLower(char *input) or void makeLower(char input[]). Right now the argument to makeLower is declared as an array or char pointers, not a pointer to an array of char.
In the new makeLower I proposed above, you can access single characters either as an array (input[i]) or as a pointer plus offset (*(input + i). Like I said in my comment, the last version is what the compiler will probably create if you use the first. But the first is more readable so I suggest that.
Also in makeLower you make a comparison with "\0", which is a string and not a character. This is almost right actually: You should use input[i] != '\0'.
And finally this is how I would implement it:
void makeLower(char *input)
{
while (*input != '\0') /* "while (*input)" would also work */
{
*input = tolower(*input);
input++;
}
}
A few explanations about the function:
All char arrays can be converted to a char pointer, but not the other way around. Passing char pointer is the most common way to pass a string actually, as you can see from all standard functions that accepts strings (like strlen or strcpy.)
The expression *input dereferences (i.e. takes the value of what a pointer points to) the string. It is the same as *(input + 0) and so get the value of the first character in the string.
While the first character in the string is not '\0' (which technically is a normal zero) we will loop.
Get the first character of the string and pass it to the tolower function. This will work no matter what the character is, tolower will only turn upper case characters to lower case, all other characters will be returned as they already were.
The result of tolower copied over the first character. This works because the right hand side of an assignment must be executed before the assignment, so there will not be any error or problem.
Last we increase the pointer by one. This will make input point to the next character in the string. This works because input is a local variable, so operations on the pointer will not affect anything in the calling function.
This function can now be called like this:
char input[100];
fgets(input, sizeof(input), stdin);
printf("before: \"%s\"\n", input);
makeLower(input);
printf("after : \"%s\"\n", input);
Did you try while(*input[i] != "\0") instead of what you have ? For some reason you seem to pass to your function a pointer to pointer to char (*input[]) and &lineStr so it would make sense to dereference twice when you check for string terminator character "\0"....
Just a thought, hope it helps
I think the problem is that you don't know that the string is going to equal '\0' when you want it to. So you may be going out of bounds which is very likely that you don't know the length of the string.
As far as I understand things, it's fine to pass '\0' to tolower(). It's a valid unsigned char value, and tolower() simply returns the input character if it is not able to do any conversion.
Thus, the loop can be succinctly put as:
while(input[i] = tolower(input[i]))
++i;
This does one more call to tolower(), but it's shorter and (imo) quite clear. Just wanted to mention it as an alternative.
when it comes to C i am not a noob - i'm more like a total & complete stupid ignorant noob! i am trying to write a program to parse simple text files, and i would like to make it as general as possible(why i use getline). well here is my code:
//afile.c
#include <stdio.h>
#include <stdlib.h>
main( )
{FILE *fp1;
char *filename;
char **line;
size_t *sz;
int s;
filename = "n";
if ((fp1 = fopen(filename,"r")) == NULL ){printf("error...");return 1;}
do {
s = getline(&line,sz,fp1);
if (s != -1)
printf(" %s \n",line);//<-- %s seems to be wrong! %*s removes the gcc warning
} while (s != EOF);
fclose(fp1);}
I am pretty sure its some pointer allocation problem, but i really cant figure out where it is. i've found out that replacing %s with %s makes the compiler warning disappear, but it results in an infinity of \t(tabs) being written in the terminal.
By the way, the error message i get is:
stack smashing detected *: ./afile terminated
Segmentation fault
getline expects an argument of type char**, and you supplied &line, which is char***. Additionally, getline acts on the current value of the value its first arguments points to (so, the value of line), and you didn't initialize it. Change your program to:
char *line = NULL;
and it should be fine.
You failed to initialize the line variable, and it contains a random value. Readline probably tries to realloc() it.
UPDATE: the definition for line is also wrong, only one asterix needed, as pointed out by others.
int main(void )
{
FILE *fp1;
char *filename;
char *line = NULL; /* <- here */
size_t *sz;
int s;
...
}
Your pointer redirections are inconsistent. The variable line is declared:
char **line;
Which is a pointer to a pointer to a character, or a pointer to a string. getline() expects a pointer to a string, but you pass &line - a pointer to a pointer to a string.
Finally, your printf() format specified is %s, do it wants to format a string, but you give it a pointer to a string.
Long story short: remove an asterisk to create
char *line;
I have a char buffer which contains characters read from a file. I need to take this char buffer and find the first end of line character within it.
EOL characters in this case are \n,\r,\f.
Initially, I was planning to do the following:
// let's read into our buffer now...
char * m_pLineBuff;
if(!readCharBuf(m_pLineBuff, bytesToRead)) { report("Could not fill line buffer", RPT_ERROR, __PRETTY_FUNCTION__); }
// setup our newline candidates in an array
int iEOLChars[] = {'\n','\f','\r'};
// find the first instance of a newline character
int iEOLPosition = std::find_first_of(m_pLineBuff, m_pLineBuff+bytesToRead, iEOLChars, iEOLChars+3);
However, I apparently cannot pass a char pointer to the std::find_first_of method -- I can only pass an integer. The exact error the compiler provides me is:
error: invalid conversion from ‘char*’ to ‘int’
This seems strange to me, as I've defined the start and end locations of my char buffer and I do not understand why it could not iterate through them looking for the first occurrence of any of my EOL characters.
Any advice on how to resolve this? Is there a way to use find_first_of, or should I simply iterate through each position of the char buffer and check to see if the char at the location matches any of my EOL characters.
The "find_first_of" function I am referring to is this one: http://www.cplusplus.com/reference/algorithm/find_first_of/
Any assistance is always appreciated.
The function find_first_of returns, in this case, a pointer, not an index, so try:
char *iEOLPosition = std::find_first_of(m_pLineBuff, m_pLineBuff+bytesToRead, iEOLChars, iEOLChars+3);
I think the problem is a type mismatch here:
char * m_pLineBuff;
int iEOLChars[] = {'\n','\f','\r'};
Try it declaring your iEOLChars as a char array.
Check your first_first_of function I think it can never have 4 parameters
Refer first_first_of