I’m new to C and trying to learn a few things. What I’m trying to do is read in a file and store the information. Since the format will be a CSV, the plan is to read in each character, determine if its a number or a comma, and store the numbers in a linked list. The problem I’m having is reading in numbers that are more than one character long like the following example.
5,2,24,5
Here’s the code I’ve got so far and its just not giving back output that I expect. Here’s the code, and the output is below the code sample.
#include <ctype.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
struct list {
float value;
struct list * next;
struct list * prev;
};
int main( int argc, char *argv[] ){
FILE *infile;
char *token = NULL;
char my_char;
/* Open the file. */
// The file name should be in argv[1]
if((infile = fopen(argv[1], "r")) == NULL) {
printf("Error Opening File.\n");
printf("ERROR: %s\n", strerror(errno));
exit(1);
}
while((my_char = (char)fgetc(infile)) != EOF){
//Is my_char a number?
if(isdigit(my_char)){
if(token == NULL){
token = (char *)malloc(sizeof(char));
memset(token, '\0', 1);
strcpy(token, &my_char);
printf("length of token -> %d\n", strlen(token));
printf("%c\n", *token);
} else {
token = (char *)realloc(token, sizeof(token) + 1);
strcat(token, &my_char);
printf("%s\n", token);
}
}
}
free(token);
fclose(infile);
}
And here is the output:
[estest@THEcomputer KernelFunctions]$ nvcc linear_kernel.cu -o linear_kernel.exe
[estest@THEcomputer KernelFunctions]$ ./linear_kernel.exe iris.csv
length of token -> 5
5
5a#1a#
5a#1a#3a#
5a#1a#3a#5a#
5a#1a#3a#5a#1a#
5a#1a#3a#5a#1a#4a#
*** glibc detected *** ./linear_kernel.exe: realloc(): invalid next size: 0x0000000001236350 ***
I don’t understand why the length of the token is ‘5’ when I expect to be 1 and the strange looking characters that follow 5 (represented by ‘a#’). Can anyone help me understand this a little better?
The main issue appears to be a problem with null terminated strings. The
malloccall is allocating 1 byte. Butstrcpycopies bytes until it reaches a null terminator (a zero byte). So the results are not well defined since the byte aftermy_charis a “random” value from the stack.You need to allocate one byte longer (and realloc one byte longer) than the length of the string to allow for a null terminator. And the
strcpyandstrcatcalls are not valid for the source “string” which is actually just a character. To continue using the basic logic that you are implementing, it would be necessary to simply assign the character value to the appropriate position in thetokenarray. Alternatively, you could declaremy_charas a two byte character array and set the second byte to a 0 terminator to allowstrcpyandstrcatto be used. For example,And then it would be necessary to change the usage of
my_characcordingly (assign the value tomy_char[0], and remove the&in the strcpy/strcat calls). The compiler warnings/errors would help address those changes.