I am attempting to grab a title from a text file in a way that is completely new to me. My code is set up as follows:
struct sequence
{ char *name;
char *sequence;
int sequencelen;
};
int main(int argc, char *argv[])
{
struct sequence *newseq;
getsequence("test.txt", newseq);
}
void getsequence(const char *file, struct sequence *seq)
{
FILE *fp = fopen(file, "r");
struct sequence *seqptr = malloc(sizeof(*seq));
char c;
if (!fp)
{
exit(1);
}
while ((c = fgetc(fp)) != "\n")
{
if (c == '>')
continue;
strcat(seqptr -> name, c);
}
printf("Name: %s", seqptr -> name); //Expected output: this_is_a_new_sequence_title
}
The structure for the text file is as follows:
>this_is_a_new_sequence_title
Using structs in this way is, like I said, new to me, but seeing how it is another way to use them I would like to know how to do it. I am unsure, however, if I'm using them correctly, especially with regards to the strcat function.
Do I have to dynamically allocate memory for the struct's member variables, and, if so, how would I go about doing that? Or do I just have everything horribly wrong?
You're never allocating memory for the string. So when you call strcat(), the destination string is uninitialized memory, leading to undefined behavior.
Also, the 2nd argument to strcat() is a string, not a character. That's more undefined behavior as the library function interprets the single character as the address of a string.
You need to initialize storage space for sequence when you allocate it. Also, for code like this (dynamic strings) it's good to separate "allocated room" from "string length", and store both.
Related
int main(int argc, char *argv[])
{
char *line, buffer[1024];
char *token, *setValue, *pointer;
FILE *fp = fopen("file", "r");
if(fp == NULL)
{
printf("File was unable to be opened.\n");
}
fgets(buffer,1024,fp);
printf("%s\n", buffer);
while(fgets(buffer,1024,fp) != NULL)
{
strcpy(token, strsep(&buffer, ","));
printf("%s\n", token);
}
return 0;
}
I'm having a bit of trouble understanding how strsep works.. I've looked up tutorials for it, but when I try different methods, it keeps just not being able to compile.. It'd be appreciated if someone helped me understand the syntax and the way it works. Thank you.
**EDIT: 'Buffer' contains "I,was,in,the,school"
****EDIT x2: I'm trying to parse a csv file, and using the basic 'Buffer' I created on my desktop as an example. I want to separate the different words by the respective comma.
regarding:
strcpy(token, strsep(&buffer, ","));
the variable token is ONLY a pointer, it has not been set to point to any memory that the application owns. Therefore, it will contain what ever trash was on the stack at the location of the variable.
The result is undefined behavior and it can lead to a seg fault event.
Suggest declare token as
char token[ 1024 ];
so it is large enough to hold a maximum length string (I.E. the length of buffer[]
as it the above wasn't bad enough:
the posted code is missing the statement: #include <string.h> so as to expose the prototype for the function strsep() so the compiler will make the assumption that the parameters and returned value are int rather than their actual types.
The posted code is also missing the statement: #include <stdio.h> so the parameter and return types for the functions: fopen(), fgets(), printf()and even the struct type forFILEare assumed to beint` rather than their actual types.
Switching to C from Java, and I'm having some troubles grasping memory management
Say I have a function *check_malloc that behaves as such:
// Checks if malloc() succeeds.
void *check_malloc(size_t amount){
void *tpt;
/* Allocates a memory block in amount bytes. */
tpt = malloc( amount );
/* Checks if it was successful. */
if ( tpt == NULL ){
fprintf(stderr, "No memory of %lu bytes\n", amount);
exit(1);
}
return tpt;
}
I also have the following variables to work with:
FILE *f = fopen("abc.txt", "r"); // Pointer to a file with "mynameisbob" on the first line and
// "123456789" on the second line
char *pname; // Pointer to a string for storing the name
}
My goal is to use *check_malloc to dynamically allocate memory so that the String pointed to by *pname is just the correct size for storing "mynamisbob", which is the only thing on the first line of the text file.
Here is my (failed) attempt:
int main(int argc, char *argv[]){
FILE *f = fopen("abc.txt", "r"); // A file with "mynameisbob" on the first line and
// "123456789" on the second line
char *pname; // Pointer to a string for storing the name
char currentline[150]; // Char array for storing current line of file
while(!feof(f)){
fgets(currentline,100,f);
pname = ¤tline;
}
But I know this probably isn't the way to go about this, because I need to use my nice check_malloc* function.
Additionally, in my actual text file there is a "<" symbol before the name on the first line.But I just want the *pname to point to a String saying "mynameisbob" without the "<" symbol. This isn't that important now, it just is reinforcement to me that I know I can't just set the pointer to point straight to currentline.
Can anyone help me fix my thinking on this one? Thanks a lot.
In C you need to copy chars, not the "strings" (which are just pointers). Check out strcpy() and strlen(). Use strlen() to determine how long the line actually is which fgets has read, then use your malloc() to allocate exactly that (plus 1 for the 0). Then copy the chars over with strcpy().
There are several problems in your code, see my comments in this example:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// Checks if malloc() succeeds.
void *check_malloc (size_t amount) {
void *tpt;
/* Allocates a memory block in amount bytes. */
tpt = malloc( amount );
/* Checks if it was successful. */
if (tpt == NULL) {
fprintf (stderr, "No memory of %lu bytes\n", amount);
exit (EXIT_FAILURE);
}
return tpt;
}
// To avoid subtle errors I have defined buffer size here
#define BUFFER_SIZE 150
// I have used the (void) version of main () here, while not strictly neccessary, you where not using argc and argv anyway, so the can be left out in this case
int main (void) {
// It might be a good idea to make the filename a char[] as well, but I leave that as an exercise to the reader.
FILE *f = fopen("abc.txt", "r"); // A file with "mynameisbob" on the first line and
// "123456789" on the second line
// You have to check whether the file was *actually openend*
if (f == NULL) {
fprintf (stderr, "Could not open file abc.txt\n"); // '"...%s\n", filename);' might better.
exit (EXIT_FAILURE);
}
char *pname; // Pointer to a string for storing the name
char currentline[BUFFER_SIZE]; // Char array for storing current line of file
while(!feof (f)) {
char *res = fgets (currentline, BUFFER_SIZE, f);
// fgets returns NULL when EOF was encountered before the next '\n'
if (res) {
size_t read = strlen (res);
// The line might have been empty
if (read) {
// Better use "sizeof *varname", while char is always 1 byte it is a good practice
pname = check_malloc ((read + 1) * sizeof *pname); // + 1 because we have to provide an extra char für '\0'
strncpy (pname, currentline, read); // You have to use strcpy or strncpy to copy the contents of the string rather than just assigning the pointer
// What was allocated must be freed again
free (pname);
}
}
}
fclose(f); // Always close everything you open!
return EXIT_SUCCESS;
}
Actually you really don't have to use pname in this simple case, because currentline already contains the line, but since you're trying to learn about memory management this should give you a general idea of how things work.
In your code you had this line:
pname = ¤tline;
There are two problems here:
As already mentioned in my code assigning currentline to pname only copies the pointer not the contents.
The correct assignment would be pname = currentline (without the address operator &), because currentline is also a pointer under the hood (it behaves like char *currentline even though it's statically allocated).
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.
I have a char that is given from fgets, and I would like to know how I can convert it into a char*.
I am sure this has been posted before, but I couldn't find one that was doing quite what I wanted to do. Any answer is appreciated.
EDIT:
Here is the code.
char *filename = "file.txt";
FILE *file = fopen(filename, "r");
if(file != NULL) {
char line[260];
char *fl;
while(fgets(line, sizeof line, file) != NULL) {
// here I combine some strings with the 'line' variable.
str_replace(line, "\"", "\"\""); // A custom function, but it only takes char*'s.
}
printf(fl);
printf("\n");
} else {
printf(" -- *ERROR* Couldn't open file.\n");
}
Well, first of all, line is an array of chars and so can be manipulated in much the same way as a char * (See comp.lang.c FAQs for important differences), so you don't need to worry about it.
However, in case you want an answer to the general question...
The & operator is what you need:
char c;
char *pChar = &c;
However, bear in mind that pChar is a pointer to the char and will only be valid while c is in scope. That means that you can't return pChar from a function and expect it to work; it will be pointing to some part of the heap and you can't expect that to stay valid.
If you want to pass it as a return value, you will need to malloc some memory and then use the pointer to write the value of c:
char c;
char *pChar = malloc(sizeof(char));
/* check pChar is not null */
*pChar = c;
Using the & operator will give you a pointer to the character, as Dancrumb mentioned, but there is the problem of scope preventing you from returning the pointer, also as he mentioned.
One thing that I have to add is that I imagine that the reason you want a char* is so that you can use it as a string in printf or something similar. You cannot use it in this way because the string will not be NULL terminated. To convert a char into a string, you will need to do something like
char c = 'a';
char *ptr = malloc(2*sizeof(char));
ptr[0] = c;
ptr[1] = '\0';
Don't forget to free ptr later!
I have a file of strings seperated by space and I want to get those strings into an array of defined type but I get an error saying that fscanf doesn't take char**, does anyone know how to do this please?
typedef struct{
char *string;
int name;
} DBZ;
DBZ Table[100];
fp = fopen("text.txt", "r");
if(fp == NULL)
{
fprintf(stderr, "Error opening file.");
exit(1);
}
else {
int i=0;
while(!feof(fp))
{
fscanf(fp,"%s", &Table[i].string);
i++;
}
}
&Table[i].string
You're taking an address of a pointer, which is a pointer-of-a-pointer, which is a char**
Also,
fscanf provides no functionality to allocate the memory you need. You'll have to malloc a block large enough to hold whats in your file. Then you'll want to use something safer than fscanf, preferable the most secure thing available* to make sure you don't overwrite the buffer.
else {
int i=0;
while(!feof(fp))
{
Table[i].string = malloc(100);
fscanf_s(fp,"%s", Table[i].string, 100);
i++;
}
}
* These are Microsoft extensions, your platform may have something different.
You need to allocate space for char *string in your struct. And your %s takes char* not char**
Remove the &, Table[i].string is already a pointer.
string also needs to contain memory. You could change the definition of your struct to:
typedef struct{
char string[90];
int name;
} DBZ;
That assumes that your data will fit in 90 bytes. Depending on what your data is, it could also be a very inefficient way of storing it. malloc(), as others have pointed out, could help you here.