In C a string is a char*. A dynamic array of type T is represented as a pointer to T, so for char* that would be char**, not simply a char* the way you declared it.
The compiler, no doubt, has issued some warnings about it. Pay attention to these warnings, very often they help you understand what to do.
Here is how you can start your testing:
char **aPtr;
int len = 1; // Start with 1 string
aPtr = malloc(sizeof(char*) * len); // Do not cast malloc in C
aPtr[0] = "This is a test";
printf("%s",aPtr[0]); // This should work now.
Answer from Sergey Kalinichenko on Stack OverflowIn C a string is a char*. A dynamic array of type T is represented as a pointer to T, so for char* that would be char**, not simply a char* the way you declared it.
The compiler, no doubt, has issued some warnings about it. Pay attention to these warnings, very often they help you understand what to do.
Here is how you can start your testing:
char **aPtr;
int len = 1; // Start with 1 string
aPtr = malloc(sizeof(char*) * len); // Do not cast malloc in C
aPtr[0] = "This is a test";
printf("%s",aPtr[0]); // This should work now.
char *str; //single pointer
With this you can store one string.
To store array of strings you Need two dimensional character array
or else array of character pointers or else double pointer
char str[10][50]; //two dimensional character array
If you declare like this you need not allocate memory as this is static declaration
char *str[10]; //array of pointers
Here you need to allocate memory for each pointer
loop through array to allocate memory for each pointer
for(i=0;i<10;i++)
str[i]=malloc(SIZE);
char **str; //double pointer
Here you need to allocate memory for Number of pointers and then allocate memory for each pointer .
str=malloc( sizeof(char *)*10);
And then loop through array allocate memory for each pointer
for(i=0;i<10;i++)
str[i]=malloc(SIZE);
c - Dynamic memory allocation with char - Stack Overflow
Dynamic memory allocation for an array of pointers to char in C - Stack Overflow
c - How to use Dynamic Allocation for char array - Stack Overflow
Issue with Dynamic Memory Allocation for a char Array in C - Stack Overflow
Videos
Do like this:
char** list;
list = malloc(sizeof(char*)*number_of_row);
for(i=0;i<number_of_row; i++)
list[i] = malloc(sizeof(char)*number_of_col);
Additionally, if you are allocating memory dynamically. you are to free it as work done:
for(i=0;i<number_of_row; i++)
free(list[i] );
free(list);
EDIT
In you revised question:
int wordLine = 0, counter = 0, i;
wordLine and counter are 0
before this code:
list = malloc(sizeof(char*)*wordLine+1);
for(i = 0;i < wordLine ; i++)
list[i] = malloc(sizeof(char)*counter);
you have to assign value to wordLine and counter variable
Also memory allocation should be before the following loop(outside):
while((c = fgetc(myFile)) != EOF){
:
:
}
EDIT:
New your third version of question. You are reading file two times. So you need to fseek(), rewind() to first char before second loop starts.
try with:
fseek(fp, 0, SEEK_SET); // same as rewind()
rewind(fp); // same as fseek(fp, 0, SEEK_SET)
also I have doubt in your logic to calculate numberOfLines and maxNumberOfChars. please check that also
EDIT
I think your calculation for maxNumberOfChars = 0, numberOfLines = 0 is wrong try like this:
maxNumberOfChars = 0, numberOfLines = 0, numberOfChars = 0;
while((c = fgetc(myFile)) !=EOF){
if(c == '\n'){
numberOfLines++;
if(maxNumberOfChars < numberOfChars)
maxNumberOfChars = numberOfChars;
numberOfChars=0
}
numberOfChars++;
}
maxNumberOfChars is max number of chars in a line.
Also change code:
malloc(sizeof(char)*(maxNumberOfChars + 1));
If I were you, I'd map the file to private memory, using mmap, and then iterate over the file, storing starts of words in an array of char** that you can increase as you go with realloc, and replacing line breaks with 0.
That way, you have your words in memory as a continuous block, you don't have to care about file I/O, because you have the entire text file in memory as char*, and you don't have to malloc an array of arrays.
For information on the functions, see the respective man pages, or drop me a comment :)
EDIT: If you don't know mmap yet, have a look at this: http://www.jimscode.ca/index.php/component/content/article/13-c/45-c-simple-mmap-example
Most C programmers today still try to read files into memory using fopen and friends, but that's completely unnecessary and introduces additionel levels of complexity. (buffering, growing arrays, ...) and mmap is a nice alternative that moves all the nasty work down to the OS
Declaring Static Character Arrays (strings)
When you know (or have a reasonable idea how large your array needs to be, you can simply declare an array of sufficient size to handle your input (i.e. if you names are no longer than 25 characters, then you could safely declare name[26]. For strings, you always need at minimum the number of chars to store + 1 (for the null-terminating character).
If there may be a few characters more than 25, there's nothing wrong with declaring your array few bytes longer than needed to protect against accidental writing beyond the end of the array. Say name[32].
Let's declare an array of 5-characters below and look at how the information is stored in memory.
char name[5] = {0}; /* always initialize your arrays */
The above declaration creates an array of 5-contiguous bytes on the stack for your use. e.g., you can visualize the 5-bytes of memory initialized to zero as follows:
+---+---+---+---+---+
name | 0 | 0 | 0 | 0 | 0 |
+---+---+---+---+---+
\
'name' holds the starting address for
the block of memory that is the array
(i.e. the address of the first element
like: 0x7fff050bf3d0)
Note: when using name to hold a 'character string', the actual string can be no longer than 4 chars because you must end a sting with a null-terminating character, which is the null-character '\0' (or simply numeric 0, both are equivalent)
To store information in name, you can either do it by assigning characters one-at-a-time:
name[0] = 'J';
name[1] = 'o';
name[2] = 'h';
name[3] = 'n';
name[4] = 0; /* null-terminate. note: this was already done by initialization */
In memory you now have:
+---+---+---+---+---+
name | J | o | h | n | 0 | /* you actually have the ASCII value for */
+---+---+---+---+---+ /* each letter stored in the elements */
Of course, nobody assigns one character at a time in this manner. You options are many, using one of the functions provided by C, e.g. strcpy, strncpy, memcpy, or by reading information from a file stream, or file descriptor with fgets, getline, or by using a simple loop and index variable to do the assignment, or by using one of the string formatting functions, e.g. sprintf, etc... For example you can accomplish the same thing with any of the following:
/* direct copy */
strcpy (name, "John");
strncpy (name, "John", 5);
memcpy (name, "John", sizeof "John"); /* include copy of the terminating char */
/* read from stdin into name */
printf ("Please enter a name (4 char max): ");
scanf ("%[^\n]%*c", name);
Note: above with strncpy, if you had NOT initialized all element to 0 (the last of which will serve as your null-terminating character, and then used strncpy (name, "John", 4); you would need to manually terminate the string with name[4] = 0;, otherwise you would not have a valid string (you would have an unterminated array of chars which would lead to undefined behavior if you used name where a string was expected.)
If you do not explicitly understand this STOP, go read and understand what a null-terminated string is and how it differs from an array of characters. Seriously, stop now and go learn, it is that fundamental to C. (if it doesn't end with a null-terminating character - it isn't a c-string.
What if I don't know how many characters I need to store?
Dynamic Allocations of Character Strings
When you do not know how many characters you need to store (or generally how many of whatever data type), the normal approach is to declare a pointer to type, and then allocate a reasonably anticipated amount of memory (just based on your best understanding of what you are dealing with), and then reallocate to add additional memory as required. There is no magic to it, it is just a different way of telling the compiler how to manage the memory. Just remember, when you allocate the memory, you own it. You are responsible for (1) preserving a pointer to the beginning address of the memory block (so it can be freed later); and (2) freeing the memory when you are done with it.
A simple example will help. Most of the memory allocation/free functions are declared in stdlib.h.
char *name = NULL; /* declare a pointer, and initialize to NULL */
name = malloc (5 * sizeof *name); /* allocate a 5-byte block of memory for name */
if (!name) { /* validate memory was allocated -- every time */
fputs ("error: name allocation failed, exiting.", stderr);
exit (EXIT_FAILURE);
}
/* Now use name, just as you would the statically declared name above */
strncpy (name, "John", 5);
printf (" name contains: %s\n", name);
free (name); /* free memory when no longer needed.
(if reusing name, set 'name = NULL;')
*/
Note: malloc does NOT initialize the contents of the memory it allocates. If you want to initialize your new block of memory with zero (as we did with the static array), then use calloc instead of malloc. You can also use malloc and then call memset as well.
What happens if I allocate memory, then need More?
As mentioned above discussing dynamic memory, the general scheme is to allocate a reasonable anticipated amount, then realloc as required. You use realloc to reallocate the original block of memory created by malloc. realloc essentially creates a new block of memory, copies the memory from your old block to the new, and then frees the old block of memory. Since the old block of memory is freed, you want to use a temporary pointer for reallocation. If reallocation fails, you still have your original block of memory available to you.
You are free to add as little or as much memory as you like at any call to realloc. The standard scheme usually seen is to start with some initial allocation, then reallocate twice that amount each time you run out. (the means you need to keep track of how much memory is currently allocated).
To sew this up, let's end with a simple example that simply reads a string of any length as the first argument to the program (use "quotes" if your string contains whitespace). It will then allocates space to hold the string, then reallocate to append more text to the end of the original string. Finally it will free all memory in use before exit:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main (int argc, char **argv) {
if (argc < 2) { /* validate input */
fprintf (stderr, "error: insufficient input. usage: %s \"name\"\n",
argv[0]);
return 1;
}
size_t len = strlen (argv[1]); /* length of input */
size_t sz_mem = len + 1; /* memory required */
char *name = malloc (sz_mem * sizeof *name); /* allocate memory for name */
if (!name) { /* validate memory created successfully or throw error */
fputs ("error: name allocation failed, exiting.", stderr);
return 1;
}
printf ("\n allocated %zu bytes of memory for 'name'\n", sz_mem);
memset (name, 0, sz_mem); /* initialize memory to zero (optional) */
strncpy (name, argv[1], sz_mem); /* copy the null-terminator as well */
printf (" name: '%s' (begins at address: %p)\n", name, name);
/* realloc - make name twice as big */
void *tmp = realloc (name, 2 * sz_mem); /* use a temporary pointer */
if (!tmp) { /* check realloc succeeded */
fprintf (stderr, "error: virtual memory exhausted, realloc 'name'\n");
return 1;
}
memset (tmp + sz_mem, 0, sz_mem * sizeof *name); /* zero new memory */
name = tmp; /* assign new block to name */
sz_mem += sz_mem; /* update current allocation size */
printf (" reallocated 'name' to %zu bytes\n", sz_mem);
strncat (name, " reallocated", sizeof " reallocated");
printf ("\n final name : '%s'\n\n", name);
free (name);
return 0;
}
Use/Output
$ ./bin/arraybasics "John Q. Public"
allocated 15 bytes of memory for 'name'
name: 'John Q. Public' (begins at address: 0xf17010)
reallocated 'name' to 30 bytes
final name : 'John Q. Public reallocated'
Memory Check
When you dynamically allocate memory, it is up to you to validate you are using the memory correctly and that you track and free all the memory you allocate. Use a memory error checker like valgrind to veryify your memory use is correct. (there is no excuse not to, it is dead-bang-simple to do) Just type valgrind yourprogramexe
$ valgrind ./bin/arraybasics "John Q. Public"
==19613== Memcheck, a memory error detector
==19613== Copyright (C) 2002-2012, and GNU GPL'd, by Julian Seward et al.
==19613== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info
==19613== Command: ./bin/arraybasics John\ Q.\ Public
==19613==
allocated 15 bytes of memory for 'name'
name: 'John Q. Public' (begins at address: 0x51e0040)
reallocated 'name' to 30 bytes
final name : 'John Q. Public reallocated'
==19613==
==19613== HEAP SUMMARY:
==19613== in use at exit: 0 bytes in 0 blocks
==19613== total heap usage: 2 allocs, 2 frees, 45 bytes allocated
==19613==
==19613== All heap blocks were freed -- no leaks are possible
==19613==
==19613== For counts of detected and suppressed errors, rerun with: -v
==19613== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 2 from 2)
In the output, the following lines are of particular significance:
==19613== HEAP SUMMARY:
==19613== in use at exit: 0 bytes in 0 blocks
==19613== total heap usage: 2 allocs, 2 frees, 45 bytes allocated
This tells you that all memory allocated during your program has been properly freed. (make sure you close all open file streams, they are dynamically allocated as well).
Of equal importance is the ERROR SUMMARY:
==19613== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 2 from 2)
There are no errors in the memory use. If you attempt to read, write or free memory from a location outside your block, or from an unitialized location or that would leave other memory unreachable, that information will show as an error.
(the suppressed: 2 from 2 just relate to additional debug libraries not present on my system)
This ended up longer than intended, but if it helps, it was worth it. Good luck.
How can I announce the array and then define it's size?
Don't; 'announce' it when you know what size it needs to be. You can't use it before then anyway.
In C99 and later, you can define variables when needed β anywhere in a statement block. You can also use VLAs (variable-length arrays) where the size is not known until runtime. Don't create enormous arrays as VLAs (e.g. 1 MiB or more β but tune the limit to suit your machine and prejudices); use dynamic memory allocation after all.
If you're stuck with the archaic C89/C90 standard, then you can only define variables at the start of a block, and arrays have sizes known at compile time, so you have to use dynamic memory allocation β malloc(), free() etc.
If i have an array already full of data in a function:
char line [10] [128]
how would i dynamically allocate it so that i can use it in other functions?
Almost. Strings are NUL terminated, so you probably want to allocate an extra byte to store the NUL byte. That is, even though sides is 1 character long, it really is 2 bytes: {5,'\0'}.
So it would be:
tempSides = (char *)malloc((strlen(sides)+1)*sizeof(char));
and if you wanna copy it in:
strcpy(tempSides, sides);
Note that:
- Strings are zero-terminated (\0), and strlen() doesn't count it;
- By definition, sizeof(char) is 1 (byte), so it's not required;
- If you use a C (not C++) compiler, there's no need to cast it to
char *;
So that would be:
char *tempSides = malloc(strlen(inSides) + 1);
Still, if you want to duplicate the contents of inSides, you can use strdup, e.g.:
char *tempSides = strdup(inSides);
if (tempSides != NULL) {
// do whatever you want...
free(tempSides);
}
In this declaration
char **s = calloc(n, 10 * (sizeof(char) + 1));
you allocated a memory the address of which is assigned to the pointer s. The memory was zero-initialized due to calling the function calloc.
So in this statement
fgets(*(s + i), 10 * (sizeof(char) + 1), stdin);
the pointer s is dereferenced and either is a null pointer (because the pointed memory was zero-initialized) or has an indeterminate value if the expression s + i points outside the allocated memory.
You need to allocate an array of pointers of the type char * and assign to each pointer the address of an allocated array of characters.
Also in general you should check the return value of a call of calloc or malloc.
There is another problem with your code. After the call of scanf
scanf("%i", &n); //number of strings being inputted
the input buffer contains the new line character '\n' that will be read by the following call of fgets. So the first call of fgets will read in fact an empty string.
Another problem is that you should remove the new line character that can be appended to the read string by fgets. For example some read string can contain the new .line character while others can be without it depending on how many characters the user typed.
If you want to write the program without using the subscript operator with pointers then it can look for example the following way.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
size_t n = 0;
if ( scanf( "%zu", &n ) == 1 )
{
scanf( "%*[^\n]" );
scanf( "%*c" );
}
char **s = NULL;
if ( n != 0 ) s = calloc( n, sizeof( char * ) );
if ( s != NULL )
{
size_t len = 11;
size_t m = 0;
while ( m < n && ( *( s + m ) = malloc( len * sizeof( char ) ) ) != NULL ) m++;
size_t i = 0;
while ( i < m && fgets( *( s + i ), len, stdin ) != NULL ) i++;
m = i;
for ( i = 0; i < m; i++ ) //print the strings
{
( *( s + i ) )[ strcspn( *( s + i ), "\n" )] = '\0';
// or without the subscript operator
// *( *( s + i ) + strcspn( *( s + i ), "\n" ) ) = '\0';
puts( *( s + i ) );
}
for ( i = 0; i < n; i++ ) free( *( s + i ) );
}
free( s );
return 0;
}
The program output might look like
10
one
two
three
four
five
six
seven
eight
nine
ten
one
two
three
four
five
six
seven
eight
nine
ten
scanf("%i", &n); //number of strings being inputted
is incomplete, since scanf(3) can fail (e.g. if your user enters hello). You need to add more code checking that scanf was successful. I suggest:
if (scanf("%i", &n) < 0) {
perror("number of strings expected");
exit(EXIT_FAILURE);
}
Then
char **s = calloc(n, 10 * (sizeof(char) + 1));
is wrong. Each element of the array is a char*, which on most machines has 4 or 8 bytes (the sizeof(void*)).
So replace it with
char **s = calloc(n, sizeof(char*));
or with the equivalent char**s = calloc(n, sizeof(*s)); which in my opinion is less readable.
Also, calloc can fail. You need to add a test, like
if (s == NULL) {
perror("calloc of s");
exit(EXIT_FAILURE);
}
Read carefully the documentation of each function (like calloc, fgets etc...) which you did not wrote in this C reference.
The next step should be a loop filling each element of s. With another calloc, or some call to strdup(3) if your system provides it. Of course, that calloc (or strdup) can also fail and you need to test against failure.
You could also use getline(3) (or even readline(3)) if your system has it. Check with your manager if you are legally and technically allowed to use them.
If your compiler is GCC, invoke it with all warnings and debug info: gcc -Wall -Wextra -g. Once you have no warnings, use a debugger like GDB to understand the behavior of your executable.
Consider also using the Clang static analyzer (after getting permission to use it).
Draw on board (or on paper) a figure with arrows representing pointers (like the doubly linked-list figure on wikipedia) to understand the behavior of your program.