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.
Related
I am using OpenGL, don't worry my problem is with C and not something related to OpenGL. In OpenGL, we have something called shaders. It is a text file. All I want to do is to read that text file and pass it to a function that accepts only const char * const*. (eg. func(&shaderSource) and shaderSource must be const char* shaderSource.). I just want this terminology with multiple files. Can I? I saw people doing this with C++, but I chose C over C++ in the project. Here is some of my failed attempts.
char vertexShaderContent[1000] = readfile("Shader/default.frag.txt");
const char *vertexShaderSource;
strcpy(vertexShaderSource, vertexShaderContent);
Here I tried to get a new variable (By the way this is in the main function) that executes the function and gets the return value of that function. Now I did copy that string (using strcat) to assign the value of vertexShaderContent to vertexShaderSource. By the way here is my readfile code:
char *readfile(const char* filename) {
char *res = malloc(sizeof(char *) * 100);
char *word = malloc(sizeof(char *));
FILE *file = fopen(filename, "r");
while (fgets(word, sizeof(word), file) != NULL) {
strcat(res, word);
}
strcat(res, "\n\0");
fclose(file);
return res;
}
Summary
All my problem is that I want to pass a char* to a function accepting const char*s. If I can't, is there is any way I can get this 'multiple' files to work?
Thanks.
In char vertexShaderContent[1000] = readfile("Shader/default.frag.txt");, readfile returns a pointer to char, but vertexShaderContent is an array of char. To initialize an array, one needs to provide values for each element to be initialized. A pointer to char is not a correct type for initializing char values.
What may work here is char *vertexShaderContent = readfile("Shader/default.frag.txt");. That defines vertexShaderContent to be a pointer to the memory returned by readfile. However, it is not clear what you want to do, because the code that follows it is confusing:
const char *vertexShaderSource;
strcpy(vertexShaderContent, vertexShaderSource);
This would overwrite the data at vertexShaderContent with new data, so it loses the data that readfile returned. And it attempts to copy from vertexShaderSource, but vertexShaderSource has not been set to point to anywhere. Its value is indeterminate. This strcpy cannot do anything useful. Since we do not know what you are trying to do here, we cannot recommend a solution.
These lines in readfile are incorrect:
char *res = malloc(sizeof(char *) * 100);
char *word = malloc(sizeof(char *));
The first allocates space for 100 char *. To allocate space for 100 char, use char *res = malloc(100 * sizeof *res);.
The second allocates space for one char *. But it looks like you want space for one “word”, which would likely be some varying number of characters. Maybe you would want to start with space for at least 100 characters:
char *word = malloc(100 * sizeof *word);
That could help get the code going at first, although a good eventual solution would ensure the allocated spacer could not be overflowed.
In strcat(res, word), the data pointed to by res has not yet been initialized. Before using strcat, you must have some string in the destination. That can be the empty string, which you can create by putting a null terminator character in res:
*res = '\0';
All my problem is that I want to pass a char* to a function accepting const char*s.
Nothing in the question shows any attempt to pass a char * for a const char * parameter that would not work, except for the issues noted above.
I am making my own version of make. I allow for some arguments to be passed via command line.
I am working on it in chunks. I am setting the fileName right now
I have the following code
int main(int argc, char *argv[]) {
char *fileName = NULL;
char fileFlag[2];
strcpy(fileFlag, "-f");
printf("%s\n", fileFlag);
if (argc == 1) {
fileName = (char *) malloc(sizeof("Makefile"));
strcpy(fileName, "Makefile");
printf("One arg %s\n", fileName);
}
printf("\n%s", fileName);
return 0;
}
When it runs I get the following output.
-f
One arg Makefile
Shouldn't it print another line?
The first problem is
strcpy(fileFlag, "-f");
fileFlag is one element short of the required space, you need to have 3 element-array to store "-f" along with the terminating null. In this case, as per the strcpy() behaviour,
The strcpy function copies the string pointed to by s2 (including the terminating null
character) into the array pointed to by s1. [...]
So, including the null-character, the size of the source is 3, so is needed for the destination also. Otherwise, you'll be accessing out of bound memory which invokes undefined behavior.
That said,
please see this discussion on why not to cast the return value of malloc() and family in C..
Always check for the success of malloc() before using the returned pointer.
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];
}
I'm trying to get input from the user while allocating it dynamically and then "split" it using strtok.
Main Questions:
Im getting an infinite loop of "a{\300_\377" and ",".
Why do i get a warning of "Implicitly declaring library function "malloc"/"realoc" with type void"
Other less important questions:
3.i want to break, if the input includes "-1", how do i check it? As you can see it breaks now if its 1.
4.In the getsWordsArray() i want to return a pointer to an array of strings. Since i dont know how many strings there are do i also need to dynamically allocate it like in the getInput(). (I dont know how many chars are there in each string)
int main(int argc, const char * argv[])
{
char input = getInput();
getWordsArray(&input);
}
char getInput()
{
char *data,*temp;
data=malloc(sizeof(char));
char c; /* c is the current character */
int i; /* i is the counter */
printf ("\n Enter chars and to finish push new line:\n");
for (i=0;;i++) {
c=getchar(); /* put input character into c */
if (c== '1') // need to find a way to change it to -1
break;
data[i]=c; /* put the character into the data array */
temp=realloc(data,(i+1)*sizeof(char)); /* give the pointer some memory */
if ( temp != NULL ) {
data=temp;
} else {
free(data);
printf("Error allocating memory!\n");
return 0 ;
}
}
printf("list is: %s\n",data); // for checking
return *data;
}
void getWordsArray(char *input)
{
char *token;
char *search = " ,";
token = strtok (input,search);
while (token != NULL ) {
printf("%s\n",token);
token = strtok(NULL,search);
}
}
EDIT:
i noticed i forgot to "strtok" command so i changed it to token = strtok(NULL,search);
I still get wierd output on the printf:
\327{\300_\377
Change:
int main(int argc, const char * argv[])
{
char input = getInput();
getWordsArray(&input);
}
to:
int main(int argc, const char * argv[])
{
char *input = getInput();
getWordsArray(input);
}
with a similar to the return value of getInput():
char *getInput()
{
// ...
return data;
}
In your code, you were only saving the first character of the input string, and then passing mostly garbage to getWordsArray().
For your malloc() question, man malloc starts with:
SYNOPSIS
#include <stdlib.h>
For your getchar() question, perhaps see I'm trying to understand getchar() != EOF, etc.
Joseph answered Q1.
Q2: malloc and realoc returns type void *. You need to explicitly convert that to char *. Try this:
data = (char *) malloc(sizeof(char));
Q3: 1 can be interpreted as one character. -1, while converting to characters, is equivalent to string "-1" which has character '-' and '1'. In order to check against -1, you need to use strcmp or strncmp to compare against the string "-1".
Q4: If you are going to return a different copy, yes, dynamically allocate memory is a good idea. Alternatively, you can put all pointers to each token into a data structure like a linked list for future reference. This way, you avoid making copies and just allow access to each token in the string.
Things that are wrong:
Strings in C are null-terminated. The %s argument to printf means "just keep printing characters until you hit a '\0'". Since you don't null-terminate data before printing it, printf is running off the end of data and just printing your heap (which happens to not contain any null bytes to stop it).
What headers did you #include? Missing <stdlib.h> is the most obvious reason for an implicit declaration of malloc.
getInput returns the first char of data by value. This is not what you want. (getWordsArray will never work. Also see 1.)
Suggestions:
Here's one idea for breaking on -1: if ((c == '1') && (data[i-1] == '-'))
To get an array of the strings you would indeed need a dynamic array of char *. You could either malloc a new string to copy each token that strtok returns, or just save each token directly as a pointer into input.
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;