I have extracted the "meaning" part of my code (and also replace some line to simplify it).
I have 2 dynamic pointers, one for the current line (extracted from a file) and a second for the current token.
Following this question, Free/delete strtok_r pointer before processing complete string?
I wrote this :
int main(void) {
int n = 455;
char *tok2, *freetok2;
char *line, *freeline;
line = freeline = malloc(n*sizeof(*line));
tok2 = freetok2 = malloc(n*sizeof(*tok2));
/* content of the file) */
const char* file_reading = "coucou/gniagnia/puet/";
/* reading from the file */
strcpy(line, file_reading);
strtok(line, "/");
/* get the second token of the line */
tok2 = strtok(NULL, "/");
fprintf(stdout, "%s \n", tok2); // print gniagnia
fprintf(stdout, "%s \n", line); // print coucou
/* free error */
//free(tok2);
/* worked, but maybe don't free "everything ?" */
//free(line);
free(freetok2);
free(freeline);
return 0;
}
But at the end, I'm not sure of what is correct or not, and I find this solution not so elegant (because of using 2 "save variables".
Is that correct ? Is there some ways to improve it ?
Thanks
Edit: changed my code for this, (and it will handle all the lines of the file)
include <unistd.h>
include <stdlib.h>
int main(void) {
char *tok2;
char *line;
/* content of the file) */
const char* file_reading = "coucou/gniagnia/puet/";
const char* file_reading2 = "blabla/dadada/";
/* reading from the file */
line = strdup(file_reading);
strtok(line, "/");
/* get the second token of the line */
tok2 = strtok(NULL, "/");
printf("%s \n", tok2);
printf("%s \n", line);
/* reading from the file */
line = strdup(file_reading2);
strtok(line, "/");
/* get the second token of the line */
tok2 = strtok(NULL, "/");
printf("%s \n", tok2);
printf("%s \n", line);
free(line);
return 0;
}
You're not actually using the memory pointed by freetok2, you don't need to malloc anything, thus you don't need the freetok2 variable.
Saying free(line) or free(freeline) is the same in your code so you don't need the freeline at all.
Another problem is this: malloc(n*sizeof(*line));. You might as well be saying: malloc(n); because sizeof(char) is always 1. But best of all would be:
line = malloc(strlen(file_reading) + 1);
strcpy(line, file_reading);
The code should be modified as follows:
int main(void) {
int n = 455;
char *tok2;
char *line;
line = malloc(n*sizeof(*line));
/* content of the file) */
const char* file_reading = "coucou/gniagnia/puet/";
/* reading from the file */
strcpy(line, file_reading);
strtok(line, "/");
/* get the second token of the line */
tok2 = strtok(NULL, "/");
fprintf(stdout, "%s \n", tok2); // print gniagnia
fprintf(stdout, "%s \n", line); // print coucou
free(line);
return 0;
}
Related
I am trying to read a CSV file of the following format:
5,455,78,5
12245,4,78
1,455,4557,1,8,9
I have managed to open the file but I have no idea how to interpret the data. All the data is written in the first column, but I do not know how many rows there are or how many entries there is in each row.
This is my code for opening the file.
printf("File chosen is: %s",file);
int p=0;
FILE *myFile = NULL;
myFile = fopen(file,"r");
if (myFile == NULL)
{
exit(1);
}
if (myFile != NULL)
{
printf("\n\nFile read succesfully");
}
This should parse your csv. After opening you file, read each line using fgets. Loop through until fgets returns NULL which indicates no line could be read and you reached the end of your file. Use strtok to parse your line from fgets using the comma as your delimiter.
#include <stdio.h> // file handling functions
#include <stdlib.h> // atoi
#include <string.h> // strtok
...
char buffer[80];
while (fgets(buffer, 80, myFile)) {
// If you only need the first column of each row
char *token = strtok(buffer, ",");
if (token) {
int n = atoi(token);
printf("%d\n", n);
}
// If you need all the values in a row
char *token = strtok(buffer, ",");
while (token) {
// Just printing each integer here but handle as needed
int n = atoi(token);
printf("%d\n", n);
token = strtok(NULL, ",");
}
}
...
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
const char* getfield(char* line, int num)
{
const char* tok;
for (tok = strtok(line, ",");
tok && *tok;
tok = strtok(NULL, ",\n"))
{
if (!--num)
return tok;
}
return NULL;
}
int main()
{
FILE *stream = fopen("yourfile.csv", "r");
int i = 0;
int j = 0;
printf("Choose a line to be given its elements: ");
scanf("%d", &j);
char line[1024];
while (fgets(line, 1024, stream))
{
char* tmp = _strdup(line);
i++;
printf("Element %d would be %s\n", i, getfield(tmp, j));
free(tmp);
}
}
Thank you for posting some code, but you don't mention what you wish to do with your data once you read it in.
I'll give you some pointers:
Use an array of known size to read your data into from the file and buffer it for processing. Run this in a loop. e.g.
char buffer[1000];
while (fgets(buffer, sizeof (buffer), myFile))
{
char *data = strtok(buffer, ",");
printf("Data %s\n", data);
/* Further processing of data */
data = strtok(NULL, ",");
}
fclose(myFile);
Process that buffer using strtok to separate out your strings. The token is the data delimiter which should be ',' but I'm not clear on whether you also have a newline character in there, but it needs to be consistent.
Handle your strings returned above.
I have the functions below which reads words from a file and outputs each word using fgets and strtok where the words in the file are split by newline:
word1
word2
word3
I'm trying to mimic the functionality where the words in the file are on a single line split only by a space:
word1 word2 word3
However I seem to only be able to get the first word whilst changing the strtok char to " " and attempting to read a single line. I'm unsure what i'm missing.
#include <string.h>
#include <malloc.h>
int readLines;
char *output[255];
char *filename = "commands.txt";
char fileRead(const char *filename, char *output[255])
{
int count = 0;
char input[255];
char *line;
FILE *file = fopen(filename, "r");
if (file == NULL) {
printf("Cannot open file: %s\n", filename);
} else {
while(count < 255 && fgets(input, sizeof(input), file)) {
line = strtok(input, "\n");
if (line) {
output[count++] = strdup(line); /* Store replica */
}
}
fclose(file);
}
return count;
}
char *strdup(const char *str)
{
char *ret = malloc(strlen(str)+1);
if (ret) {
strcpy(ret, str);
}
return ret;
}
int main(int argc, char *argv[])
{
readLines = fileRead(filename, output);
/* read from array and pass into flag function */
for (int x = 0; x < readLines; ++x) {
printf("%s\n", output[x]);
free(output[x]);
}
return 0;
}
If I understand your question -- that you want to separate words (tokens) that are all contained on one line in a file, then you are using strtok incorrectly. In your code you have line = strtok(input, "\n"); where the delimiter is the newline. If you want to separate space separated words, then you need a space included in your delimiter as well, e.g. char *delim = " \n";
Further, on the first call to strtok you use the variable name of the buffer (or pointer to the buffer) holding the text you want to tokenize. For all remaining calls to strtok (e.g. for words 2, 3, 4...) you use NULL in its place and check the return.
Boiling your example down, you could do something like:
#include <stdio.h>
#include <string.h>
#define MAXC 255
int main (int argc, char **argv) {
char buf[MAXC] = "",
*delim = " \n";
FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;
if (!fp) { /* validate file open for reading */
fprintf (stderr, "error: file open failed '%s'.\n", argv[1]);
return 1;
}
if (!fgets (buf, MAXC, fp)) { /* read one line from file */
fprintf (stderr, "error: file read failed.\n");
return 1;
}
/* tokenize line with strtok */
for (char *p = strtok (buf, delim); p; p = strtok (NULL, delim))
printf ("%s\n", p);
if (fp != stdin) fclose (fp); /* close file if not stdin */
return 0;
}
Example Input File
$ cat dat/strtok.dat
my dog has fleas
Example Use/Output
$ ./bin/strtokoneline <dat/strtok.dat
my
dog
has
fleas
If I misunderstood, then drop a comment and I'm happy to help further. If you have any other questions about the answer, just ask.
If you prefer writing your strtok loop as a while loop instead of a for (it can be easier to look at), you can do something like the following:
char buf[MAXC] = "",
*p = buf,
*delim = " \n";
...
p = strtok (buf, delim); /* get first token (word) */
while (p) {
printf ("%s\n", p);
p = strtok (NULL, delim); /* get remaining tokens */
}
I'm trying to parse a string around an arbitrary index. In my simplest test program I could come up with I have an input string I read the input into and then do memcpy to parse the string.
For testing this I am typing in "this text" as input. readInput is a function where I just have it calling getline(&input, &size, stdnin) and return the input pointer.
int main(){
char *input;
input = readInput();
int parseAround = 4;
char *token1;
char *token2;
memcpy(token1, inputBuffer, 4);
printf("token: %s\n", token1); //prints "this"
memcpy(token1, inputBuffer + (parseAround+1), 4);
//when changed to memcpy(token2,...); segfaults
printf("token: %s\n", token1); //prints "text"
free(input);
return 0;
}
However when I change the second memcpy to use token2 rather than token1, I get a segmentation fault. Why is this?
You most likely need to allocate memory for token1.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(){
char *input = NULL;
size_t len = 0;
ssize_t read;
/* Read in the line "Hello world" */
read = getline(&input, &len, stdin);
printf("Retrieved line of length %zu :\n", read);
printf("%s", input);
/* Allocate memory for both parts of the string */
char *token1 = malloc((read+1) * sizeof(char *));
char *token2 = malloc((read+1) * sizeof(char *));
memcpy(token1, input, 6);
printf("token: %s\n", token1); //prints "Hello"
memcpy(token2, (input+6), 5);
printf("token: %s\n", token2); //prints "world"
free(input);
return 0;
}
Read in the line, allocate memory for each string part, and then copy the part you want into your s
I have to put the data from a csv file (name, address, telephone...) to a structure of my C program. It's been unsuccessful, unfortunately. I tried using strtok function to break into tokens every time it finds a ";" (because we're dealing with a Comma Separated File).
Here's what I've done:
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#define MAX_STR_LEN 256
#define MAX_BOOKS 256
struct estrutura
{
int id;
char nome[40];
char endereco[40];
char cidade[40];
char pais[20];
char cep[10];
char nasc[12];
char telefone[14];
char total[20];
};
struct estrutura cliente[200];
FILE *pFile;
//allocate buffer in each line
char *buf = malloc(MAX_STR_LEN);
char *tmp;
void abrir();
/* Functions to be coded
int menu();
int menu2(); //manutencao de clientes
void adicionar();
void alterar();
void excluir();
void exibir();
void pesquisar(); */
main()
{
system("cls");
abrir();
//menu();
}
void abrir() //open the csv file and copy it to
{
/* FileStream for the Library File */
FILE *pFile;
/* allocation of the buffer for every line in the File */
char *buf = malloc(MAX_STR_LEN);
char *tmp;
/* if the space could not be allocated, return an error */
if (buf == NULL) {
printf ("No memory\n");
}
if ( ( pFile = fopen( "control.csv", "r" ) ) == NULL ) //Reading a file
{
printf( "File could not be opened.\n" );
}
int i = 0;
while (fgets(buf, 255, pFile) != NULL)
{
if ((strlen(buf)>0) && (buf[strlen (buf) - 1] == '\n')) //checa leitura
buf[strlen (buf) - 1] = '\0';
tmp = strtok(buf, ";");
cliente[i].id = atoi(tmp); //atoi for int
tmp = strtok(NULL, ";"); //use strcpy for char
strcpy(cliente[i].nome,tmp);
tmp = strtok(NULL, ";");
strcpy(cliente[i].endereco, tmp);
tmp = strtok(NULL, ";");
strcpy(cliente[i].cidade, tmp);
tmp = strtok(NULL, ";");
strcpy(cliente[i].pais, tmp);
tmp = strtok(NULL, ";");
strcpy(cliente[i].cep, tmp);
tmp = strtok(NULL, ";");
strcpy(cliente[i].nasc, tmp);
tmp = strtok(NULL, ";");
strcpy(cliente[i].telefone, tmp);
tmp = strtok(NULL, ";");
strcpy(cliente[i].total, tmp);
//tempBook.ID = atoi(buf); fix below
printf("%i, %s, %s, %s, %s, %s, %s, %s, %s \n",i, cliente[i].id , cliente[i].nome, cliente[i].endereco, cliente[i].cidade, cliente[i].pais, cliente[i].cep, cliente[i].nasc, cliente[i].telefone, cliente[i].total);
i++;
}
//free(buf);
fclose(pFile);
}
How can I solve this problem? I can't successfully copy the data from 100 clients in the csv to a structure.
Thank you since now!
There are three main problems here:
The format string in printf("%i, %s, %s, %s, ...) doesn't match the parameters, you need one more %i: printf("%i, %i, %s, %s, %s, ...).
In your code you never call abrir() but you call menu(), which doesn't exist, therefore your code doesn't even compile.
If you are on Windows (and only then) you need fopen(..., "rt")) instead of fopen(..., "r"))
Furthermore (not causing actual problems in your code):
char *buf = malloc(MAX_STR_LEN); can be replaced by char buf[MAX_STR_LEN];. It's pointless to allocate memory dynamically if the amount of memory is known at compile time. In that case you must of course not call free(buf) (which is commented out anyway).
Following declarations just after struct estrutura cliente[200]; are useless, you can remove them.
FILE *pFile;
//allocate buffer in each line
char *buf = (char*)malloc(MAX_STR_LEN);
char *tmp;
Otherwise the program should work fine unless your input file has fields that are larger than the field in your struct estrutura.
can anyone tell my why this code is giving me a segmentation fault 11 before entering the do loop?
int parsePath(char *dirs[]){
char *pathEnvVar;
char *thePath;
for(int i=0; i<MAX_ARGS; i++)
dirs[i]=NULL;
pathEnvVar = (char *) getenv("PATH");
thePath = (char *) malloc(strlen(pathEnvVar) +1);
strcpy(thePath, pathEnvVar);
printf("the path is %s \n", thePath );
/* Loop to parse thePath. Look for a ':' delimiter between each path name */
const char delim[2] = ":";
char *token;
int counter = 0;
/* get the first token */
token = strtok(thePath, delim);
printf("got to line 80 \n");
printf("token is %s \n", token);
printf("token is %u \n", (int)token);
printf("got to line 83 \n");
/* walk through other tokens */
do
{
printf("help me");
counter++;
strcpy(dirs[counter], token);
printf("Path is %s", dirs[counter]);
}while((token = strtok(NULL, delim)));
return 0;
}
I'm confused because it prints "got to line 83" but not "Help me" so for some reason it won't enter the do loop?
Here is the output:
the path is /usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:/usr/texbin
got to line 80
token is /usr/bin
token is 2302687600
got to line 83
Segmentation fault: 11
The problem is on the line
strcpy(dirs[counter], token);
At the beginning, you initialize all elements in dirs as NULL. Thus, here on the above line you copies token into NULL.