Adding to an array in an external file, and adding elements to it.

I have an array in an external file, "array.txt", which contains:

char *testarray[]={"Zero", "One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine"};

I want to be able to add an element to this array, and have that element display, whenever I call it, without having to recompile the source code. Is this possible?

--- Post updated at 09:23 PM ---

I should also mention, that I am using

#include "array.txt"

with this file.

If you keep a file like this, it's much easier to add to:

Zero
One
Two
Three
Four
Five
Six
Seven
Eight
Nine

Then you translate it into an array with

( echo "static char *testarray[]={" ; xargs printf "\"%s\"," < arr ; echo "};" ) > array.h

It ending in a comma is allowable in C, which makes this easier.

The 'static' is to prevent linker errors if you use this in more than one file.

Ok. Thank you for that. But, I can't quite understand how I implement that into my code...

Is it a function, is it a shell script, what exactly is it?

cat text.txt
>the table stands at the window
cat test.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main() {
	int i;
//	char **testarr = (char**)malloc(sizeof(char*));
	char *dl = ", \t\n";
	char *word;
	FILE *file;
	file = fopen("text.txt", "r");

	fseek(file, 0l, SEEK_END);
	long size = ftell(file);
	char *buf = (char*)malloc(size * sizeof(char));
	fseek(file, 0l, SEEK_SET);
	fread(buf, sizeof(char), size, file);
	fclose(file);

	char **testarr = (char**)malloc(size * sizeof(char*));
	word = strtok(buf, dl);
	for(i=0; word != NULL; i++) {
		testarr = (char*)malloc(strlen(word));
		strcpy(testarr, word);
		word = strtok(NULL, dl);
	}
        free(buf);

	for(int j = 0; j < i; j++) {
		printf("%s\n", testarr[j]);
                free(testarr[j]);
        }
        free(testarr);
}
./test
the
table
stands
at
the
window

--- Post updated at 10:46 ---

fixed the code, commented out the wrong line :slight_smile:

--- Post updated at 11:41 ---

Something I am confused, I can not properly allocate memory for addresses in a dynamic array

--- Post updated at 12:34 ---

I fixed in a dynamic array.
But in the strtok function, the valgrind shows one error

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main() {
	int i;
	char *dl = ", \t\n";
	char *word;
	FILE *file;
	file = fopen("text.txt", "r");

	fseek(file, 0l, SEEK_END);
	long size = ftell(file);
	char *buf = (char*)malloc(size * sizeof(char) + 1);
	fseek(file, 0l, SEEK_SET);
	fread(buf, sizeof(char), size, file);
	fclose(file);

	char **testarr = (char**)malloc(sizeof(char*));
	word = strtok(buf, dl);
	for(i=0; word != NULL; i++) {
		testarr = (char**)realloc(testarr, sizeof(char*) + sizeof(char*) * i);
		testarr = (char*)malloc(strlen(word) + 1);
		strcpy(testarr, word);
		word = strtok(NULL, dl);
	}
	free(buf);

	for(int j = 0; j < i; j++) {
		printf("%s\n", testarr[j]);
		free(testarr[j]);
	}
	free(testarr);
}

--- Post updated at 13:16 ---

Collected the program with debug information and Valgrind calmed down :slight_smile:

--- Post updated at 13:27 ---

Add words to the file

cat text.txt
the table stands at the window
and the picture hang on the wall

Run without recompiling

./test
the
table
stands
at
the
window
and
pucture
hung
on
the
wall
2 Likes

Awesome. Thank you. :slight_smile:

Thanks to everyone for their help. Now, i'd like to know, if possible, how do I display this array?

--- Post updated at 07:49 PM ---

Let me elaborate a little more on what i'd like to see... I'd like to be able to traverse the elements in the array with the arrow keys. That's essentially what i'm trying to do. I already have the code ready to accomplish this. I just need to be able to feed the function the name of the array. And that's it.

Thanks.

cat filename?

for(n=0; n<size; n++) printf("%s\n", array[n]) ?

You may need to be more specific.

[edit] You sneaky edited under me.

What prevents you from doing so?

What does this function look like?

For some reason, unix.com isn't letting me include code in my posts.. here's a link to the code:

#include <ncurses.h> #include <stdlib.h> #include <string.h> #include "text.t - Pastebin.com

OK, that's your code, now what's your question?

This line right here:

 selection=barmenu(testarray,row,col,arraylength,width,menulength,3);

It obviously isn't the array that needs to be called.

Ok. I've made a lot of progress.

I'm having problems with this array now:

         const char *testarray[]={"Zero", "One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine", "Ten"};

And this:

    selection=barmenu(testarray,row,col,arraylength,width,menulength,0);

Which does this:

pbtelnet(selection, "26");
pbtelnet

is a function to telnet to an address. The first argument is the hostname, the second is the port number, so, this iteration is telnetting to port 26 of the value of the "Zero" array element.

My question is, it works perfectly fine, but for some reason it telnets to 127.0.0.1. I'm wondering why?

Also, how do I change the value of said element ("Zero")? At this point in time it seems to be set to "0".
I'm wondering how do I change that?

BTW, if you're looking for the source code to the

 barmenu

function, my paste on pastebin is still there.

Why would it telnet to anything? I see that nowhere in your code.

This may be helpful:

arraylength=sizeof(testarray)/sizeof(char *); // Placeholder, only works with predefined arrays

OK, having taken a better look at what you're doing, I think this is what you were looking for. It loads from a newline-separated file, and can append to it. main() returns a value depending on what option you select, 1 for the first line, etc, etc, or 127 if no selection.

#include <ncurses.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>      // for isspace()

int barmenu(const char const **array, int row, int col,
        int arraylength, int width, int menulength, int selection);

// Removes whitespace from the end of strings
void chomp(char *str)
{
        int len=strlen(str);

        if(len>0)
        while((len>0) && isspace(str[len-1]))
                str[--len]='\0';
}

int main(void)
{
        char buf[128];
        int selection,row=1,col=10,arraylength=0,width=5, menulength=5;

        char **testarray=NULL;
        FILE *fp=fopen("filename","r");

        while(fgets(buf,128,fp) != NULL)
        {
                chomp(buf); // Remove \n from end of line
                if(strlen(buf) > width) width=strlen(buf);
                if(!buf[0]) continue; // Ignore blank lines

                arraylength++;
                // Room for n+1 elements of char * size.
                testarray=realloc(testarray, sizeof(char *)*(arraylength+1));
                // strdup is an easy str=malloc(strlen(s)+1); strcpy(str,s);
                testarray[arraylength-1]=strdup(buf);
        }

        // The +1 gives us room for a NULL on the end.  Makes it easier to find crashes.
        testarray[arraylength]=NULL;
        fclose(fp);

        // If no elements were loaded, it will still be NULL
        if(testarray == NULL)
        {
                fprintf(stderr, "Unable to load options\n");
                exit(1);
        }

        initscr();
        noecho();
        keypad(stdscr,TRUE);

        selection=barmenu((const char const **)testarray,row,col,arraylength,width,menulength,0);

        mvprintw(15,0,"Selection= %d",selection);
        refresh();
        getch();
        endwin();

        // Add another option to file
        fp=fopen("filename","a");
        fputs("whatever\n", fp);
        fclose(fp);

        // We allocated all this stuff, so free it.
        for(col=0; col<arraylength; col++) if(testarray[col]) free(testarray[col]);
        free(testarray);

        // Cannot return -1 to commandline.  127 is the maximum we should return.
        if(selection < 0) return(127);
        // 0 has special meaning, return n+1
        return selection+1;
}

int barmenu(const char const **array, int row, int col,
        int arraylength, int width, int menulength, int selection)
{
        int counter,offset=0,ky=0;
         char formatstring[7];
         curs_set(0);

         if (arraylength < menulength)
                 menulength=arraylength;

         if (selection > menulength)
                 offset=selection-menulength+1;

         sprintf(formatstring,"%%-%ds",width); // remove - sign to right-justify the menu items

         while(ky != 27)
                 {
                 for (counter=0; counter < menulength; counter++)
                         {
                         if (counter+offset==selection)
                                 attron(A_REVERSE);
                         mvprintw(row+counter,col,formatstring,array[counter+offset]);
                         attroff(A_REVERSE);
                         }

                 ky=getch();

                 switch(ky)
                         {
                         case KEY_UP:
                                 if (selection)
                                         {
                                         selection--;
                                         if (selection < offset)
                                                 offset--;
                                         }
                                 break;
                         case KEY_DOWN:
                                 if (selection < arraylength-1)
                                         {
                                         selection++;
                                         if (selection > offset+menulength-1)
                                                 offset++;
                                         }
                                 break;
                         case KEY_HOME:
                                 selection=0;
                                 offset=0;
                                 break;
                         case KEY_END:
                                 selection=arraylength-1;
                                 offset=arraylength-menulength;
                                 break;
                         case KEY_PPAGE:
                                 selection-=menulength;
                                 if (selection < 0)
                                         selection=0;
                                 offset-=menulength;
                                 if (offset < 0)
                                         offset=0;
                                 break;
                         case KEY_NPAGE:
                                 selection+=menulength;
                                 if (selection > arraylength-1)
                                         selection=arraylength-1;
                                 offset+=menulength;
                                 if (offset > arraylength-menulength)
                                         offset=arraylength-menulength;
                                 break;

                         case 10: //enter
                                 return selection;
                                 break;
                         case KEY_F(1): // function key 1
                                 return -1;
                         case 27: //esc
                                 // esc twice to get out, otherwise eat the chars that don't work
                                 //from home or end on the keypad
                                 ky=getch();
                                 if (ky == 27)
                                         {
                                         curs_set(0);
                                         mvaddstr(9,77,"   ");
                                         return -1;
                                         }
                                 else
                                         if (ky=='[')
                                                 {
                                                 getch();
                                                 getch();
                                                 }
                                         else
                                                 ungetch(ky);
                         }
                 }
         return -1;
}

Ok. Sorry for not being able to post my code here. Here's some more code.

int conn() { char c[1000]; FILE *fptr; if ((fptr = fopen(" - Pastebin.com

My question is simple: how do I select which data is read by fscanf?

fscanf(fptr,"%[^\n]", c);

Reads until a newline is detected. I'd like to be able to read a certain line in the text file (contact.txt).
Possibly with user input. Is this possible?

Thank you for the code. It doesn't do exactly what I want it to do, but it helps. Thanks.

My answer is simple: However you want.

More specifically, scanf cannot seek line 5. (neither can fseek -- they count bytes, not lines.) To get to line 5, read 4 lines:

int line=5;
char buf[512];
FILE *fp=fopen("file.txt", "r");
while(--line) fgets(buf, 512, fp);
// You are now at line 5.
code_to_read_fifth_line();

Next, rule #1 of C is "never, ever, ever use fscanf". If you absolutely must use scanf, use sscanf. read one line at a time with fgets like I showed you, clean them up with chomp like I showed you, then call sscanf(string, "whatever", arguments); . That will avoid most of scanf's inevitable stumbling blocks.

First problem, scanf has a buffering issue, which is probably why it's not doing what you expect. The first time you call it, it will read until a newline is detected. The second time you call it, it reads until the exact same newline is detected! That newline was never matched, so is still there.

However, fscanf has another problem. What if one of those lines is 1000 bytes but your buffer is only 10? Crash!

You can fix the first issue, to a point. You have to tell fscanf everything it should expect, including the stuff you don't want to keep. Only % codes get read into variables, other stuff gets silently skipped. fscanf(fp, "%[^\r\n]\r\n", c); But if you ever end up with input you didn't specify, fscanf will quite literally choke on it. That's why I specify \r\n here instead of \n. That was a crash issue in software I ported from Windows to UNIX - fscanf had to be amended to accommodate Windows-style carriage returns. \r\n works with both here.

A better example of the way scanf thinks might be sscanf("abcde12345fghijk", "abcde%dfghijk", &number); abcde and fghijk get matched without being stored, only %d is stored because of the %. If you fed it the string "abcdf12345fghijk" it would read "abcd" and stop at f, where it stops agreeing with the string you gave it. The & is required for atomic types - integers and floating point. Strings don't get the & because character arrays are already pointers as far as C's concerned.

Then what do you want? Your questions are both too specific and not specific enough because you're making hasty choices looking for solutions to problems we don't know about. Like the "inserting text into header file" question as a workaround to actually loading a normal text file. Please explain and I might be able to do what you want. How is telnet involved here? What are you actually doing?

I'm writing a telnet BBS client. The code i've showed you is the user interface code. I have a telnet function, which, obviously, telnets to a certain address, specified by which line the arrow key selects in the array. My problems are:

1) I have to recompile, every time a BBS is added to the array. Which is an external file.

2) The array is limited to twenty (20) BBSes.. or elements, however you want to look at it

I hope this illustrates what i'm trying to do. And hopefully you understand what i'm trying to do.
Any specific questions?.

You know how to load from file now. Why not load the BBSes from file too? They could be the same file even.