ejolson
Posts: 12313
Joined: Tue Mar 18, 2014 11:47 am

Re: Two-dimensional array of character strings in C

Sun Feb 18, 2024 4:07 pm

Geralds wrote:
Sun Feb 18, 2024 3:43 pm
So there would be no disadvantage or advantage from running either flavour of OS 64 bit V 32 bit in the case of my 2-D array, other than the input /output limit on file size ?
Pointers in a 64-bit program are 64-bit while pointers in a 32-bit program are 32-bit.

I think 64-bit arm also has more registers but since I've not indulged in ARM assembly, I'm not sure exactly what kind or how many.

Sometimes 64-bit programs run slower because it takes more memory bandwidth to move the pointers around. Sometimes 32-bit programs run slower because fewer registers are available to the optimiser.

It's not that difficult to write C code that runs under either architecture. I'm out off practice but I recall printf and scanf are where some incompatibilities occur due to different sizes of the variable types. There are standard headers to address this, but again, I'm out of practice.
Last edited by ejolson on Sun Feb 18, 2024 4:19 pm, edited 1 time in total.

User avatar
jahboater
Posts: 8898
Joined: Wed Feb 04, 2015 6:38 pm
Location: Wonderful West Dorset

Re: Two-dimensional array of character strings in C

Sun Feb 18, 2024 4:14 pm

ejolson wrote:
Sun Feb 18, 2024 4:07 pm
I think 64-bit arm also has more registers but since I've not indulged in ARM assembly, I'm not sure exactly what kind of how many.
Indeed, it has more than double the number of usable integer registers and double the number of floating-point/16 byte vector registers. (it uses 5 bits instead of 4 bits to encode the register numbers).
This makes a huge difference!
Having nearly 32 scalar local integer variables (plus 32 floating-point ones) available means few local variables need be spilled into memory. 64-bit mode also has a very useful "zero" register.
ejolson wrote:
Sun Feb 18, 2024 4:07 pm
It's not that difficult to write C code that runs under either architecture. I'm out off practice but I recall printf and scanf are where some incompatibilities occur due to different sizes of the variable types. There are standard headers to address this, but again, I'm out of practice.
Yes. Just use the fixed width types in <inttypes.h> such as int64_t or int32_t and everything just works.
Very rarely you might want a variable that changes size depending on 64/32 bits and then use "long".

Geralds
Posts: 33
Joined: Tue Sep 26, 2017 9:35 am
Location: west sussex

Re: Two-dimensional array of character strings in C

Wed Feb 21, 2024 9:06 pm

ejolson wrote:
Wed Feb 07, 2024 9:33 pm

As a conversation piece, here is a simple CSV parser written in C that handles arbitrary sized tables while avoiding the use of malloc.

Code: Select all

/*  csvparser.c -- Parse an unquoted CSV file without malloc
    Written 2024 by Eric Olson */

#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <sys/resource.h>

FILE *open_file(char *file_name,char *mode){
    FILE *file_handle;
    file_handle=fopen(file_name,mode);
    if(file_handle==NULL){
        fprintf(stderr,"Error opening %s file!\n",file_name);
        exit(1);
    }
    return(file_handle);
}

typedef struct { int m,n; } Rowcol;

// Find number of rows and columns
Rowcol getrowcol(char *csvdata){ 
    if(!csvdata||!*csvdata){
        return (Rowcol){0,0};
    }
    int m=0,n=0,k=0;
    for(char *p=csvdata;*p;p++){
        if(*p==','){
            k++;
        } else if(*p=='\n'){
            if(n<k) n=k;
            k=0;
        } else if(!k){
            k++; m++;
        }
    }
    if(n<k) n=k;
    return (Rowcol){m,n};
}

// Parse the csvdata and make strings in place
void makedata(Rowcol d,char *data[d.m][d.n],char *csvdata){
    int i=0,j=0;
    bzero(data,d.m*d.n*sizeof(char *));
    if(!csvdata) return;
    char *p=csvdata,*q=p;
    for(;;){
        if(*p==','){
            *p=0;
            if(i<d.m&&j<d.n) data[i][j]=q;
            j++; q=++p;
        } else if(*p=='\n'){
            *p=0;
            if(i<d.m&&j<d.n) data[i][j]=q;
            i++; j=0; q=++p;
        } else if(!*p){
            if(i<d.m&&j<d.n) data[i][j]=q;
            break;
        } else {
            p++;
        }
    }
}

int main(int argc, char **argv){
    setrlimit(RLIMIT_STACK, // Allow a big stack
        &(const struct rlimit)
        {RLIM_INFINITY,RLIM_INFINITY});

    if(argc<2){
        fprintf(stderr,"Error no config file!\n");
        exit(1);
    }
    FILE *conf_file=open_file(argv[1],"r");
    fseek(conf_file,0,SEEK_END);
    long p=ftell(conf_file); // The size of the file

    char csvdata[p+1]; // Stack allocated buffer
    fseek(conf_file,0,SEEK_SET);
    if(fread(csvdata,p,1,conf_file)==0){
        fprintf(stderr,"Unable to read file %s!\n",argv[1]);
        exit(1);
    }
    csvdata[p]=0;

    Rowcol d=getrowcol(csvdata);

    char *data[d.m][d.n]; // Stack allocated matrix
    makedata(d,data,csvdata);

    for(int i=0;i<d.m;i++){ // Test the CSV parser
        for(int j=0;j<d.n;j++){
            printf("%7s",data[i][j]);
        }
        printf("\n");
    }

    // Stack allocated variables disappear on return
    return 0;
}
I took this code that was written by ejolson which worked well for me , I then created column view of the data in the 2nd column which I did with:-

Code: Select all

  
 int  lp=d.m; 
  char *type [lp]; 
    for (int j=db_start; j < lp ; j++) {
        type[j] = data[j][1];
   }    
  

All looked good, then if I add another view for the 3rd column with :-

Code: Select all

int  lp=d.m; 
 char *type [lp]; 
  char *make [lp];  
    for (int j=db_start; j < lp ; j++) {
        type[j] = data[j][1];
        make[j] = data[j][2]; 
    }    
  
When I print out the data in type and make the data is the same and is the data that is in 3rd column so type is wrong what am I missing ?
https://sommariva.co.uk/

ejolson
Posts: 12313
Joined: Tue Mar 18, 2014 11:47 am

Re: Two-dimensional array of character strings in C

Wed Feb 21, 2024 9:43 pm

Geralds wrote:
Wed Feb 21, 2024 9:06 pm
ejolson wrote:
Wed Feb 07, 2024 9:33 pm

As a conversation piece, here is a simple CSV parser written in C that handles arbitrary sized tables while avoiding the use of malloc.

Code: Select all

/*  csvparser.c -- Parse an unquoted CSV file without malloc
    Written 2024 by Eric Olson */

#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <sys/resource.h>

FILE *open_file(char *file_name,char *mode){
    FILE *file_handle;
    file_handle=fopen(file_name,mode);
    if(file_handle==NULL){
        fprintf(stderr,"Error opening %s file!\n",file_name);
        exit(1);
    }
    return(file_handle);
}

typedef struct { int m,n; } Rowcol;

// Find number of rows and columns
Rowcol getrowcol(char *csvdata){ 
    if(!csvdata||!*csvdata){
        return (Rowcol){0,0};
    }
    int m=0,n=0,k=0;
    for(char *p=csvdata;*p;p++){
        if(*p==','){
            k++;
        } else if(*p=='\n'){
            if(n<k) n=k;
            k=0;
        } else if(!k){
            k++; m++;
        }
    }
    if(n<k) n=k;
    return (Rowcol){m,n};
}

// Parse the csvdata and make strings in place
void makedata(Rowcol d,char *data[d.m][d.n],char *csvdata){
    int i=0,j=0;
    bzero(data,d.m*d.n*sizeof(char *));
    if(!csvdata) return;
    char *p=csvdata,*q=p;
    for(;;){
        if(*p==','){
            *p=0;
            if(i<d.m&&j<d.n) data[i][j]=q;
            j++; q=++p;
        } else if(*p=='\n'){
            *p=0;
            if(i<d.m&&j<d.n) data[i][j]=q;
            i++; j=0; q=++p;
        } else if(!*p){
            if(i<d.m&&j<d.n) data[i][j]=q;
            break;
        } else {
            p++;
        }
    }
}

int main(int argc, char **argv){
    setrlimit(RLIMIT_STACK, // Allow a big stack
        &(const struct rlimit)
        {RLIM_INFINITY,RLIM_INFINITY});

    if(argc<2){
        fprintf(stderr,"Error no config file!\n");
        exit(1);
    }
    FILE *conf_file=open_file(argv[1],"r");
    fseek(conf_file,0,SEEK_END);
    long p=ftell(conf_file); // The size of the file

    char csvdata[p+1]; // Stack allocated buffer
    fseek(conf_file,0,SEEK_SET);
    if(fread(csvdata,p,1,conf_file)==0){
        fprintf(stderr,"Unable to read file %s!\n",argv[1]);
        exit(1);
    }
    csvdata[p]=0;

    Rowcol d=getrowcol(csvdata);

    char *data[d.m][d.n]; // Stack allocated matrix
    makedata(d,data,csvdata);

    for(int i=0;i<d.m;i++){ // Test the CSV parser
        for(int j=0;j<d.n;j++){
            printf("%7s",data[i][j]);
        }
        printf("\n");
    }

    // Stack allocated variables disappear on return
    return 0;
}
I took this code that was written by ejolson which worked well for me , I then created column view of the data in the 2nd column which I did with:-

Code: Select all

  
 int  lp=d.m; 
  char *type [lp]; 
    for (int j=db_start; j < lp ; j++) {
        type[j] = data[j][1];
   }    
  

All looked good, then if I add another view for the 3rd column with :-

Code: Select all

int  lp=d.m; 
 char *type [lp]; 
  char *make [lp];  
    for (int j=db_start; j < lp ; j++) {
        type[j] = data[j][1];
        make[j] = data[j][2]; 
    }    
  
When I print out the data in type and make the data is the same and is the data that is in 3rd column so type is wrong what am I missing ?
That code works for me. When test.csv contains

Code: Select all

A1,A2,A3,A4
B1,B2,B3,B4,B5
C1,C2,C3,C4,C5,C6
running the program with the additions yields

Code: Select all

$ ./view test.csv 
     A1     A2     A3     A4 (null) (null)
     B1     B2     B3     B4     B5 (null)
     C1     C2     C3     C4     C5     C6

Second column (type):
A2 B2 C2 

Third column (make):
A3 B3 C3 
For reference the complete program looks like

Code: Select all

/*  csvparser.c -- Parse an unquoted CSV file without malloc
    Written 2024 by Eric Olson */

#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <sys/resource.h>

FILE *open_file(char *file_name,char *mode){
    FILE *file_handle;
    file_handle=fopen(file_name,mode);
    if(file_handle==NULL){
        fprintf(stderr,"Error opening %s file!\n",file_name);
        exit(1);
    }
    return(file_handle);
}

typedef struct { int m,n; } Rowcol;

// Find number of rows and columns
Rowcol getrowcol(char *csvdata){ 
    if(!csvdata||!*csvdata){
        return (Rowcol){0,0};
    }
    int m=0,n=0,k=0;
    for(char *p=csvdata;*p;p++){
        if(*p==','){
            k++;
        } else if(*p=='\n'){
            if(n<k) n=k;
            k=0;
        } else if(!k){
            k++; m++;
        }
    }
    if(n<k) n=k;
    return (Rowcol){m,n};
}

// Parse the csvdata and make strings in place
void makedata(Rowcol d,char *data[d.m][d.n],char *csvdata){
    int i=0,j=0;
    bzero(data,d.m*d.n*sizeof(char *));
    if(!csvdata) return;
    char *p=csvdata,*q=p;
    for(;;){
        if(*p==','){
            *p=0;
            if(i<d.m&&j<d.n) data[i][j]=q;
            j++; q=++p;
        } else if(*p=='\n'){
            *p=0;
            if(i<d.m&&j<d.n) data[i][j]=q;
            i++; j=0; q=++p;
        } else if(!*p){
            if(i<d.m&&j<d.n) data[i][j]=q;
            break;
        } else {
            p++;
        }
    }
}

int main(int argc, char **argv){
    setrlimit(RLIMIT_STACK, // Allow a big stack
        &(const struct rlimit)
        {RLIM_INFINITY,RLIM_INFINITY});

    if(argc<2){
        fprintf(stderr,"Error no config file!\n");
        exit(1);
    }
    FILE *conf_file=open_file(argv[1],"r");
    fseek(conf_file,0,SEEK_END);
    long p=ftell(conf_file); // The size of the file

    char csvdata[p+1]; // Stack allocated buffer
    fseek(conf_file,0,SEEK_SET);
    if(fread(csvdata,p,1,conf_file)==0){
        fprintf(stderr,"Unable to read file %s!\n",argv[1]);
        exit(1);
    }
    csvdata[p]=0;

    Rowcol d=getrowcol(csvdata);

    char *data[d.m][d.n]; // Stack allocated matrix
    makedata(d,data,csvdata);

    for(int i=0;i<d.m;i++){ // Test the CSV parser
        for(int j=0;j<d.n;j++){
            printf("%7s",data[i][j]);
        }
        printf("\n");
    }

    int db_start=0;
    int lp=d.m; 
    char *type[lp]; 
    char *make[lp];  
    for(int j=db_start;j<lp;j++){
        type[j]=data[j][1];
        make[j]=data[j][2]; 
    }

    printf("\nSecond column (type):\n");
    for(int j=db_start;j<lp;j++){
        printf("%s ",type[j]);
    }
    printf("\n\nThird column (make):\n");
    for(int j=db_start;j<lp;j++){
        printf("%s ",make[j]);
    }
    printf("\n");

    // Stack allocated variables disappear on return
    return 0;
}
I wonder if there is a bug somewhere else in your program. If you can isolate the non-working part and post a simple but complete example here, that might help.

Geralds
Posts: 33
Joined: Tue Sep 26, 2017 9:35 am
Location: west sussex

Re: Two-dimensional array of character strings in C

Wed Feb 21, 2024 11:11 pm

ejolson wrote:
Wed Feb 07, 2024 9:33 pm
I wonder if there is a bug somewhere else in your program. If you can isolate the non-working part and post a simple but complete example here, that might help.
I did that and it works need to do more investigation code as follows:-

Code: Select all

*  csvparser.c -- Parse an unquoted CSV file without malloc
    Written 2024 by Eric Olson */

#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <sys/resource.h>

FILE *open_file(char *file_name,char *mode){
    FILE *file_handle;
    file_handle=fopen(file_name,mode);
    if(file_handle==NULL){
        fprintf(stderr,"Error opening %s file!\n",file_name);
        exit(1);
    }
    return(file_handle);
}

typedef struct { int m,n; } Rowcol;

// Find number of rows and columns
Rowcol getrowcol(char *csvdata){ 
    if(!csvdata||!*csvdata){
        return (Rowcol){0,0};
    }
    int m=0,n=0,k=0;
    for(char *p=csvdata;*p;p++){
        if(*p==','){
            k++;
        } else if(*p=='\n'){
            if(n<k) n=k;
            k=0;
        } else if(!k){
            k++; m++;
        }
    }
    if(n<k) n=k;
    return (Rowcol){m,n};
}

// Parse the csvdata and make strings in place
void makedata(Rowcol d,char *data[d.m][d.n],char *csvdata){
    int i=0,j=0;
    bzero(data,d.m*d.n*sizeof(char *));
    if(!csvdata) return;
    char *p=csvdata,*q=p;
    for(;;){
        if(*p==','){
            *p=0;
            if(i<d.m&&j<d.n) data[i][j]=q;
            j++; q=++p;
        } else if(*p=='\n'){
            *p=0;
            if(i<d.m&&j<d.n) data[i][j]=q;
            i++; j=0; q=++p;
        } else if(!*p){
            if(i<d.m&&j<d.n) data[i][j]=q;
            break;
        } else {
            p++;
        }
    }
}

int main(int argc, char **argv){
    setrlimit(RLIMIT_STACK, // Allow a big stack
        &(const struct rlimit)
        {RLIM_INFINITY,RLIM_INFINITY});

    if(argc<2){
        fprintf(stderr,"Error no config file!\n");
        exit(1);
    }
    FILE *conf_file=open_file(argv[1],"r");
    fseek(conf_file,0,SEEK_END);
    long p=ftell(conf_file); // The size of the file

    char csvdata[p+1]; // Stack allocated buffer
    fseek(conf_file,0,SEEK_SET);
    if(fread(csvdata,p,1,conf_file)==0){
        fprintf(stderr,"Unable to read file %s!\n",argv[1]);
        exit(1);
    }
    csvdata[p]=0;

    Rowcol d=getrowcol(csvdata);

    char *data[d.m][d.n]; // Stack allocated matrix
    makedata(d,data,csvdata);

    for(int i=0;i<d.m;i++){ // Test the CSV parser
        for(int j=0;j<d.n;j++){
            printf("%7s ",data[i][j]);
        }
        printf("\n");
    }

    // Stack allocated variables disappear on return
    
    printf("********* new part ********");
    
    int  lp=d.m; 
    char *type [lp]; 
    
   
   
   char *make [lp]; 
    
    for (int j=0;j<lp;j++){
       type[j]=data[j][1];
       make[j]=data[j][2];
   }
    
    for (int j=0;j<lp;j++){
       printf("Type = %s Make = %s \n",type[j],make[j]);
   }
    
    
    
    
    return 0;
}
input file

Code: Select all

t
t,e,jag
s
t,elise,lotus
t,polo,vw
s
t,f,jaguar
output

Code: Select all

www-data@piserver41:~/projects/projects_shared $ ./test_read_csv_nomalloc config.file 

      t  (null)  (null) 
      t       e     jag 
      s  (null)  (null) 
      t   elise   lotus 
      t    polo      vw 
      s  (null)  (null) 
      t       f  jaguar 
********* new part ********Type = (null) Make = (null) 
Type = e Make = jag 
Type = (null) Make = (null) 
Type = elise Make = lotus 
Type = polo Make = vw 
Type = (null) Make = (null) 
Type = f Make = jaguar 

www-data@piserver41:~/projects/projects_shared $ 
https://sommariva.co.uk/

Geralds
Posts: 33
Joined: Tue Sep 26, 2017 9:35 am
Location: west sussex

Re: Two-dimensional array of character strings in C

Thu Feb 22, 2024 9:24 pm

I found the problem, in my main program I had the data 2d array out of scope but my new 1d arrays which point to the data array were in scope.

Just go to show that getting pointers wrong, can lead to unpredictable behaviour!
https://sommariva.co.uk/

Geralds
Posts: 33
Joined: Tue Sep 26, 2017 9:35 am
Location: west sussex

Re: Two-dimensional array of character strings in C

Sat Feb 24, 2024 9:30 pm

Is there away to pass 2d and 1d strings arrays in to Variadic functions (<stdarg.h>) ?

works with str[0] str[7] ....... etc, but when I pass just the str array I get garbage.
https://sommariva.co.uk/

Return to “C/C++”