Array of Strings in C

Trying to fill one from a file

  • (2 Pages)
  • +
  • 1
  • 2

16 Replies - 3633 Views - Last Post: 09 September 2008 - 12:30 PM Rate Topic: -----

#1 sngardner  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 17
  • Joined: 07-September 08

Array of Strings in C

Post icon  Posted 07 September 2008 - 11:47 PM

Hey Guys-

I've just picked up C for a few classes I'm taking this semester, and I'm having trouble with something simple.

char this_line[512];
char *list[sizeof(this_line)];

int i = 0;
while (fgets(this_line, sizeof(this_line), mainfile) != NULL)
{
	list[i] = malloc(sizeof(this_line));
	list[i] = this_line;
	++i;
}

fclose(mainfile);
return 0;



That code (plus a few file opening lines and argument readings) is intended to read each line from 'mainfile' (a text file specified by the user) and place it into an array of strings. I know this has been covered in various places, but I'm having trouble getting my head around them since all of them seem to define the array of strings based on a known number of known-length strings (whereas mine is an unknown number of strings).

Can anyone tell me what's going wrong with this? I know its getting each line correctly and incrementing the i counter, but for some reason each member of the list array is always the last line of the file (ie, calling "printf(list[i])" just outputs the last complete line of the file).

I'd really appreciate any help anyone can give me with this.

Is This A Good Question/Topic? 0
  • +

Replies To: Array of Strings in C

#2 sensui  Icon User is offline

  • D.I.C Head
  • member icon

Reputation: 30
  • View blog
  • Posts: 146
  • Joined: 24-August 08

Re: Array of Strings in C

Posted 08 September 2008 - 03:24 AM

You can't copy an array of characters just like that list[i] = this_line;.
You must use strcpy() ( strcpy( list[i], this_line ); ) from the header file string.h like this:
#include <string.h>
//... the rest of your code
char this_line[512];
char *list[sizeof(this_line)];

int i = 0;
while (fgets(this_line, sizeof(this_line), mainfile) != NULL)
{
    list[i] = malloc(sizeof(this_line));
    strcpy( list[i], this_line ); //note the use of strcpy() from string.h header
    ++i;
}

fclose(mainfile);
return 0;



Hope this helps...
Was This Post Helpful? 0
  • +
  • -

#3 sngardner  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 17
  • Joined: 07-September 08

Re: Array of Strings in C

Posted 08 September 2008 - 07:08 AM

Are you sure my array is declared right? Even when replacing the list[i] = this_line with strcpy, after the while loop the list array is still filled with null objects, and I get an "incompatible implicit declaration" warning on the strcpy line.
Was This Post Helpful? 0
  • +
  • -

#4 sensui  Icon User is offline

  • D.I.C Head
  • member icon

Reputation: 30
  • View blog
  • Posts: 146
  • Joined: 24-August 08

Re: Array of Strings in C

Posted 08 September 2008 - 07:20 AM

This should work:
#include <string.h>
//... the rest of your code

const int SIZE = 512;
char this_line[SIZE];
char *list[SIZE];

int i = 0;
while (fgets(this_line, SIZE, mainfile) != NULL)
{
    list[i] = ( char * ) malloc( SIZE );
    strcpy( list[i], this_line ); //note the use of strcpy() from string.h header
    ++i;
}

fclose(mainfile);
return 0;


Was This Post Helpful? 0
  • +
  • -

#5 JackOfAllTrades  Icon User is offline

  • Saucy!
  • member icon

Reputation: 6078
  • View blog
  • Posts: 23,546
  • Joined: 23-August 08

Re: Array of Strings in C

Posted 08 September 2008 - 08:29 AM

The only problem here is that you're going to run into a problem if the file exceeds 512 lines in length. This code will be more flexible:
#include <stdlib.h>
#include <string.h>
#include <stdio.h>

#define MAX_LINE_SIZE 512
#define MAX_LIST_SIZE 512
#define INCREMENT_SIZE 10

int main(int argc, char *argv[])
{
   char line[MAX_LINE_SIZE];
   char **list = calloc(INCREMENT_SIZE, sizeof(*list));

   int i = 0;
   if (argc == 1)
   {
      printf("Need command line argument\n");
      return -1;
   }

   FILE *fp = fopen(argv[1], "r");
   unsigned int lines_read = 0;
   if (fp)
   {
      while (NULL != fgets(line, sizeof (line), fp))
      {
         if (0 != i && 0 == i % INCREMENT_SIZE)
         {
            char **temp = list;
            list = realloc(list,
                           (i + 1 * INCREMENT_SIZE) * sizeof(*list));
            if (!list)
            {
               // Reached memory limitation
               // Cleanup
               int j = 0;
               while (j != i)
               {
                  free(temp[j]);
                  ++j;
               }
               free(temp);
               return -1;
            }
         }

         list[i++] = strdup(line);
      }

      fclose(fp);
   }

   lines_read = i;
   i = 0;
   while (i < lines_read && list[i])
   {
      printf ("Line %d: %s\n", i, list[i]);
      free(list[i]);
      ++i;
   }
   free(list);

   return 0;
}


Was This Post Helpful? 0
  • +
  • -

#6 sngardner  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 17
  • Joined: 07-September 08

Re: Array of Strings in C

Posted 08 September 2008 - 09:24 AM

Quote

This should work:


const int SIZE = 512;  
char this_line[SIZE];  
char *list[SIZE];	 
int i = 0;  
while (fgets(this_line, SIZE, mainfile) != NULL)  
{  
	list[i] = ( char * ) malloc( SIZE );  
	strcpy( list[i], this_line ); //note the use of strcpy() from string.h header  
	++i;  
}	 
fclose(mainfile);  
return 0;  



As far as I can tell, all that is different is that you defined the size of the array and line variable as a constant int - I haven't had a chance to check it on my home machine, but could you explain why my original code wouldn't work? I'm just trying to get a handle on the real basic C stuff so I'm not too lost in the future.

View PostJackOfAllTrades, on 8 Sep, 2008 - 08:29 AM, said:

The only problem here is that you're going to run into a problem if the file exceeds 512 lines in length. This code will be more flexible:


The reason I specified 512 lines was that the assignment stipulates that the max size of each line should be 512. I was thinking that I'd check for a '/n' character after each line is read in, to see if its valid and throw the requisite error if not.

Would that work fine, or does the fgets(.....) function automatically append a newline at the end of each line even if there's "overflow" to the buffer from the external source?
Was This Post Helpful? 0
  • +
  • -

#7 JackOfAllTrades  Icon User is offline

  • Saucy!
  • member icon

Reputation: 6078
  • View blog
  • Posts: 23,546
  • Joined: 23-August 08

Re: Array of Strings in C

Posted 08 September 2008 - 09:35 AM

fgets stores the newline it has read from the file.

Your solution is fine for the length of the line; I was addressing only the length of the file.

Can you post the code that was giving you the "incompatible implicit declaration" error?
Was This Post Helpful? 0
  • +
  • -

#8 sngardner  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 17
  • Joined: 07-September 08

Re: Array of Strings in C

Posted 08 September 2008 - 09:48 AM

View PostJackOfAllTrades, on 8 Sep, 2008 - 09:35 AM, said:

fgets stores the newline it has read from the file.

Your solution is fine for the length of the line; I was addressing only the length of the file.

Can you post the code that was giving you the "incompatible implicit declaration" error?



char this_line[512];
char *list[sizeof(this_line)];

int i = 0;
while (fgets(this_line, sizeof(this_line), mainfile) != NULL)
{
    list[i] = malloc(sizeof(this_line));
    strcpy(list[i], this_line); //This code was giving me the "implicit..." warning
    ++i;
}

fclose(mainfile);
return 0;



Something along these lines, I don't have the exact code in front of me but I don't think I changed anything other than the strcpy line. Also, how would the file length be affected by the declaration of 512 as the max line length? I was under the impression that I had declared an open-sized array of strings of length 512bytes.

Sorry, I misread your original reply. Thanks for the help!

This post has been edited by sngardner: 08 September 2008 - 09:51 AM

Was This Post Helpful? 0
  • +
  • -

#9 JackOfAllTrades  Icon User is offline

  • Saucy!
  • member icon

Reputation: 6078
  • View blog
  • Posts: 23,546
  • Joined: 23-August 08

Re: Array of Strings in C

Posted 08 September 2008 - 10:08 AM

I have no idea why that's giving you an error, unless this_line is declared somewhere outside of the scope of the function in which the while loop resides, which may lead the compiler to implicitly determine it's an integer.

Quote

I was under the impression that I had declared an open-sized array of strings of length 512bytes.


Unfortunately, no. This code
char this_line[512];  
char *list[sizeof(this_line)];



1. declares an array of 512 characters
2. declares an array of 512 pointers to characters (sizeof(line) is 512)

So, with this loop:
int i = 0;
while (fgets(this_line, sizeof(this_line), mainfile) != NULL)
{
    list[i] = malloc(sizeof(this_line));
    strcpy(list[i], this_line); //This code was giving me the "implicit..." warning
    ++i;
}


when you get to the 513th line of the file, list[i] will be outside of the declared array, and you should get a segmentation fault/access violation.

It's quite possible you needn't account for a file greater than 512 lines in length, in which case I would just add another condition to the while loop, that i < sizeof(list):
while (fgets(this_line, sizeof(this_line), mainfile) != NULL
   && i < sizeof(list))

Was This Post Helpful? 0
  • +
  • -

#10 sngardner  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 17
  • Joined: 07-September 08

Re: Array of Strings in C

Posted 08 September 2008 - 11:20 AM

Quote

char this_line[512];  
char *list[sizeof(this_line)];



1. declares an array of 512 characters
2. declares an array of 512 pointers to characters (sizeof(line) is 512)


So, if I am understanding you correctly, my code right now only creates an array of characters (a string) and an array of pointers, one pointer mapped to each character. Then, if i wanted to declare an array of strings, something like this is needed?

char this_line[512];  
char *ptr_this_line[sizeof(this_line)];
char **list;
strcpy(list[i], ptr_this_line);



My end goal is to get each separate, validly formed line in my file into separate members of an array of strings.

Thanks again for the help.
Was This Post Helpful? 0
  • +
  • -

#11 JackOfAllTrades  Icon User is offline

  • Saucy!
  • member icon

Reputation: 6078
  • View blog
  • Posts: 23,546
  • Joined: 23-August 08

Re: Array of Strings in C

Posted 08 September 2008 - 12:04 PM

No, no...the previous code there is correct.

list is an array of 512 "pointers to character", but they're not actually single characters. In fact, they're not pointing to anything of use at the start. list might look like this in memory:
------------------
| index | address |
------------------
| 0	   | 00000 |
------------------
| 1	   | 00000 |
------------------
...510 more "containers".



After each loop, this_line contains the string read from the file. Say you read "fish\n" into it. The contents of this_line then look like
--------------------------
| f | i | s | h | \n | \0 | 506 more bytes of raw, unused data
--------------------------



The first character of fish has a memory address, as does each other character. In C, however, character arrays are special. They allow us to use the address of the first character to see the entire contents of the character array, up to the terminating null (\0) character, and manipulate it with the string and I/O functions.

Now, the content of this_line needs to be added to our list of strings. So we are going to create the first pointer in our list. First things first, we need to create an area in memory to hold the content. In this case we're going to use a fixed-size buffer which matches the size of the one that we used to read the string. This will use more memory, but that's OK to start. So the malloc(sizeof(this_line)) will create in memory an area providing 512 (i.e., sizeof(this_line)) contiguous bytes of memory, enough to hold 511 characters and the terminating null character. It returns the address of the first byte of this memory, which is stored in the list.

So now, let's say we have the address of the allocated memory, which is 12345. This address is now in list, as shown:

------------------
| index | address |
------------------
| 0	   | 12345 |
------------------
| 1	   | 00000 |
------------------
...510 more "containers".



When you access list[0], you are given a pointer to a char array, 12345.

Now, the memory starting at address 12345 doesn't contain anything yet, so we need to use strcpy to copy the contents of this_line into that portion of memory, at which point, accessing list[0] will provide you with fish\n. That allocated memory stays in place until it's freed later.

The next time through the loop, you will have incremented i to 1, so the same thing happens, only the newly allocated address goes into index 1 of list.

Hope this makes a little sense.

This post has been edited by JackOfAllTrades: 08 September 2008 - 12:04 PM

Was This Post Helpful? 0
  • +
  • -

#12 sngardner  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 17
  • Joined: 07-September 08

Re: Array of Strings in C

Posted 08 September 2008 - 12:27 PM

Alright, thanks. That did a good job of explaining it to me, I kind of thought it was like that but I think the nature of the subject lends itself well to confusing the hell out of new users.

In any case, do you have any idea why the output of this code:

  
//... the rest of my code  
char this_line[512];  
char *list[sizeof(this_line)];  
   
int i = 0;  
while (fgets(this_line, sizeof(this_line), mainfile) != NULL)  
{  
    list[i] = malloc(sizeof(this_line));  
    strcpy( list[i], this_line ); //note the use of strcpy() from string.h header  
    ++i;  
}  

printf("%s", list[1]);

fclose(mainfile);  
return 0;  



would be:
(null)

I thoroughly tested the code that reads in the mainfile, so I don't think it is that.
Was This Post Helpful? 0
  • +
  • -

#13 JackOfAllTrades  Icon User is offline

  • Saucy!
  • member icon

Reputation: 6078
  • View blog
  • Posts: 23,546
  • Joined: 23-August 08

Re: Array of Strings in C

Posted 08 September 2008 - 12:40 PM

I think I would have to see more of the code to tell you. If there are functions involved, then you may have things falling out of scope.
Was This Post Helpful? 0
  • +
  • -

#14 sngardner  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 17
  • Joined: 07-September 08

Re: Array of Strings in C

Posted 08 September 2008 - 05:57 PM

Alright, I am using this code right now:

/*
 * main.c
 *
 *  Created on: Sep 6, 2008
 *      Author: sam
 */

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

int main(int argc, char **argv)
{
	char *filename;
	FILE *mainfile;

	filename = argv[1];

	mainfile = fopen(filename, "r");

	if (mainfile == NULL)
	{
		printf("Error, can't open file ");
		printf(filename);
		printf("\n");
		return 1;
	}
	else
	{
		const int  SIZE = 512;
			  char this_line[SIZE];
			  char *list[SIZE];

		int i = 0;
		while (fgets(this_line, sizeof(this_line), mainfile) != NULL)
		{
			list[i] = malloc(SIZE);
			strcpy(list[i], this_line);
			++i;
		}

		printf("%s", list[i]);

		fclose(mainfile);

		return 0;
	}

	exit (EXIT_SUCCESS);
}



The output is still '(null)'

Can anyone see what I'm missing here? If you can't see anything wrong, does anyone mind trying on a native Unix machine? I'd like to make sure that my VMWare installation of Ubuntu isn't causing weird issues.

Thanks again for all the help.
Was This Post Helpful? 0
  • +
  • -

#15 sensui  Icon User is offline

  • D.I.C Head
  • member icon

Reputation: 30
  • View blog
  • Posts: 146
  • Joined: 24-August 08

Re: Array of Strings in C

Posted 09 September 2008 - 03:02 AM

Instead of printf("%s", list[i]); use for( int j = 0; j < i; j++ ) printf("%s", list[j]);.

Hope this helps.
Was This Post Helpful? 0
  • +
  • -

  • (2 Pages)
  • +
  • 1
  • 2