Parsing string to array in C? - c

I am trying to parse a string in to an array with specific delimiters but its not working as expected. I tried a lot to get this working but failed.
Code i am using is below.
CODE TO PARSE
char itemCode[] = "0xFF,0xAA,0xBB,0x00,0x01,0x04,0x90";
char itemCodeToSend[34] = {0};
char ** res = NULL;
char * p = strtok (itemCode, ",");
int n_spaces = 0, i;
/* split string and append tokens to 'res' and 'itemCodeToSend' */
while (p) {
res = realloc (res, sizeof (char*) * ++n_spaces);
if (res == NULL)
exit (-1); /* memory allocation failed */
res[n_spaces-1] = p; // Copying to char**
strcpy(&itemCodeToSend[0],p);// Copying to Array
p = strtok (NULL, ",");
}
/* realloc one extra element for the last NULL */
res = realloc (res, sizeof (char*) * (n_spaces+1));
res[n_spaces] = 0;
/* print the result */
for (i = 0; i < (n_spaces); ++i)
printf ("res[%d] = %s\n", i, res[i]);
for (i = 0; i < 34; ++i)
printf ("0x%02x",(unsigned)res[i]&0xffU);
/* free the memory allocated */
free (res);
I am getting the below output for char** but not for char[]
res[0] = "0xFF"; itemCodeToSend[0] = "0x30";
res[1] = "0xAA"; itemCodeToSend[1] = "0x30";
res[2] = "0xBB"; itemCodeToSend[2] = "0x30";
res[3] = "0x00"; itemCodeToSend[3] = "0x30";
res[4] = "0x01"; itemCodeToSend[4] = "0x30";
res[5] = "0x04"; itemCodeToSend[5] = "0x30";
res[6] = "0x90"; itemCodeToSend[6] = "0x30";
Am i using right way to copy the extracted value to array?

Looks like you want these lines to access itemCodeToSend.
for (i = 0; i < 34; ++i)
printf ("0x%02x",(unsigned)res[j]&0xffU);
Before that, you you write to itemCodeToSend it looks like you
want to write the integer values, not their textual representation. And not to overwrite
the same element in each loop.
Perhaps you need something along the lines of
itemCodeToSend[n_spaces-1] = strtol(p, 0, 16);
or similar, instead of
strcpy(&itemCodeToSend[0],p);// Copying to Array

Related

malloc() for an array of strings, not working as hoping

I am trying to make a function that takes a string and a pointer to an array of strings and malloc() the array of char arrays and copies each individual word of the string. This is what I have so far, I think I'm close, I'm just struggling with using malloc() on an array of arrays.
int string_parser(char *inp, char **array_of_words_p[])
{
int CurrentChar = 0; //Variable Initialization
char *buffer; //Variable Initialization
/* Allocate memory and check for errors allocating memory */
//Allocate memory to buffer the size of the input string
buffer = (char*)malloc(strlen(inp));
if (buffer == NULL)
{
printf("Error allocating memory..\n");
return -1;
}
/* Move input string into buffer before processing */
for (CurrentChar = 0; CurrentChar < strlen(inp) + 1; CurrentChar++)
{ //For every character in input
if (inp != NULL)
{
//Move input character into buffer
buffer[CurrentChar] = inp[CurrentChar];
}
}
/* Convert string into array of words */
char ** stringbuffer = NULL;
//Convert string to array of words
char * CurrentWord = strtok_s(buffer, " ", *array_of_words_p);
//Variable Initialization
int numspaces = 0;
while (CurrentWord)
{
//Allocate memory for size of string
stringbuffer = (char**)realloc(stringbuffer, sizeof(char**) * ++numspaces);
if (stringbuffer == NULL)
{
return -1;
}
stringbuffer[numspaces - 1] = CurrentWord;
//Reset Current word to null
CurrentWord = strtok_s(NULL, " ", *array_of_words_p);
}
//Reallocate memory to include terminating character
stringbuffer = (char**)realloc(stringbuffer, sizeof(char**) * (numspaces + 1));
stringbuffer[numspaces] = 0;
/* Write processed data into returned argument */
*array_of_words_p = (char**)malloc(sizeof(char**) * (numspaces + 2));
memcpy(*array_of_words_p, stringbuffer, (sizeof(char*) * (numspaces + 2)));
free(stringbuffer);
return numspaces;
}
//Allocate memory to buffer the size of the input string
buffer = (char*)malloc(strlen(inp));
The size of the input string includes the terminating \0, so you need:
buffer = malloc(strlen(inp)+1);
//Convert string to array of words
char * CurrentWord = strtok_s(buffer, " ", *array_of_words_p);
It's unwise to abuse the *array_of_words_p for the context save variable, as this requires it to be initialized appropriately. Better:
char *context, *CurrentWord = strtok_s(buffer, " ", &context);
…
CurrentWord = strtok_s(NULL, " ", &context);
//Allocate memory for size of string
stringbuffer = (char**)realloc(stringbuffer, sizeof(char**) * ++numspaces);
It likely doesn't hurt (owing to equal pointer sizes), but sizeof(char**) is strictly speaking wrong, since the elements of the array of strings are of type char *. Correct:
stringbuffer = realloc(stringbuffer, sizeof (char *) * ++numspaces);
…
stringbuffer = realloc(stringbuffer, sizeof (char *) * (numspaces + 1));
/* Write processed data into returned argument */
*array_of_words_p = (char**)malloc(sizeof(char**) * (numspaces + 2));
memcpy(*array_of_words_p, stringbuffer, (sizeof(char*) * (numspaces + 2)));
free(stringbuffer);
You can spare this unnecessary copying and by the way avoid accessing the unallocated memory stringbuffer[numspaces+1] by replacing the above with just:
*array_of_words_p = stringbuffer;
Apart from that all, your function works and can be called like:
char **array_of_words;
int n = string_parser("this here is an example string", &array_of_words);
for (int i = 0; i < n; ++i) puts(array_of_words[i]);

read int** from file C

I have to read a file in C and create an int**.
This is the file:
2
-1,1,1,0,0,1
1,-1,0,1,0
I'm doing this:
FILE *fp = fopen("grafo.txt", "r");
char line[100];
int numLinea = 0;
char** tokens;
while (1) {
if (fgets(line,150, fp) == NULL) break;
if(numLinea == 0){
NUMERO_NODOS = atoi( line );
nodos = (int **)malloc (NUMERO_NODOS*sizeof(int *));
}else{
tokens = str_split(line, ',');
if (tokens) {
for (int i = 0; *(tokens + i); i++) {
char* contactoNodo;
strcpy(contactoNodo, *(tokens + i));
int numNodo = numLinea-1;
nodos[numNodo] = (int *) malloc (NUMERO_NODOS*sizeof(int));
nodos[numNodo][i] = atoi(contactoNodo);
printf("nodos[%i][%i] = %i\n",numNodo,i,nodos[numNodo][i]);
printf("nodos[0][0] = %i\n",nodos[0][0]);
//free(contactoNodo);
}
printf("nodos[0][0] = %i\n",nodos[0][0]);
//free(tokens);
}
}
numLinea++;
//printf("%3d: %s", i, line);
}
And this is the output:
nodos[0][0] = -1
nodos[0][0] = -1
nodos[0][1] = 1
nodos[0][0] = -1163005939
(...)
Why is nodos[0][0] = -1163005939 in the second iteration of the for loop?
SOLUTION
LOL, it was that:
if(i==0){
nodos[numNodo] = (int *) malloc (NUMERO_NODOS*sizeof(int));
}
I can't believe I didn't see it. Thanks MikeCAT!!!
Fatal errors:
You invoked undefined behavior by using value of uninitialized variable contactoNodo having automatic storage duration, which is indeteminate.
You threw away what is read in the first iteration by allocating new buffer and overwriting the pointer to old buffer by it, and invoked undefined behavior again by reading contents of buffer allocated via malloc and not initialized.
Warnings:
You should pass correct (equals or less than the actual buffer size) buffer size to fgets() to avoid buffer overrun.
They say you shouldn't cast the result of malloc() in C.
Try this:
FILE *fp = fopen("grafo.txt", "r");
char line[100];
int numLinea = 0;
char** tokens;
while (1) {
/* use correct buffer size to avoid buffer overrun */
if (fgets(line,sizeof(line), fp) == NULL) break;
if(numLinea == 0){
NUMERO_NODOS = atoi( line );
/* remove cast of what is returned from malloc() */
nodos = malloc (NUMERO_NODOS*sizeof(int *));
}else{
tokens = str_split(line, ',');
if (tokens) {
for (int i = 0; *(tokens + i); i++) {
char contactoNodo[100]; /* allocate buffer statically */
strcpy(contactoNodo, *(tokens + i));
int numNodo = numLinea-1;
if (i == 0) { /* allocate buffer in only the first iteration */
/* remove cast of what is returned from malloc() */
nodos[numNodo] = malloc (NUMERO_NODOS*sizeof(int));
}
nodos[numNodo][i] = atoi(contactoNodo);
printf("nodos[%i][%i] = %i\n",numNodo,i,nodos[numNodo][i]);
printf("nodos[0][0] = %i\n",nodos[0][0]);
/* do not free() what is not allocated via memory management functions such as malloc() */
}
printf("nodos[0][0] = %i\n",nodos[0][0]);
//free(tokens);
}
}
numLinea++;
//printf("%3d: %s", i, line);
}

C: Realloc behaves in a way i cant figure out why

#include <stdio.h>
#include <stdlib.h>
int main(int argc, char* argv[]){
char buffer[103];
char **words = malloc(1 * sizeof(*words));
size_t counter = 0;
size_t array_size = 2;
for(int i = 0; i < 5; i++){
if(!fgets(buffer, 103, stdin)){
fputs("fgets failed", stderr);
}
words[counter] = buffer;
char **more_words = realloc(words, array_size * sizeof(*more_words));
words = more_words;
array_size++;
counter ++;
}
printf("********************************************************");
for(int i = 0; i < 5; i++){
printf("%s\n", words[i]);
}
}
Now this is the simplified code im working on.
I know i dont handle lots of errors that can occour.
The point is, that when you execute this, the word array seems to have 5 entries of the 'last' entry.
Say you give fgets :
1
2
3
4
5
, then
words[0] = 5;
words[1] = 5;
words[2] = 5;
words[3] = 5;
words[4] = 5;
Why is not:
words[0] = 1;
words[1] = 2;
words[2] = 3;
words[3] = 4;
words[4] = 5;
?
The problem is not the realloc, but what you assign to pointers that you allocated:
words[counter] = buffer;
The buffer is the same pointer all the time, so you end up with the last string read into the buffer.
You need to malloc and copy the buffer for each line:
words[counter] = malloc(strlen(buffer)+1);
strcpy(words[counter], buffer);
It goes without saying that you should be NULL-checking the value returned by realloc before assigning it back to words.
if(!fgets(buffer, 103, stdin)){
fputs("fgets failed", stderr);
}
words[counter] = buffer;
You have one buffer that are overwritten each time when calling fgets, so that all strings in words effectively point to the same char array. Try this:
if(!fgets(buffer, 103, stdin)){
fputs("fgets failed", stderr);
}
// here make a new buffer and copy the string just read into it.
char *new_buffer = malloc(strlen(buffer) + 1);
strcpy(new_buffer, buffer);
words[counter] = new_buffer;

Parsing and data overwriting issues in C using custom strtok

I'm reading in a .csv file, which I then need to parse into tokens. I tried using strtok(), but that unfortunately cannot return null fields (which my data is fulll of). So I went with a home-made version of strtok that I found, strtok_single, which returns the correct values that I need.
The data is input into my array correctly; but there is something wrong because before the initilization loops finish, the data gets overwritten. I've tried print statements and analyzing the problem but I just can't figure out what's wrong. Any insight at all would be helpful.
Here is the homemade strtok function I'm using:
char* strtok_single(char* str, char const* delims) {
static char* src = NULL;
char* p, *ret = 0;
if (str != NULL)
src = str;
if (src == NULL)
return NULL;
if ((p = strpbrk(src, delims)) != NULL) {
*p = 0;
ret = src;
src = ++p;
}
return ret;
}
Here is my code:
int main() {
int numLines = 0;
int ch, i, j;
char tmp[1024];
char* field;
char line[1024];
FILE* fp = fopen("filename.csv", "r");
// count number of lines in file
while ((ch = fgetc(fp)) != EOF) {
if (ch == '\n')
numLines++;
}
fclose(fp);
// Allocate memory for each line in file
char*** activity = malloc(numLines * sizeof(char**));
for (i = 0; i < numLines; i++) {
activity[i] = malloc(42 * sizeof(char*));
for (j = 0; j < 42; j++) {
activity[i][j] = malloc(100 * sizeof(char));
}
}
// read activity file and initilize activity matrix
FILE* stream = fopen("filename.csv", "r");
i = 0;
while (fgets(line, 1024, stream)) {
j = 0;
int newlineLoc = strcspn(line, "\n");
line[newlineLoc] = ',';
strcpy(tmp, line);
field = strtok_single(tmp, ",");
while (field != NULL) {
for (j = 0; j < 42; j++) {
activity[i][j] = field;
field = strtok_single(NULL, ",");
// when I print activity[i][j] here, the values are correct
}
// when I print activity[i][j] here, the values are correct for the
// first iteration
// and then get overwritten by partial data from the next line
}
i++;
} // close while
fclose(stream);
// by the time I get to here my matrix is full of garbage
// some more code that prints the array and frees memory
} // close main
activity[i][j] = field;
When the loops finish, each activity[i][j] points to somewhere in tmp, which is overwritten in each loop. Instead, since you pre-allocate space in each activity[i][j], you should just copy the contents of the string to that:
strcpy(activity[i][j], field);
Being careful of buffer overflow (i.e. if field is more than 99 characters).
Also, the sizeof(char) is superfluous since it's always 1 by definition.
Your line "activity[i][j] = field;" is backwards - you want the pointer assigned to the malloc'd memory.

In C, How to split a string on \n into lines

I want to split a string by \n and place lines which contain a specific token into an array.
I have this code:
char mydata[100] =
"mary likes apples\njim likes playing\nmark hates school\nanne likes mary";
char *token = "likes";
char ** res = NULL;
char * p = strtok (mydata, "\n");
int n_spaces = 0, i;
/* split string and append tokens to 'res' */
while (p) {
res = realloc (res, sizeof (char*) * ++n_spaces);
if (res == NULL)
exit (-1); /* memory allocation failed */
if (strstr(p, token))
res[n_spaces-1] = p;
p = strtok (NULL, "\n");
}
/* realloc one extra element for the last NULL */
res = realloc (res, sizeof (char*) * (n_spaces+1));
res[n_spaces] = '\0';
/* print the result */
for (i = 0; i < (n_spaces+1); ++i)
printf ("res[%d] = %s\n", i, res[i]);
/* free the memory allocated */
free (res);
But then I get a segmentation fault:
res[0] = mary likes apples
res[1] = jim likes playing
Segmentation fault
How can I split a string on \n correctly in C?
strstr just returns a pointer to the first match of second argument.
Your code is not taking care of null character.
Can use strcpy to copy string.
while (p) {
// Also you want string only if it contains "likes"
if (strstr(p, token))
{
res = realloc (res, sizeof (char*) * ++n_spaces);
if (res == NULL)
exit (-1);
res[n_spaces-1] = malloc(sizeof(char)*strlen(p));
strcpy(res[n_spaces-1],p);
}
p = strtok (NULL, "\n");
}
Free res using:
for(i = 0; i < n_spaces; i++)
free(res[i]);
free(res);
Try this:
char mydata[100] = "mary likes apples\njim likes playing\nmark hates school\nanne likes mary";
char *token = "likes";
char **result = NULL;
int count = 0;
int i;
char *pch;
// split
pch = strtok (mydata,"\n");
while (pch != NULL)
{
if (strstr(pch, token) != NULL)
{
result = (char*)realloc(result, sizeof(char*)*(count+1));
result[count] = (char*)malloc(strlen(pch)+1);
strcpy(result[count], pch);
count++;
}
pch = strtok (NULL, "\n");
}
// show and free result
printf("%d results:\n",count);
for (i = 0; i < count; ++i)
{
printf ("result[%d] = %s\n", i, result[i]);
free(result[i]);
}
free(result);

Resources