This question is really close to this to this topic but I prefer the lisibility and the pointers clarification I needed offered by this solution.
So I've got a data file and I get a very long array of char from it. I want to split this string into an array with, in each case, a string wich correspond to a line of this file.
I saw solutions but they all use limited arrays, since I don't know the lenght of each line, I really need to allocate all of them dynamicly but I can't find the lenght of the lines because strtokdoesn't put a null character \0at the end of each string.
What I've got for now is this two solutions but neither work:
int get_lines(char *file, char **lines) {
int nb_lines = 0;
char *token = strtok(file, "\n");
for(int i = 0; token != NULL; i++) {
token = strtok(NULL, "\n");
nb_lines = i;
}
nb_lines++;
lines = malloc((nb_lines + 1) * sizeof(char*));
lines[nb_lines] = '\0';
token = strtok(file, "\n");
for(int i = 0; token != NULL; i++) {
token = strtok(NULL, "\n");
int nb_char = 0;
for(int j = 0; token[j] != '\n'; j++) //This will cause SIGSEGV because strtok don't keep the '\n' at the end
nb_char = j;
nb_char++;
token[nb_char] = '\0'; //This cause SIGSEGV because token's allocation finish at [nb_char-1]
lines[i] = malloc(strlen(token) * sizeof(char)); //strlen cause SIGSEGV because I cannot place the '\0' at the end of token
printf("%s", token); //SIGSEGV because printf don't find the '\0'
lines[i] = token;
}
for(int i = 0; i < nb_lines; i++) {
printf("%s", lines[i]); //SIGSEGV
}
return nb_lines;
}
So you can see above the idea of what I want to do and why it doesn't work.
Below you will see an other try I made but I'm stuck at the same point:
int count_subtrings(char* string, char* separator) {
int nb_lines = 0;
char *token = strtok(string, separator);
for(int i = 0; token != NULL; i++) {
token = strtok(NULL, separator);
nb_lines = i;
}
return nb_lines + 1;
}
char** split_string(char* string, char* separator) {
char **sub_strings = malloc((count_subtrings(string, separator) + 1) * sizeof(char*));
for(int i = 0; string[i] != EOF; i++) {
//How to get the string[i] lenght to malloc them ?
}
}
My file is quite big and the lines can be too so I don't want to malloc an other table with a size of (strlen(file) + 1) * sizeof(char) to be sure each line won't SIGSEGV and I also find this solution quite dirty, if you guys had an other idea, I would be really happy.
(Sorry for the english mistakes, I'm not really good)
Your approach with strtok has two drawbacks: First, strtok modifies the string,so you can only pass the original string once. Second, it skips empty lines, because it tretas stretches of nelines as a single token separator.. (I don't know ehether that is a concern to you.)
You can countthe newlines with a single pass through the string. Allocate memory for your line array and make a second pass, where you split the string at newlines:
char **splitlines(char *msg)
{
char **line;
char *prev = msg;
char *p = msg;
size_t count = 0;
size_t n;
while (*p) {
if (*p== '\n') count++;
p++;
}
line = malloc((count + 2) * sizeof(*line));
if (line == NULL) return NULL;
p = msg;
n = 0;
while (*p) {
if (*p == '\n') {
line[n++] = prev;
*p = '\0';
prev = p + 1;
}
p++;
}
if (*prev) line[n++] = prev;
line[n++] = NULL;
return line;
}
I've allocated two more line pointers than the newlines count: One for the case that the last line doesn't end with a newline and another one to place a NULL sentinel at the end, so that you know where yourarray ends. (You could, of course, return the actual line count via a pointer to a size_t.)
the following proposed code:
cleanly compiles
(within the limits of the heap size) doesn't care about the input file size
echo's the resulting array of file lines, double spaced, just to show it worked. for single spacing, replace the puts() with printf()
and now the code
#include <stdio.h> // getline(), perror(), fopen(), fclose()
#include <stdlib.h> // exit(), EXIT_FAILURE, realloc(), free()
int main( void )
{
FILE *fp = fopen( "untitled1.c", "r" );
if( !fp )
{
perror( "fopen for reading untitled1.c failed" );
exit( EXIT_FAILURE );
}
// implied else, fopen successful
char **lines = NULL;
size_t availableLines = 0;
size_t usedLines = 0;
char *line = NULL;
size_t lineLen = 0;
while( -1 != getline( &line, &lineLen, fp ) )
{
if( usedLines >= availableLines )
{
availableLines = (availableLines)? availableLines*2 : 1;
char **temp = realloc( lines, sizeof( char* ) * availableLines );
if( !temp )
{
perror( "realloc failed" );
free( lines );
fclose( fp );
exit( EXIT_FAILURE );
}
// implied else realloc successful
lines = temp;
}
lines[ usedLines ] = line;
usedLines++;
line = NULL;
lineLen = 0;
}
fclose( fp );
for( size_t i = 0; i<usedLines; i++ )
{
puts( lines[i] );
}
free( lines );
}
Given the above code is in a file named: untitled1.c the following is the output.
#include <stdio.h> // getline(), perror(), fopen(), fclose()
#include <stdlib.h> // exit(), EXIT_FAILURE, realloc(), free()
int main( void )
{
FILE *fp = fopen( "untitled1.c", "r" );
if( !fp )
{
perror( "fopen for reading untitled1.c failed" );
exit( EXIT_FAILURE );
}
// implied else, fopen successful
char **lines = NULL;
size_t availableLines = 0;
size_t usedLines = 0;
char *line = NULL;
size_t lineLen = 0;
while( -1 != getline( &line, &lineLen, fp ) )
{
if( usedLines >= availableLines )
{
availableLines = (availableLines)? availableLines*2 : 1;
char **temp = realloc( lines, sizeof( char* ) * availableLines );
if( !temp )
{
perror( "realloc failed" );
free( lines );
fclose( fp );
exit( EXIT_FAILURE );
}
// implied else realloc successful
lines = temp;
}
lines[ usedLines ] = line;
usedLines++;
line = NULL;
lineLen = 0;
}
fclose( fp );
for( size_t i = 0; i<usedLines; i++ )
{
puts( lines[i] );
}
free( lines );
}
Related
Hello I am trying to break up a series of strings by spaces in a sentence and display it line by line via a 2d array but am only getting the first word inputted in a sentence. I am using strtok_r but seem to find what I'm doing wrong.
int split(char *s)
{
int count=0;
printf("the code is here");
char *rest;
char* token=strtok_r(s," ", &rest);
while(token != NULL){
count++;
printf("token \s\n ", token);
token=strtok_r(NULL," ",&rest);
if(count==0){
printf("problem \n");
exit(-1);
}
char ** twod=(char**)calloc((count+1),sizeof(char*));
token=strtok_r(s," ",&rest);
int x=0;
while(token !=NULL){
twod[x]=(char*)calloc(strlen(token+1),sizeof(char));
strcpy(twod[x],token);
x++;
token=strtok_r(NULL," ", &rest);
for(x=0;x<count;x++){
printf("%s ", twod[x]);
}
}
}
the following proposed code:
is missing the main() function
corrects the signature for function: split()
documents why each header file is included
performs the desired functionality
cleanly compiles, except maybe on windows
does not use the function: strtok_r()
If compiled on Windows, will need a statement at the top of the code similar to: #define _CRT_SECURE_NO_WARNINGS 1
places all the extracted strings into the 2 dimensional array, rather than skipping the first 2
expands the amount of memory for twod[], as needed, so as to avoid undefined behavior
checks for errors and handles them properly, including freeing the allocated memory before exiting. Checks for errors from realloc() and strdup()
frees the allocated memory before exiting, so as to avoid any memory leaks
Note: it is ok to pass NULL to free()
and now, the proposed code:
#include <string.h> // strdup(), strtok()
#include <stdlib.h> // realloc(), exit(), EXIT_FAILURE, free()
#include <stdio.h> // printf(), perror()
void split( char *s )
{
size_t count=0;
char ** twod = NULL;
char* token = strtok( s, " " );
while( token )
{
count++;
printf("token %s\n ", token);
char ** temp = realloc( twod, count * sizeof( char * ) );
if( ! temp )
{
perror( "malloc failed" );
for( size_t i = 0; i < count; i++ )
{
free( twod[i] );
}
free( twod );
exit( EXIT_FAILURE );
}
twod = temp;
twod[ count -1 ] = strdup( token );
if( ! twod[ count -1 ] )
{
perror( "strdup failed" );
for( size_t i = 0; i < count; i++ )
{
free( twod[i] );
}
free( twod );
exit( EXIT_FAILURE );
}
token = strtok( NULL," " );
}
for( size_t x=0; x < count; x++ )
{
printf("%s ", twod[x]);
}
for( size_t i = 0; i < count; i++ )
{
free( twod[i] );
}
free( twod );
}
I have a text file with:
recipName=Fork friend=Cup sonName=Spork feature=hair sendName=Spoon"
What I want to do is copy all the words before an = sign to one character array, and copy the stuff to the right of the = to another character array or string.
This is my code so far:
int main (int argc, char * argv[])
{
char data[100];
char line[5][100];
char key[5][100];
char value[5][100];
FILE * fdata = fopen(argv[1], "r"); //read data.txt file
FILE * ftemp = fopen(argv[2], "r"); //read and write to template.txt file
if (fdata == NULL)
{
printf("could not read file.\n");
}
int i = 0;
while (fgets(data, 100, fdata) != NULL)
{
printf("data: %s", data);
//this is where i get stuck, idk how to utilize this loop to copy the variable and variable names from the data.txt file i was given...thanks for the help
++i;
}
fclose(fdata);
fclose(ftemp);
return 0;
}
there might be some better functions that will do more of what you want in string.h
you will have to work out the logistics and count the number of '=' characters and decide how to handle that.
#include <string.h>
char *ptr1, *ptr2;
char tempstring[100];
char before[100];
char after[100];
/* you already have data[] filled... where you get stuck */
ptr1 = strchr( data, '=' ); /* find first occurence of = */
ptr2 = strrchr( data, '=' ); /* find last occurence of = */
if ( *ptr1 == '\0' )
{
/* did not find '=' print error message and stop */
}
if ( *ptr2 == '\0' )
{
/* did not find '=' print error message and stop */
}
/* below is what you are interested in */
strcpy( tempstr, data );
ptr1 = strchr( tempstr, '=' );
*ptr1 = '\0'; /* turn = into null */
strcpy( before, tempstr );
printf("everything before = character is %s\n", tempstr ); /* watch out if = is first character, nothing before it */
strcpy( tempstr, data );
ptr2 = strchr( tempstr, '=' );
ptr2++;
if ( *ptr2 != '\0' ) /* = might have been last character */
{
strcpy( after, tempstr );
printf("everything after = character is %s\n", tempstr );
}
so for the first strchr call,
before[] will have "recipName"
and after[] will have "Fork friend=Cup sonName=Spork feature=hair sendName=Spoon"
you can do a
sscanf( after, "%s", after2 );
to get just "Fork" into after2[] array assuming there will always be a space character separating things.
for chqrlie
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
# define MAX 5
int Count_Token ( char str[], char token )
{
char *p;
int cnt = 0;
/* str must be null terminated with '\0' otherwise infinite loop will happen */
p = str;
while ( *p != '\0' )
{
if ( *p == token )
cnt++;
p++;
}
return cnt;
}
void Get_KeyValue_at_Position( char str[], char token, int position, char k[], char v[] )
{
char *ptr;
char temp_str[100];
int i;
ptr = str;
/* assumes str[] passed in does not have leading space before first key */
/* this for loop puts ptr on start of key at position */
for ( i = 0; i < position; i++ }
{
/* move ptr to next space */
while (( *ptr != ' ' ) && ( *ptr != '\0' ))
ptr++;
/* account for more than one space separating key/value pairs and put ptr on beginning of next key */
while ( *ptr == ' ' )
ptr++;
}
/* get key */
strcpy( temp_str, ptr )
ptr_token = strchr( temp_str, token );
*ptr_token = '\0';
strcpy( k, tempstr );
/* get value */
strcpy( temp_str, ptr );
ptr_token = strchr( temp_str, token );
ptr_token++;
strcpy( v, ptr_token );
}
int main ( int argc, char * argv[] )
{
char data[100];
char key[MAX][100]; /* has string before token */
char value[MAX][100]; /* has string afte token */
FILE *fdata;
fdata = fopen(argv[1], "r"); //read data.txt file
if ( fdata == NULL )
{
printf("could not read file %s\n", argv[1] );
exit( 0 );
}
fgets( data, 100, fdata );
while ( ! feof( fdata ) )
{
printf("data: %s", data);
//this is where i get stuck, idk how to utilize this loop to copy the variable and variable names from the data.txt file i was given...thanks for the help
/* count how many token characters there are in data[] string */
num_token = Count_Token( data, '=' );
if ( num_token > MAX )
{
printf(" num token is %d, MAX is %d, stopping program.\n", num_token, MAX );
fclose( fdata );
exit( 0 );
}
for ( i = 0; i < num_token; i++ )
{
/* make sure i index does not exceend declaration size of key and value */
Get_KeyValue_at_Position( data, token, i, key[i], value[i] );
}
fgets( data, 100, fdata );
}
fclose(fdata);
return 0;
}
The purpose of this exercise is to create a program that can read the contents of a file and copy it to a new one. But there is also another thing to do that I do not know how to do:
I should also replace all tabs ('\t') that i find in files with 7 white space.
How can I solve this latter problem? Thank you.
I tried it with these lines of code, but obviously not working. It also also shows the following warning:
warning C4047: '=': 'char' differs in levels of indirection from 'char [8]'
for (int i = 0; i < x; i++){
if (buf[i] == '\t') {
buf[i] = " ";
}
}
This is my code: (of course if it can be improved in some way, do not hesitate to tell me. Thank you)
#include <stdio.h>
#include <stdlib.h>
int main(void) {
char buf[500];
FILE *fp, *nuovo;
errno_t err, err1;
/*lettura e creazione file*/
if (err = fopen_s(&fp, "text.txt", "r")) {
printf("Errore");
} else {
printf("File Letto");
}
if (err1 = fopen_s(&nuovo, "nuovo.txt", "w")) {
printf("Errore");
} else {
printf("File Creato");
}
int x = fread_s(buf, sizeof(buf), 1, 500, fp);
/*THIS IS THE PLACE FOR THE MISSING CODE*/
fwrite(&buf, 1, x, nuovo);
fclose(fp);
fclose(nuovo);
}
You cannot replace one character with a string, which has many characters.
One approach to solving this problem is as follows: instead of making the replacement in place, you could do it while performing the output.
Loop through the characters in buf, and check if buf[i] is a TAB. If it is not a TAB, call fputc(buf[i], nuovo). Otherwise, call fputs(" ", nuovo).
You have to create a new dynamic allocate buffer wher you copy all characters from your source and substitute tab by spaces:
#include <malloc.h>
const char *whitespace = " ";
int whitespaceLen = strlen( whitespace );
int newBufSize = 0;
char *newBuf = NULL;
int newBufPos = 0;
for (int i = 0; i < x; i++)
{
int isTab = buf[i] == '\t'; // test if next char in buf is tab
int charSize = isTab ? whitespaceLen : 1; // size which is neede for next char in newBuf
if ( newBufPos + charSize < newBufSize ) // test if newBuf is large enough
{
newBufSize += 500;
char *temp = realloc( newBuf, newBufSize ); // enlarge newBuf
if ( temp == NULL )
{
free( newBuf ); // out of memory, free newBuf an terminate
newBuf = NULL;
break;
}
newBuf = temp;
}
if ( isTab )
{
memcpy( newBuf+newBufPos, whitespace, whitespaceLen ); // copy whitespace blanks to newBuf
newBufPos += whitespaceLen ;
}
else
newBuf[ newBufPos++ ] = buf[i]; // copy char to newBuf
}
Note somewhere you have to free( newBuf );
I have written the following code to split the lines, in which the strings are separated by symbol '#', and storing in the array named as'buf' here. This code is working fine if I am comparing any string present in the array[0] . but If I try to find the string present in array[3] for example here as 'admin', then it is having error as 'segmentation fault' . Could anyone help me to find why this code is not comparing any other argument.
I would be very thankful for this.
char **strsplit(const char* str, const char* delim, size_t* numtokens) {
char *s = strdup(str);
size_t tokens_alloc = 1;
size_t tokens_used = 0;
char **tokens = calloc(tokens_alloc, sizeof(char*));
char *token, *rest = s;
while ((token = strsep(&rest, delim)) != NULL) {
if (tokens_used == tokens_alloc) {
tokens_alloc *= 2;
tokens = realloc(tokens, tokens_alloc * sizeof(char*));
}
tokens[tokens_used++] = strdup(token);
}
if (tokens_used == 0) {
free(tokens);
tokens = NULL;
} else {
tokens = realloc(tokens, tokens_used * sizeof(char*));
}
*numtokens = tokens_used;
free(s);
return tokens;
}
The main() is as follows:
int main(void) {
char *line = NULL;
size_t linelen;
char **tokens;
size_t numtokens;
int ret=1;
FILE *ptr_file;
char buf[1000];
system("rm -rf input1.txt");
system("/www/stest/mds1 > input1.txt");
ptr_file =fopen("/www/stest/input1.txt","r");
if (!ptr_file)
return 1;
while (fgets(buf,1000, ptr_file)!=NULL)
{
tokens = strsplit(buf, "#\n", &numtokens);
size_t i;
for ( i = 0; i < numtokens; i++)
{
ret=strcmp(tokens[3],"member");
if(ret==0)
{
printf("%s",buf);
break;
}
}
fclose(ptr_file);
return 0;
return EXIT_SUCCESS;
}
Here is the output of the above code and I am having error if I want to print the lines which has 'member'as the third argument of the array.
abc#google.com#abdu#admin
abc#rediff.com#savya#cashier
abc#yahoo.com.com#andy#member
abc#google.com#susan#group
abc#facebook.com#andre#admin
Thanks.
I suspect what you want is something like this:
tokens = strsplit(buf, "#\n", &numtokens);
if(numtokens >= 4 && strcmp(tokens[3],"member") == 0)
{
printf("%s",buf);
}
As shown in George Houpis's answer it would also be good to double-check that strsplit does not return a null pointer.
This is not an answer, but the comment is not big enough. If you run this as your main, what is the output?
int main( int argc, char ** argv )
{
FILE * fin = fopen( "/www/stest/input1.txt", "rt" );
if( !fin )
return 1;
char buffer[1000];
while( fgets( buffer, 1000, fin ) )
{
size_t token_count;
char ** tokens = strsplit( buffer, "#\n", &token_count );
if( tokens )
{
size_t index;
for( index = 0; index < token_count; ++index )
if( !strcmp( tokens[index], "member" ) )
printf( "%d: %s | %s", index, tokens[index], buffer );
for( index = 0; index < token_count; ++index )
free( tokens[index] );
free( tokens );
}
}
fclose( fin );
return 0;
}
When I run with those 5 lines in the text file, I get:
3: member | abc#yahoo.com.com#andy#member
EDIT:
You can tokenize the string without malloc by keeping a second buffer and using pointers to that (still uses memory on the stack).
int main( int argc, char ** argv )
{
FILE * fin = fopen( argv[1], "rt" );
if( !fin )
return 1;
char buffer[1000];
while( fgets( buffer, 1000, fin ) )
{
char buffer_copy[1000];
strcpy( buffer_copy, buffer );
char * tokens[1000];
size_t token_count = 0;
char * ptr = tokens[token_count] = buffer_copy;
while( *ptr )
if( ( *ptr == '#' ) || ( *ptr == '\n' ) )
*ptr++ = '\0', tokens[++token_count] = ptr;
else
++ptr;
size_t index;
for( index = 0; index < token_count; ++index )
if( !strcmp( tokens[index], "member" ) )
printf( "%d: %s | %s", index, tokens[index], buffer );
}
fclose( fin );
return 0;
}
If you go with fixed position (always 3rd (0 indexed)), you can just scan and check:
int is_member( const char * buffer )
{
if( !buffer )
return 0;
size_t index;
const char * ptr = buffer;
for( index = 0; index < 3; ++index, ++ptr )
if( !( ptr = strchr( ptr, '#' ) ) )
return 0;
return !strncmp( ptr, "member", 6 ) && ( ( *( ptr + 7 ) == 0 ) || ( *( ptr + 7 ) == '#' ) || ( *( ptr + 7 ) == '\n' ) );
}
int main( int argc, char ** argv )
{
FILE * fin = fopen( argv[1], "rt" );
if( !fin )
return 1;
char buffer[1000];
while( fgets( buffer, 1000, fin ) )
if( is_member( buffer ) )
printf( "%s", buffer );
fclose( fin );
return 0;
}
Or if the position is not known, then you can find each token on the fly. This takes no significant additional memory (a couple pointers) and does not modify your buffer:
int is_member( const char * buffer, const char * delimiters )
{
size_t index;
const char * ptr = buffer, * eptr = buffer;
for( ; eptr; ptr = eptr + 1 )
// If the next delimiter is found and it is 6 characters away or not found, and the substring matches 'member', return 1.
if( ( !( eptr = strpbrk( ptr, delimiters ) ) || ( eptr - ptr == 6 ) ) &&
!strncmp( ptr, "member", 6 ) )
return 1;
return 0;
}
int main( int argc, char ** argv )
{
FILE * fin = fopen( argv[1], "rt" );
if( !fin )
return 1;
char buffer[1000];
while( fgets( buffer, 1000, fin ) )
if( is_member( buffer, "#\n" ) )
printf( "%s", buffer );
fclose( fin );
return 0;
}
I did it it without using file * since I have the buffer already. It is working. thanks.
char buffer_copy[1000];
strcpy( buffer_copy, buffer );
char * tokens[1000];
size_t token_count = 0;
char * ptr = tokens[token_count] = buffer_copy;
while( *ptr )
if( ( *ptr == '#' ) || ( *ptr == '\n' ) )
*ptr++ = '\0', tokens[++token_count] = ptr;
else
++ptr;
size_t index;
for( index = 0; index < token_count; ++index )
if( !strcmp( tokens[index], "member" ) )
printf( "%d: %s | %s", index, tokens[index], buffer );
I am trying to tokenize a string to give an array of strings but it seems like my code is wrong.
Here is my code:
asmInstruction *tokenizeLine(char *charLine) {
int words = countTokens(charLine);
char *tokens = (char*) malloc(MAX_LINE_LENGTH);
asmInstruction *instr = (asmInstruction*) malloc(sizeof(asmInstruction*));
instr->args = (char**) malloc(MAX_LINE_LENGTH);
int count = 1;
tokens = strtok(charLine, " ,");
while (count <= words) {
tokens = strtok(NULL, " ,");
instr->args[count - 1] = (char*)malloc(MAX_LINE_LENGTH);
instr->args[count - 1] = tokens;
++count;
}
free(tokens);
return instr;
}
/* Reads a file and returns the number of lines in this file. */
uint32_t countLines(FILE *file) {
uint32_t lines = 0;
int32_t c;
while (EOF != (c = fgetc(file))) {
if (c == '\n') {
++lines;
}
}
/* Reset the file pointer to the start of the file */
rewind(file);
return lines;
}
And the structure:
typedef struct {
char **args; /* An array of strings*/
} asmInstruction;
My main is here:
int main() {
char s[] = "ldr r2,r1";
asmInstruction *instr = tokenizeLine(s);
printf("%s", instr->args[0]);
}
/* Counts the number of tokens in a line */
uint32_t countTokens(char line[]) {
/* The correct way to do this! */
uint32_t numberOfTokens = 0;
/* Split at spaces and commas */
char *tokens = strtok(line, " ,");
while (tokens != NULL) {
tokens = strtok(NULL, " ,");
numberOfTokens++;
}
return numberOfTokens;
}
So, this should print ldr.
However, it prints null.
If I loop over the tokens it doesn't print them out but null.
I'm expecting to print out the tokens
ldr
r2
r1
But only the first one gets printed out.
It seems like instr->args[count-1] never gets assigned something because apparently tokens hasn't been assigned something either.
Why is that?
Thanks.
the following code:
handles errors
has many/ most of the logic errors corrected
properly defines the struct asmInstruction
performs the functionality indicated in the question.
suggest elimination of the struct asmInstruction as it is not needed, just use a char** args = NULL; in the tokenizeLine() function and return args.
it is not necessary, nor desirable to malloc memory for 'tokens'. Because that memory pointer will be overlayed each time 'tokens' is set from the returned value from strtok()
If a malloc is done, then there will be a memory leak.
In the following code, there still needs to be some
additional logic for freeing malloc'd memory and for closing the file before calling 'exit( EXIT_FAILURE );'
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
struct asmInstruction
{
char **args; /* An array of strings*/
};
#define MAX_LINE_LENGTH (100)
// prototypes
uint32_t countTokens(char line[]);
uint32_t countLines(FILE *file);
struct asmInstruction *tokenizeLine(char *charLine);
int main( void )
{
char s[] = "ldr r2,r1";
struct asmInstruction *instr = tokenizeLine(s);
printf("%s", instr->args[0]);
return( 0 );
} // end function: main
/* Counts the number of tokens in a line */
uint32_t countTokens(char line[])
{
/* The correct way to do this! */
uint32_t numberOfTokens = 0;
/* Split at spaces and commas */
char *tokens = strtok(line, " ,");
while (tokens != NULL)
{
tokens = strtok(NULL, " ,");
numberOfTokens++;
}
return numberOfTokens;
} // end function: countTokens
struct asmInstruction *tokenizeLine(char *charLine)
{
int words = countTokens(charLine);
char *tokens = NULL;
struct asmInstruction *instr = NULL;
if( NULL == (instr = malloc(sizeof( struct asmInstruction)) ) )
{ // then malloc failed
perror( "malloc for struct asmInstruction failed" );
exit( EXIT_FAILURE );
}
// implied else, malloc successful
instr->args = NULL;
if( NULL == (instr->args = malloc(words*sizeof(char*)) ) )
{ // then malloc failed
perror( "malloc for array of char pointers failed:" );
exit( EXIT_FAILURE );
}
// implied else, malloc successful
memset( instr->args, '\0', words*sizeof(char*) );
int count = 0;
tokens = strtok(charLine, " ,");
while ( tokens )
{
if( NULL == (instr->args[count] = malloc(strlen(tokens)+1) ) )
{ // then, malloc failed
perror( "malloc for arg failed" );
exit( EXIT_FAILURE );
}
// implied else, malloc successful
strcpy(instr->args[count], tokens );
++count;
tokens = strtok(NULL, " ,");
} // end while
return instr;
} // end function: tokenizeLine
/* Reads a file and returns the number of lines in this file. */
uint32_t countLines(FILE *file)
{
uint32_t lines = 0;
int32_t c;
while (EOF != (c = fgetc(file)))
{
if (c == '\n') {
++lines;
}
}
/* Reset the file pointer to the start of the file */
rewind(file);
return lines;
} // end function: countLines
asmInstruction *tokenizeLine(char *charLine) {
int words = countTokens(charLine);
char *tokens;//don't need malloc for this, because just pointer holder.
asmInstruction *instr = (asmInstruction*) malloc(sizeof(asmInstruction));//allocate size isn't sizeof(asmInstruction*)
instr->args = (char**) malloc((words+1) * sizeof(char*));//+1 for NULL, or add member E.g instr->numOfWords = words
int count = 0;
tokens = strtok(charLine, " ,");
while (tokens) {
instr->args[count] = malloc(strlen(tokens)+1);
strcpy(instr->args[count++], tokens);
//or process for each line
//instr->args[count++] = tokens;//no need allocate for word
tokens = strtok(NULL, " ,");//get next tokens
}
instr->args[count] = NULL;//set sentinel
return instr;
}