Given file:

14;@;12;& 41;^;35;* 18;$;25;! ... 

It is necessary to read it into an array and then pass it elementwise:

 #include <stdio.h> #include <string.h> #include <stdlib.h> #define BUFFER_SIZE 1024 // Ρ…Π²Π°Ρ‚ΠΈΡ‚ для всСго char buf[BUFFER_SIZE]; int main(void) { char **result = NULL; FILE *fp = NULL; char *tok= NULL; int line_nums = 4; // ΠΏΡ€Π΅Π΄ΠΏΠΎΠ»ΠΎΠΆΠΈΠΌ Π² Ρ„Π°ΠΉΠ»Π΅ 4 строки fp = fopen("file.txt", "r"); int linecount = 1; // пСрвая строка с Π΅Π΄ΠΈΠ½ΠΈΡ†Ρ‹ result = malloc(line_nums * sizeof(char*)+1); // Π²Ρ‹Π΄Π΅Π»ΠΈΠ»ΠΈ ΠΏΠ°ΠΌΡΡ‚ΡŒ для ΡƒΠΊΠ°Π·Π°Ρ‚Π΅Π»Π΅ΠΉ Π½Π° 4 символа 14;@;12;& while ((getc(fp))!= EOF) { fgets(buf, BUFFER_SIZE, fp); // Ρ‡ΠΈΡ‚Π°Π΅ΠΌ линию int tokcounter = 0; // обнуляСм Ρ‚ΠΎΠΊΠ΅Π½-счСтчик для ΠΊΠ°ΠΆΠ΄ΠΎΠΉ строки tok = strtok(buf, ";"); // ΠΏΡ€ΠΎΡ‡ΠΈΡ‚Π°Π»ΠΈ ΠΏΠ΅Ρ€Π²ΠΎΠ΅ Π·Π½Π°Ρ‡Π°Π½ΠΈΠ΅ // Вопрос: здСсь Ρ‚ΠΎΠΆΠ΅ Π½Π°Π΄ΠΎ ΠΊΠ°ΠΊ-Ρ‚ΠΎ Π²Ρ‹Π΄Π΅Π»ΠΈΡ‚ΡŒ ΠΏΠ°ΠΌΡΡ‚ΡŒ while( tok != NULL ){ result[tokcounter] = malloc(strlen(tok) * sizeof(char *) + 1); // выдСляСм ΠΏΠ°ΠΌΡΡ‚ΡŒ для элСмСнта // Вопрос: ΠΊΠ°ΠΊ ΠΆΠ΅ ΠΏΡ€Π°Π²ΠΈΠ»ΡŒΠ½ΠΎ Π²Ρ‹Π΄Π΅Π»ΠΈΡ‚ΡŒ ΠΏΠ°ΠΌΡΡ‚ΡŒ для ΠΊΠ°ΠΆΠ΄ΠΎΠ³ΠΎ элСмСнта? strncpy(result[tokcounter], tok, sizeof(tok)); tok = strtok( NULL, ";"); tokcounter++; } linecount++; } fclose(fp); // ΠΏΠ΅Ρ‡Π°Ρ‚Π°Π΅ΠΌ Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚ Вопрос : ΠΏΠΎΡ‡Π΅ΠΌΡƒ-Ρ‚ΠΎ тСряСтся пСрвая Ρ†ΠΈΡ„Ρ€Π°: //8 //$ //25 //! for (int i = 0; i < 4; i++) { printf("%s\n", result[i]); } for (int i = 0; i < 4; i++) { // освобоТдаСм ΠΏΠ°ΠΌΡΡ‚ΡŒ free(result[i]); } free(result); return 0; } 

Questions are set as comments in the code.

At the output of the array of arrays on which it will be possible to run line by line (as in the file) and perform actions. Ie that the data is processed line by line , and inside the cycle in pairs

 while(*result != NULL ) { // Ρ†ΠΈΠΊΠ» ΠΏΠΎ строкам for (int k = 0; k = 4; k=k+2){ // Ρ†ΠΈΠΊΠ» ΠΏΠΎ ΠΏΠ°Ρ€Π°ΠΌ index //41 index + 1 // ^ } ++result; } 
  • Please give at least a couple more lines in the file for an example, in order to understand exactly what you need to "pull out" from the file, and give an example of a matrix that should turn out. - Gromov Anton
  • In a strange way, you parse your lines ... In the example, is specified as the delimiter ";" (semicolon), and in strtok() feed just a comma ... What do you want from it? And about the record ... Well, there you can only copy the lines into your array (via strncpy(), memcpy() , etc.). And naturally, you need to allocate all the necessary memory for result , and not just an array of pointers. - Vladimir
  • @vladimir did not copy, typed and sealed. How to allocate memory for each iteration of the loop? - GarfieldCat
  • Yes, about the same as without a loop, just for(int i=0; i<=line_nums; ++i) result[i] = malloc(line_length * sizeof(char) + 1); your array: for(int i=0; i<=line_nums; ++i) result[i] = malloc(line_length * sizeof(char) + 1); . (I took into account that you have the number of lines "+1", although this "+1" was implied, apparently, for '\ 0'? - then it is not necessary in external memory allocation). And at the end of working with such an array, you must also free up first in the cycle result[i] , and then the result itself. - Vladimir
  • But how to determine the required size for the line_length line line_length - you have to solve it yourself according to the requirements of the problem (in the given example, I would think that 2 (+1 on '\ 0') would be enough). - Vladimir

1 answer 1

You have a lot of shortcomings (from the second time you cannot normally allocate dynamic memory, do not close the open file stream, incorrectly implement the reading process itself, a compiler error occurs on the line with strncpy , and, most likely, that is why you have a question, do you not ?), and therefore fix your code is equivalent to the fact that I just write my own , but that's okay, we will solve your problem :)

IMO, I would like to receive a triple pointer, but you need an "array of arrays", so let's assume that we want to get the following structure:

 { {"14"},{"@"},{"12"},{"&"}, {"41"},{"^"},{"35"},{"*"}, {"18"},{"$"},{"25"},{"!"} } 

I will be brief, because there will be a lot of code.

Preprocessor directives that are out of function are in front of you:

 #include <stdlib.h> #include <string.h> #include <stdio.h> #define MAX_LINE_SIZE ( 128u ) #define PARAM_COUNT_PER_LINE ( 4u ) #if ( PARAM_COUNT_PER_LINE != 2 && PARAM_COUNT_PER_LINE != 4 ) #error Parameter count should be 2 or 4. #endif #define DELIMITER ";" #define DELIMITER_SYMB ';' #define DELIMITER_COUNT ( PARAM_COUNT_PER_LINE - 1u ) /*1 - int32_t, 2 - int64-t, other option causes error*/ #define FIRST_PARAM_TYPE_OPTION 1 /* количСство символов для числовых Π»ΠΈΡ‚Π΅Ρ€Π°Π»ΠΎΠ²*/ /* Π²Ρ‹ Π½Π΅ ΡƒΡ‚ΠΎΡ‡Π½ΠΈΠ»ΠΈ, сколько Π±ΡƒΡ„Π΅Ρ€ Π΄ΠΎΠ»ΠΆΠ΅Π½ Π²ΠΌΠ΅Ρ‰Π°Ρ‚ΡŒ символов для числа, поэтому ΠΏΠΎ ΡƒΠΌΠΎΠ»Ρ‡Π°Π½ΠΈΡŽ Π±ΡƒΠ΄Π΅Ρ‚ int32_t */ /*Расчитывал Ρ‚Π°ΠΊ:*/ /*1 - Π½Π° ΠΊΠΎΠ½Π΅Ρ† строки, 1 - Π½Π° Π²ΠΎΠ·ΠΌΠΎΠΆΠ½Ρ‹ΠΉ Π·Π½Π°ΠΊ минуса, ΠΎΡΡ‚Π°Π»ΡŒΠ½Ρ‹Π΅ - количСство символов Π² максимальном числС*/ #if ( FIRST_PARAM_TYPE_OPTION == 1 ) #define FIRST_PARAM_TYPE int32_t #define FIRST_PARAM_SIZE ( 12u ) /* Ρ€Π°Π·ΠΌΠ΅Ρ€ для int32_t */ #elif ( FIRST_PARAM_TYPE_OPTION == 2 ) #define FIRST_PARAM_TYPE int64_t #define FIRST_PARAM_SIZE ( 22u ) /* Ρ€Π°Π·ΠΌΠ΅Ρ€ для int64_t */ #else #error Unable to set first parameter size. #endif #define SECOND_PARAM_SIZE ( 2u ) /*Π½Π΅ знаю, сколько Π²Π°ΠΌ Π½ΡƒΠΆΠ½ΠΎ символов, Π½ΠΎ ΠΏΡƒΡΡ‚ΡŒ Π±ΡƒΠ΄Π΅Ρ‚ ΠΎΠ΄ΠΈΠ½ + символ ΠΊΠΎΠ½Ρ†Π° строки*/ 

To validate the file, I will use the get_lines_count function. With at least one "invalid" line, the function will return zero, in the rest - the number of "correct" lines read.

 static size_t get_lines_count ( const char* filename ) { FILE* fp; size_t lines_count = 0u; char line[ MAX_LINE_SIZE ]; fp = fopen( filename, "r" ); if ( NULL == fp ) return 0u; while ( fgets( line, MAX_LINE_SIZE, fp ) != NULL ) { if ( 0 != is_valid(line) ) { fclose(fp); return 0u; } lines_count++; } fclose(fp); return lines_count; } 

The key function here is is_valid . That is what is needed for proper validation of the string. If you can improve the implementation - "forward."

 static int is_valid( char* line ) /*скорСС всСго, ΠΌΠΎΠΆΠ½ΠΎ ΠΈ эффСктивнСй*/ { size_t symb_counter = 0u; size_t match_symb_count = 0u; size_t line_length; if ( NULL == line ) return -1; line_length = strlen(line); /*Ссли Ρ‚ΠΎΡ‡ΠΊΠ° с запятой Π² самом Π½Π°Ρ‡Π°Π»Π΅ */ if ( DELIMITER_SYMB == line[0u] ) return -2; while ( symb_counter < line_length ) { /* Ссли попалась Ρ‚ΠΎΡ‡ΠΊΠ° с запятой, ΠΈ Π·Π° Π½Π΅ΠΉ Π½Π΅ ΠΈΠ΄Ρ‘Ρ‚ ΡΠ»Π΅Π΄ΡƒΡŽΡ‰Π°Ρ*/ if ( DELIMITER_SYMB == line[symb_counter] && DELIMITER_SYMB != line[symb_counter + 1u] ) match_symb_count++; symb_counter++; } if ( DELIMITER_COUNT != match_symb_count ) return -3; return 0; } 

Suppose that all lines after this will be valid. How to implement reading? Use get_params_from , which assumes the file name and the number of lines in the file (as you might guess, get_lines_count will be used "externally") Here is my implementation:

 char** get_params_from( const char* filename, size_t lines_count ) { FILE* fp; char** result; char tmp_buf[MAX_LINE_SIZE]; size_t all_param_counter = 0u; if ( 0u == lines_count ) return NULL; fp = fopen( filename, "r" ); if ( NULL == fp ) return NULL; result = ( char** ) malloc ( sizeof( char* ) * lines_count * PARAM_COUNT_PER_LINE ); while ( all_param_counter < lines_count * PARAM_COUNT_PER_LINE ) { result[all_param_counter] = ( char* ) malloc ( sizeof( char ) * FIRST_PARAM_SIZE ); result[all_param_counter + 1u] = ( char* ) malloc ( sizeof( char ) * SECOND_PARAM_SIZE ); all_param_counter += 2u; } all_param_counter = 0u; while ( fgets( tmp_buf, MAX_LINE_SIZE, fp ) != NULL || all_param_counter < lines_count * PARAM_COUNT_PER_LINE ) { tmp_buf[strcspn( tmp_buf, "\n" )] = '\0'; /*ΠΎΠ΄ΠΈΠ½ ΠΈΠ· ΠΊΠΎΡ€ΠΎΡ‚ΠΊΠΈΡ… способов ΡƒΠ±Ρ€Π°Ρ‚ΡŒ newline ΠΈΠ· ΠΊΠΎΠ½Ρ†Π°*/ paramcpy( result[all_param_counter], strtok( tmp_buf , DELIMITER), FIRST_PARAM_SIZE ); paramcpy( result[all_param_counter + 1u], strtok( NULL , DELIMITER), SECOND_PARAM_SIZE ); #if ( PARAM_COUNT_PER_LINE == 4 ) paramcpy( result[all_param_counter + 2u], strtok( NULL , DELIMITER), FIRST_PARAM_SIZE ); paramcpy( result[all_param_counter + 3u], strtok( NULL , DELIMITER), SECOND_PARAM_SIZE ); #endif all_param_counter += PARAM_COUNT_PER_LINE; } fclose(fp); return result; } 

A few comments on the function:

  • Look at this "piece":

     result = ( char** ) malloc ( sizeof( char* ) * lines_count * PARAM_COUNT_PER_LINE ); while ( all_param_counter < lines_count * PARAM_COUNT_PER_LINE ) { result[all_param_counter] = ( char* ) malloc ( sizeof( char ) * FIRST_PARAM_SIZE ); result[all_param_counter + 1u] = ( char* ) malloc ( sizeof( char ) * SECOND_PARAM_SIZE ); all_param_counter += 2u; } 

    I did not know how long (by the number of characters) your elements should be, so I decided to implement dynamic memory allocation in exactly this way.

  • paramcpy need the paramcpy function not only to copy the potential element itself into the allocated memory, but also to validate it. Implementation:

     static int paramcpy( char* parameter, char* token, size_t param_size ) { if ( NULL == token || strlen(token) > param_size - 1) { parameter[0] = '\0'; return -1; } strncpy( parameter, token, param_size ); return 0; } 

    Note that if an invalidation is left, we simply leave the element empty, but you can catch it in get_params_from (after all, paramcpy can also return -1). Again, most likely, it can be modified for the better, so do not hesitate. :)

Principle, here you are and got your items. There are only 2 questions left:

  1. How to free up memory?
  2. How beautiful to display something? :)

one

This , thank God, is made a little easier than highlighting:

 void free_params_buf ( char** params_buffer, size_t lines_count ) { size_t all_params_counter = 0u; while ( all_params_counter < lines_count * PARAM_COUNT_PER_LINE ) { free(params_buffer[all_params_counter]); all_params_counter++; } free(params_buffer); } 

2

Well, you can like this:

 void print_params_buf( char** params_buffer , size_t lines_count ) { size_t lines_counter = 0u; if ( NULL == params_buffer || 0u == lines_count ) return; printf("{\n"); while ( lines_counter < lines_count * PARAM_COUNT_PER_LINE ) { printf(" {\"%s\"},{\"%s\"}", params_buffer[lines_counter], params_buffer[lines_counter + 1u] ); #if ( PARAM_COUNT_PER_LINE == 4 ) printf(",{\"%s\"},{\"%s\"}", params_buffer[lines_counter + 2u], params_buffer[lines_counter + 3u]); #endif puts(""); lines_counter += PARAM_COUNT_PER_LINE; } printf("}\n"); } 

Rest

  • main used the following:

      int main( void ) { char const* filename = "file.txt"; size_t file_lines_count = get_lines_count(filename); char** all_params_buffer = get_params_from( filename, file_lines_count ); print_params_buf( all_params_buffer, file_lines_count ); free_params_buf(all_params_buffer, file_lines_count); return 0; } 

    That's why I used get_lines_count "from the outside": if you call in the functions themselves, then there will be a lot of calls to the file: D

  • The module (you can do full-fledged modules with your questions) can also work not only with the format β€œ% s;% s;% s;% s”, but also with β€œ% s;% s” (change the value of PARAM_COUNT_PER_LINE to 2u and the file structure itself, of course: D)

  • To cast to an integer type every odd element (that is, your integer), you can use strtol and cast to the type given in preprocessing ( int32_t or int64_t ).

    Suppose I want to get the 5th element in int32_t (this is a platform-independent type for 32-bit int). Then I do the following: FIRST_PARAM_TYPE variable = (FIRST_PARAM_TYPE) strtol(params_buffer[5u], NULL, 10);

    After preprocessing, it will be like int32_t variable = ( int32_t ) strtol(params_buffer[5u], NULL, 10); (don't forget about #include <stdint.h> )

Output examples

For your file:

 { {"14"},{"@"},{"12"},{"&"} {"41"},{"^"},{"35"},{"*"} {"18"},{"$"},{"25"},{"!"} } 

For a file like:

 14;@ 12;& 41;^ 35;* 18;$ 25;! 

And setting PARAM_COUNT_PER_LINE to 2u will be:

 { {"14"},{"@"} {"12"},{"&"} {"41"},{"^"} {"35"},{"*"} {"18"},{"$"} {"25"},{"!"} } 
  • > IMO, I would like to receive a triple pointer, but you need a "array of arrays" and a triple pointer is really needed - how wrong I was ... - GarfieldCat
  • @GarfieldCat, you can easily proceed from the data that I provided, that is, after this, somehow adjust the "char **" under the "char ***", but now I don’t want to redo the code, because I have a lot to it's time "killed." However, thank you anyway :) - Gromov Anton
  • @GarfieldCat that is why you must first understand the question, and then ask it. Take care of yourself and others in the next. times, and everyone will be happy :) And for the mistake do not blame yourself: everyone happens :) - Gromov Anton