Skip to content

Instantly share code, notes, and snippets.

@mezcel
Last active May 10, 2021 13:37
Show Gist options
  • Save mezcel/922015df1109edb1b55adc544ec29de9 to your computer and use it in GitHub Desktop.
Save mezcel/922015df1109edb1b55adc544ec29de9 to your computer and use it in GitHub Desktop.
Notes: Messing with C (csv and structs)
## .gitnore
## https://gist.github.com/922015df1109edb1b55adc544ec29de9.git
.vscode
*.exe
mainOut*
*.obj
*.o
*.out
## ide generated stuff
*.pdb
*.ilk

Notes: Messing with C (csv and structs)

I am just tinkering with fundamentals or defund-a-mental.

In this gist I am playing with reading and parsing files into a struct.

clone:

git clone https://gist.github.com/922015df1109edb1b55adc544ec29de9.git ~/gist.github/mezcel/csv-and-structs.git


Dependency

Win10

  • Visual Studio Downloads

    • I prefer the CLI over the IDE GUI. (Less configurations, more portable)
    • Build bust be performed by the %comspec% /k "C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\Common7\Tools\VsDevCmd.bat shell.
      • Launch VSCode from this shell if you want to debug
    • Run the following scripts: launchVsDevCmd.bat and then make.bat.
    • Or just run: cl main.c /c functions.c /Fe"main.exe"
    • Or cl /c functions.c; cl main.c functions.obj /Fe"main.exe"

    OR

  • MinGw or the Cygwin environment.

    • Cygwin packages: gcc-core, automake, make, bash, binutils, cygwin, cygwin-devel, cygutils-extra

Debian

  • gcc
    sudo apt update
    sudo apt install -y build-essential gcc gdb

Notes

System environment headers

Standard Libraries

library Linux Windows 10 use case
#include <stdio.h> stdio.h cstdio.h printf(), sprintf(), fread(), fopen(), fclose()
#include <stdlib.h> stdlib.h stdlib.h calloc(), realloc(), malloc(), system(), free()
#include <string.h> string.h cstring.h strcmp()
#include <time.h> time.h ctime.h After year 2038, use an x64 compiler

Windows 10

library Visual Studio C++ use case
#include <windows.h> windows.h GetConsoleScreenBufferInfo()
#include <conio.h> conio.h getch()

Debian Linux

library GCC use case
#include <sys/stat.h> sys/stat.h stat()
#include <sys/ioctl.h> sys/ioctl.h ioctl(), TIOCGWINSZ, struct winsize
#include <unistd.h> unistd.h STDOUT_FILENO
#include <json-c/json.h> json-c/json.h Debian Linux json-c library
#include "gtk/gtk.h" "gtk/gtk.h" used for Gtk

Notes:

The sizeof() function in Gcc is not the same as Visual Studio's C++ sizeof(). T hey are interchangeable for simple arrays, like

char* ch = "word"; sizeof(word)
We can make this file beautiful and searchable if this error is corrected: No commas found in this CSV file in line 0.
"className.attrID";"className.attrName"
0;"NameZero"
1;"NameOne"
2;"NameTwo"
3;"NameThree"
4;"NameFour"
5;"NameFive"
6;"NameSix"
7;"NameSeven"
/* functions.c */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "header.h"
int isCharAnInt( char *strInput ) {
/* diy alternative to "isdigit"
* #include <ctype.h> // https://www.unix.com/man-page/linux/3/isdigit/
*
* determine if a char character is an int
* return either 0=false, 1=true */
int passFlag = 0;
if( strInput[0] >= '0' && strInput[0] <= '9') {
passFlag = 1;
}
return passFlag; // 0=false, 1=true
}
int returnDigitCount( int intInput) {
/* return the number of digits of an int */
int count = 0;
if ( intInput == 0) {
count = 1;
return count;
}
while( intInput ) {
intInput /= 10;
count++;
}
return count;
}
char ** strsplit( const char * src, const char * delim ) {
/* return a char delineated array
* the output will be a 2d pointer to a pointer array*/
char * pbuf = NULL;
char * ptok = NULL;
int count = 0;
int srclen = 0;
char ** pparr = NULL;
srclen = strlen( src );
pbuf = ( char* ) malloc( srclen + 1 );
if( !pbuf ) {
return NULL;
}
strcpy( pbuf, src );
ptok = strtok( pbuf, delim );
while( ptok ) {
pparr = ( char** ) realloc( pparr, ( count + 1 ) * sizeof( char* ) );
*( pparr + count ) = strdup( ptok );
count++;
ptok = strtok( NULL, delim );
}
pparr = ( char** ) realloc( pparr, ( count + 1 ) * sizeof( char* ) );
*( pparr + count ) = NULL;
free( pbuf );
return pparr;
}
void strsplitfree( char ** strlist ) {
/* free memory of 2d nested arrays or an array of strings */
int i = 0;
while( strlist[ i ] ) {
free( strlist[ i++ ] );
}
free( strlist );
}
char *removeNewLine( char *str ) {
for( int i = 0; str[ i ] != '\0'; i++ ) {
if( str[ i ] == '\n' ) {
str[ i ] = ' ';
}
}
return str;
}
entityA_t * polulateEntity_ClassA( char * scvline ) {
/* poulate a ObjectA_struct struct */
char ** pp = NULL;
char *cleanScvLine;
entityA_t * entity_record = NULL;
cleanScvLine = removeNewLine( scvline );
pp = strsplit( cleanScvLine, ";" );
entity_record = ( entityA_t* ) calloc( 1, sizeof( entityA_t ) );
entity_record -> attributeID = atoi( pp[ 0 ] );
entity_record -> attributeName = strdup( pp[ 1 ] );
entity_record -> headerString = strdup( cleanScvLine );
strsplitfree( pp );
return entity_record;
}
void csvToStruct_ClassA( database_t *database, int maxRecordChars, char *filePath ) {
/* poulate the ClassA_struct and ERDatabase_struct structs
* It will also count the number of records in a scv file and save it for quick refference
*/
char *scvline = malloc( maxRecordChars + 1 );
int counter = 0;
int arrayIndex = 0;
entityA_t *entity_record;
FILE * csvFile = fopen( filePath, "r" );
while( fgets( scvline, maxRecordChars, csvFile ) ) {
entity_record = polulateEntity_ClassA( scvline );
if ( counter == 0 ) {
database -> classA.recordsArray[ counter ].headerString = entity_record -> headerString;
} else {
//arrayIndex = counter;
database -> classA.recordsArray[ counter ].attributeID = entity_record -> attributeID;
database -> classA.recordsArray[ counter ].attributeName = entity_record -> attributeName;
}
counter++;
}
database -> classA.csvTotalRecords = counter;
database -> classA.csvPath = filePath;
// destroy temp string memory
free( entity_record );
fclose( csvFile );
free( scvline );
}
void make_struct_ERDatabase_csv( database_t *ERDatabase, char *csv_path ) {
// Popilate the ERDatabase_struct struct with the ClassA_struct
csvToStruct_ClassA( ERDatabase, 50, csv_path );
}
/* header.h */
/* https://gcc.gnu.org/codingconventions.html */
#ifndef HEADER
#define HEADER
// Data Structures
typedef struct ObjectA_struct {
int totalChars;
int csvIndex;
int attributeID;
char *attributeName;
char *headerString;
} entityA_t;
typedef struct ClassA_struct {
// used for csv file information
char *csvPath;
char *csvHeaderString;
int csvTotalRecords;
int csvMaxRecordChars;
entityA_t recordsArray[ 9 ];
} classA_t;
typedef struct ERDatabase_struct {
// one must know or set the min size beforehand
// kinda like in Sql
classA_t classA;
} database_t;
// Prototypes
int isCharAnInt( char *strInput );
char** strsplit( const char * src, const char * delim );
void strsplitfree( char ** strlist );
char* removeNewLine( char *str );
int* testArr( database_t * database, char * filePath );
entityA_t* polulateEntity_ClassA( char * scvline );
void csvToStruct_ClassA( database_t *ERDatabase, int LINE_MAX_LEN, char *filePath );
void make_struct_ERDatabase_csv( database_t *ERDatabase, char *csv_path );
#endif
:: launchVSDevCmd.bat
:: Launch the VS19 Developer Command Prompt
:: Depends on BuildTools provided by https://visualstudio.microsoft.com/downloads
%comspec% /k "C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\Common7\Tools\VsDevCmd.bat"
/* main.c */
// Headers
#include <stdio.h>
#include "header.h"
// Prototypes
void DemoImportDB( database_t *database );
// Functions
void DemoImportDB( database_t *database ) {
printf( "\nFile: %s\n", database -> classA.csvPath );
printf( "Total records in csv: %d\n", database -> classA.csvTotalRecords );
for ( int i = 0; i < database -> classA.csvTotalRecords; i++ ) {
if ( i == 0 ) {
printf( "index: %d\theader: %s\n", i, database -> classA.recordsArray[i].headerString );
} else {
printf( "index: %d\tattributeID: %d\tattributeName: %s\n", i,
database -> classA.recordsArray[i].attributeID,
database -> classA.recordsArray[i].attributeName );
}
}
}
// MAIN()
int main( int argc, char **argv ) {
printf( "##\n## Parse a CSV into an ER struct database\n##\n" );
database_t ERDatabase; // Declare rosary db ER struct
char *csv_path = "ClassA.csv";
make_struct_ERDatabase_csv( &ERDatabase, csv_path );
DemoImportDB( &ERDatabase );
return 0;
}
:: make.bat
:: clean previous builds
del *.exe
del *.obj
:: compile object
cl /c functions.c
:: build if object was compiled
IF EXIST functions.obj (
cl main.c functions.obj /Fe"mainOut.exe"
)
:: launch if exists
IF EXIST .\mainOut.exe CALL .\mainOut.exe
## Makefile
## For Debian OS
## Requires: build-essential
CC=gcc
all: main.o functions.o
$(CC) main.o functions.o -o "mainOut.out"
functions.o: functions.c
$(CC) -c functions.c
main.o: main.c
$(CC) -c main.c
depends:
sudo apt update -y
sudo apt install -y build-essential gcc gdb make
clean:
rm -f *.o *.out *.obj *.pdb *.ilk *.exe mainOut*
/*
sizeof.c
messing with int arrays and exploring passing an array into a function
this is a test comparing: VS BuildTools (cpp) vs GNU Gcc
*/
#include <stdio.h>
// Globabls
int intArrayGlobal[] = { 60,70,80,90,1,2 }; // used with testB()
// Prototypes
void testA();
void testB();
int testC( int intArrayMain[] );
// MAIN
int main() {
testA();
testB();
int intArrayMain[] = { 60,70,80,90,1,2 };
printf( "\nint testC( int* intArrayMain );\t\t// Not working ??? \n" );
printf( "\tint intArrayMain[] = { 60,70,80,90,1,2 }; // sould be 6\n" );
printf( "\t*( &intArrayMain + 1 ) - intArrayMain = %d\t\t// Works \n", *( &intArrayMain + 1 ) - intArrayMain );
printf( "\tsizeof(intArrayMain)/sizeoff(intArrayMain[0]) = %d\t// Works", sizeof(intArrayMain)/sizeof(intArrayMain[0]) );
int sizeC = testC( intArrayMain );
printf( "\n\tsizeC = %d\n", sizeC );
return 0;
}
// Functions
void testA() {
//* DIY sizeof() it is less efficient. compile at runtime instead of build */
int intArrayLocal[] = { 60,70,80,90,1,2 };
// take the address of array and increment it by itself, and the (int*) difference is the space it occupies
int sizeA = *( &intArrayLocal + 1 ) - intArrayLocal;
printf("\nvoid testA(); // Works\n");
printf( "\tint intArrayLocal[] = { 60,70,80,90,1,2 }; // souldd be 6\n" );
printf( "\tsizeA =\t %d \n", sizeA );
}
void testB() {
/*
https://www.geeksforgeeks.org/how-to-find-size-of-array-in-cc-without-using-sizeof-operator/
&arr ==> Pointer to an array of 6 elements. [See this for difference between &arr and arr]
(&arr + 1) ==> Address of 6 integers ahead as pointer type is pointer to array of 6 integers.
*(&arr + 1) ==> Same address as (&arr + 1), but type of pointer is "int *".
*(&arr + 1) - arr ==> Since *(&arr + 1) points to the address 6 integers ahead of arr, the difference between two is 6.
*/
//* DIY sizeof() it is less efficient. compile at runtime instead of build */
int sizeB = *( &intArrayGlobal + 1 ) - intArrayGlobal;
printf( "\nvoid testB();// works\n" );
printf( "\tint intArrayGlobal[] = { 60,70,80,90,1,2 }; // sould be 6\n" );
printf( "\tsizeB =\t %d \n", sizeB );
}
int testC( int intArrayMain[] ) {
printf("\nDebug: int testC( int* intArrayMain ); \n");
printf("\t\t\t Address\t\t Int\t\tdiff Address\tdiff int\n");
printf("\t\t\t -------\t\t -------\t-------\t\t-------\n");
printf( "\tintArrayMain\t= %p \t%d\n", intArrayMain, intArrayMain );
printf( "\tintArrayMain+1\t= %p \t%d \t%p \t\t%d\n", intArrayMain+1, intArrayMain+1, (intArrayMain+1) - intArrayMain, (intArrayMain+1) - intArrayMain );
printf( "\t*intArrayMain\t= %p \t\t\t%d\n", *intArrayMain, *intArrayMain );
printf( "\t*intArrayMain+1\t= %p \t\t\t%d \t\t%p \t\t%d\n", *intArrayMain+1, *intArrayMain+1, (*intArrayMain+1) - *intArrayMain, (*intArrayMain+1) - *intArrayMain );
printf( "\t&intArrayMain\t= %p \t%d\n", &intArrayMain, &intArrayMain );
printf( "\t&intArrayMain+1\t= %p \t%d \t%p \t\t%d\n", &intArrayMain+1, &intArrayMain+1, (&intArrayMain+1) - &intArrayMain, (&intArrayMain+1) - &intArrayMain );
int size1 = sizeof(intArrayMain) / sizeof(intArrayMain[0]);
int size2 = *( &intArrayMain + 1 ) - intArrayMain;
printf( "\n\tsizeof(intArrayMain)/sizeoff(intArrayMain[0]) = \t%d\n", size1 );
printf( "\t*( &intArrayMain + 1 ) - intArrayMain = \t\t%d\n", size2 );
return size1;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment