C Increase char array of char array size - c

I have a char array of char array like so:
char my_test[2][10];
As you can see I have a length of 2 and then 10. If I need to increase the first char array (2), how can this be done dynamically?
For example, half way through my application char[2] might be in use so therefore I need to use position 3 in the char array. I would then end up with this:
char store[3][10];
But keeping the data originally store in:
char store[0][10];
char store[1][10];
char store[2][10];

You should dynamically allocate memory for the array using standard C functions malloc and realloc declared in header <stdlib.h>.
Here is a demonstrative program that shows how the memory can be allocated.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define N 10
int main(void)
{
size_t n = 2;
char ( *my_test )[N] = malloc( n * sizeof( char[N] ) );
strcpy( my_test[0], "first" );
strcpy( my_test[1], "second" );
for ( size_t i = 0; i < n; i++ ) puts( my_test[i] );
putchar( '\n' );
char ( *tmp )[N] = realloc( my_test, ( n + 1 ) * sizeof( char[N] ) );
if ( tmp != NULL )
{
my_test = tmp;
strcpy( my_test[n++], "third" );
}
for ( size_t i = 0; i < n; i++ ) puts( my_test[i] );
free( my_test );
return 0;
}
The program output is
first
second
first
second
third

char my_test[2][10];
is compile-time constant, which means that the required memory to use that array is carved to the stone already before your application starts. So you will never be able to change it's size.
You'll have to use DYNAMIC allocation. Check for something called malloc and free in case you are really working with C, or with C++ new and delete are what you need. You'll also need to learn about pointers.

Related

I can't figure out how to use double pointers

I'm trying to use dynamic memory allocation but I can't figure out pointers.
I got the first part down.
void addtext(char **wordarray)
{
char word[N];
char endword[N] = "end";
int i=0;
int words=0;
while (scanf("%19s", word), strcmp(word,endword))
{
words++;
wordarray = realloc(wordarray, words*sizeof(char *));
wordarray[words-1] = malloc (N*sizeof(char));
strcpy(wordarray[words-1], word);
}
for (i=0; i<words; i++)
printf("%s\n", wordarray[i]);
return ;
}
But I'm having trouble when I try to call the same array in a different function.
void savetext(char **wordarray)
{
FILE *savedtext;
int i=0;
savedtext = fopen("Saved Text.txt","wt");
while(wordarray[i][0]!= '\0')
{
fputs(wordarray[i++],savedtext);
fputs(" ",savedtext);
}
return ;
}
My main function looks something like this:
int main (void)
{
char **wordarray;
addtext(wordarray);
savetext(wordarray);
return 0;
}
The second part of the code is obviously wrong, but I'm not sure how to exactly how to call those functions. My previous program didn't use any memory allocation so I didn't bother with pointers.I'm really new to c so any help would be appreciated.
Oh boy. Well, you have two big problems.
First, you never allocated the first wordarray. At the very least malloc it once:
char **wordarray = malloc(1);
Or even better, use malloc instead of realloc the first time (and initialize wordarray with 0!):
wordarray = wordarray ? realloc(wordarray, words * sizeof(char *))
: malloc(words * sizeof(char *));
Second, your addtext function is receiving a copy of this array, and doing stuff with it. Whatever the stuff is, it won't be saved in your wordarray outside, in main. What you need to do is pass a pointer to the array in your function, and edit the main object through that:
void addtext(char ***wordarray)
{
// ...
}
And lastly, you have some very big performance problems, allocating buffers so often. Use a proper growing vector implementation, or if you insist on writing your own at the very least grow it by doubling the size, or even better count the words and allocate the correct size.
Also your end string is arbitrarily allocated of length N, whatever that is. You don't need that, you already know the length. In fact the string is already in the read-only section of your binary, simply get a pointer to it:
const char *endword = "end";
Perhaps refactor your program to make the string creation its own function, and for symmetry, return storage of the string as its own function.
const int STRING_SIZE = 80;
void createString(char ** strPtr, int stringSize);
void freeString(char * strPtr);
int main(int argc, char ** argv) {
char * strValue = NULL;
createString(&strValue, STRING_SIZE);
// ... do stuff ...
freeString(strValue);
}
//
// end of main
//
void createString(char ** strPtr, int stringSize) {
//
// uses pass-by-reference to return *strPtr with allocated storage
//
*strPtr = (char *) calloc(stringSize, sizeof(char));
}
void freeString(char * strPtr) {
if(strPtr == NULL) return;
free(strPtr);
strPtr = NULL;
}
For starters the program has undefined behavior at least because the pointer wordarray was not initialized and has an indeterminate value
char **wordarray;
and this indeterminate value is used in a call of the function realloc in the function addtext
wordarray = realloc(wordarray, words*sizeof(char *));
Moreover the pointer is passed to the function addtext by value. That is the function deals with a copy of the value of the pointer. So changing the copy does not influence on the value stored in the original pointer. The original pointer in main will stay unchanged.
You need to pass the pointer by reference through a pointer to it.
Another problem of the function is that the number of stored strings will not be known outside the function addtext. You need at least append the array with a null pointer that will be used as a sentinel value.
Also this condition in the while loop within the function savetext
while(wordarray[i][0]!= '\0')
does not make a sense because within the function addtext you stop entering strings when the user will enter the string "end".
while (scanf("%19s", word), strcmp(word,endword))
^^^^^^^^^^^^^^^^^^^^
So it is not necessary that the preceding entered string is an empty string.
Here is a demonstrative program that shows how for example the function addtext can be declared and defined.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define N 20
size_t addtext( char ***wordarray )
{
char word[N];
const char *sentinel = "end";
size_t n = 0;
int success = 1;
while ( success && scanf( "%19s", word ) == 1 && strcmp( word, sentinel ) != 0 )
{
char **tmp = realloc( *wordarray, ( n + 1 ) * sizeof( char * ) );
success = tmp != NULL;
if ( success )
{
++n;
*wordarray = tmp;
( * wordarray )[n-1] = malloc( strlen( word ) + 1 );
if ( ( *wordarray )[n-1] ) strcpy( ( *wordarray )[n-1], word );
}
}
return n;
}
int main(void)
{
char **wordarray = NULL;
size_t n = addtext( &wordarray );
for ( size_t i = 0; i < n; i++ )
{
if ( wordarray[i] != NULL ) puts( wordarray[i] );
}
for ( size_t i = 0; i < n; i++ )
{
free( wordarray[i] );
}
free( wordarray );
return 0;
}
If to enter the following sequence of strings
one
two
three
end
then the program output will be
one
two
three
Correspondingly the declaration of the function savetext should be changed. There is not sense in this case to pass the pointer wordarray to the function by reference because the pointer itself is not changed within the function. Also you need to pass the number of elements in the allocated array, So the function declaration can look at least like
void savetext( char **wordarray, size_t n );

Free(): invalid pointer in C program

I am executing following C program and getting runtime error as "free(): Invalid Pointer"
#include<stdio.h>
#include<stdlib.h>
static void freeArgs(char** args);
int main()
{
char** argv = calloc(4, 10);
int argc = 0;
argv[argc++]="yogita";
argv[argc++] ="negi";
argv[argc] = NULL;
freeArgs(argv);
return 0;
}
static void freeArgs(char** args)
{
char** af = args;
for (; *af; af++)
free(*af);
free(args);
}
Can anyone suggest me the solution?
free(*af);
tries to free memory that was not allocated through malloc/calloc:
argv[argc++]="yogita";
"yogita" is a string literal, thus not dynamically allocated. You can't free its memory.
This call
char** argv = calloc(4, 10);
(Note:it seems you mean
char** argv = calloc( 4, sizeof( char * ) );
end note)
with the magic number 10 allocates dynamically only one extent of memory of the size 4 * 10 that is equal to 40. So you need to call the function free only one time for the allocated extent. That is how many times malloc or calloc was called the same number of times free should be called.
I suspect that you meant something like the following
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static void freeArgs( char **args )
{
char **af = args;
while ( *af ) free( *af++ );
free( args );
}
int main(void)
{
enum { N = 4, LEN = 10 };
char **argv = calloc( N, sizeof( char * ) );
size_t argc = 0;
argv[argc] = malloc( LEN * sizeof( char ) );
strcpy( argv[argc++], "yogita" );
argv[argc] = malloc( LEN * sizeof( char ) );
strcpy( argv[argc++], "negi" );
freeArgs( argv );
return 0;
}

Printing char arrays from a list

It's been awhile since I had to deal with C pointers, and I'm having trouble with a project. Here's some example code I made to highlight my problem. I Just need to be able to add strings to the "wordList" and be able to retrieve them later.
// This typedef is in the header file
// typedef char Word[ WORD_LEN + 1 ];
Word wordList[ MAX_WORDS ];
int main () {
Word message = "HEllO";
Word message2 = "OHHO";
*wordList[ 0 ] = malloc ( sizeof( char ) * ( strlen( message ) + 1 ) );
*wordList[ 0 ] = *message;
*wordList[ 1 ] = malloc ( sizeof( char ) * ( strlen( message2 ) + 1 ) );
*wordList[ 1 ] = *message2;
printf( "%s\n", &wordList[0]);
printf( "%s\n", &wordList[1]);
}
Currently the words are not printing, it will only print the first letter. Any tips on where I might be messing up would be incredible. Thanks!
Use good ol' strcpy, no need for playing around with pointers.
Word message = "HEllO";
strcpy(wordList[0], message);
printf("%s\n", wordList[0]);
Or even strncpy as #alk pointed out
strncpy(wordList[0], message, sizeof(wordList[0]) - 1);
wordList[0][WORD_LEN] = '\0';
wordList is an array of C-"string"s. So use them like this:
Word message = "HEllO";
size_t size_max = sizeof wordList[0] - 1;
strncpy(wordList[0], message, size_max);
wordList[0][size_max] = '\0';
Right now wordList is an array of Word, and each word is an array of chars. When you defined Word wordList[ MAX_WORDS ] the space for MAX_WORDS number of Words of size WORD_LEN+1 has already been allocated in the global section, so you don't need to malloc more space for this.
To insert the message into the word you would use strcpy (http://www.cplusplus.com/reference/cstring/strcpy/) rather than mallocing space and assigning the message. So to insert message into wordList[0] would look like strcpy( wordList[0], message). Strcpy takes in two char * with the first being the destination of the copy and and second being the source.
Here is some example code of what you should try to do:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef char Word[ 10 ];
Word wordList[ 10 ];
int main(){
Word message = "Hello";
strcpy( wordList[0], message);
printf("%s", wordList[0]);
return 0;
}
** To be safer you can use strncpy (http://www.cplusplus.com/reference/cstring/strncpy/) instead of strcpy. Here you can specify the number of characters you want to copy as a parameter. All the code would look the same except you would change strcpy to strncpy and add in a third parameter of how many character to copy.
Since a Word is already typedef'd as a char array (C string), there's no need to use malloc to allocate memory in your array. Essentially, wordList is an array of arrays and you can just copy the contents of your strings (Words) into it at the desired indices. See the below code for a working implementation.
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
// some magic numbers
#define WORD_LEN 50
#define MAX_WORDS 20
typedef char Word[ WORD_LEN + 1 ];
Word wordList[ MAX_WORDS ];
int main () {
Word message = "HEllO";
Word message2 = "OHHO";
//wordList[ 0 ] = malloc ( sizeof( char ) * ( strlen( message ) + 1 ) );
//*wordList[ 0 ] = *message;
strncpy(wordList[0], message, sizeof(Word));
//wordList[ 1 ] = malloc ( sizeof( char ) * ( strlen( message2 ) + 1 ) );
//*wordList[ 1 ] = *message2;
strncpy(wordList[1], message2, sizeof(Word));
printf( "%s\n", wordList[0]);
printf( "%s\n", wordList[1]);
}

Can I free only a part of a string?

I am filling up a string of characters and I double its size from time to time.
When I finish, I would like to free unused memory.
void fun (char **str, size_t *len) {
size_t lsi; //last_significant_index
//filling up the str and reallocating from time to time.
//*len is storing the total size of allocated memory at this point
// idea #1
free((*str)[lsi + 1]);
// idea #2
for(size_t i = lsi + 1; i < *len; i++) {
free(&(*str)[i]);
}
}
None of these ideas seem to work however
Is it even possible to do it? If so, how?
Details:
I am using this function to reallocate my strings:
static void increase_list_size(char **list, size_t *list_len)
{
size_t new_list_size = (*list_len + 1) * 2; // I am not allocating my list at the declaration, so *list_len initially equals 0.
char *new_list = malloc(sizeof(char) * new_list_size);
for (size_t i = 0; i < *list_len; i++)
{
new_list[i] = (*list)[i];
}
if (list != NULL) // I don't want to free an empty list (it wasn't allocated at the declaration!
{
free(*list);
}
(*list) = new_list;
*list_len = new_list_size;
}
As you can see, I am allocating two-times more memory every time - that's why I wanted to free unused memory at the end.
I thought there was some kind of a tricky way to do it, since I felt that you can only use free() to free whole memory block.
No, you can only free() pointers that have been returned by malloc().
You want to use realloc() to change the allocated memory size to a smaller (as well as larger) size. The contents of the array will be preserved.
Example:
#include <stdlib.h>
int main() {
char *str = malloc(100);
...
str = realloc(str, 50);
...
free(str);
}
Remember to check the return value of realloc() (as well as the one of malloc()) to ensure that the (re)allocation has not failed.
You can only free a pointer that is the result of malloc or realloc. You can't reduce the size of an allocation by freeing at an arbitrary offset from it. But you can realloc it to a smaller size: realloc(*str, lsi).
one way is to create a new string and use only space required and copy the content to this one. now you can free the previous one.
I will use this is realloc() is not allowed (sometimes in homework)
the other way is realloc() as others suggested.
You can use standard C function realloc declared in header <stdlib.h>
For example
char *s = malloc( 100 );
strcpy( s, "Hello world" );
char *p = realloc( s, strlen( s ) + 1 );
if ( p != NULL ) s = p;
Here is a demonstrative program
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main( void )
{
char *s = malloc( 100 );
strcpy( s, "Hello world" );
char *p = realloc( s, strlen( s ) + 1 );
if ( p != NULL ) s = p;
puts( s );
free( s );
return 0;
}
The program output is
Hello world
Or if you want to write a separate function then it can look the following way
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void resize( char **s, size_t n )
{
char *p = realloc( *s, n );
if ( p != NULL ) *s = p;
}
int main( void )
{
char *s = malloc( 100 );
strcpy( s, "Hello world" );
resize( &s, strlen( s ) + 1 );
puts( s );
free( s );
return 0;
}
Also you can use POSIX function strdup

Assigning string array to char**

I just cannot assign string array to my char** pointer.
I have my strings in char *tempArr[12];
But I don't know how to assign them to my char** arr variable.
First, I allocate memory using: arr = (char**)malloc(numberOfElements * sizeof(char*));
Then I tried to allocate memory to each element:
arr[i] = malloc(256 * sizeof(char));
I also tried to alocate just the memory for char pointer but neither works. The result in my arr variable is 2 to 3 nonsense characters.
What could be wrong? I tried everything I was able to find and the result is either crash or nonsense content.
EDIT: Sorry I'll try to clarify it more. Background is, I am loading data from file into structs. Each struct has char** variable that is suppose to hold strings array.
In my reading code, I am using my temp array char* tempArr[12] and successfully loading strings into it. Then I pass it allong to my function that is creating my structs.
The problem starts here, I was trying to "convert" my passed array so it can be stored in char** arr variable.
char *tempArr[12];
Is array of pointers. So if you have something like
tempArr[0] = malloc(20);
strcpy(tempArr[0],"hello");
Then after what you are doing you can do. i.e. After allocating memory to your the pointer arr[i]
char **arr = malloc(numberOfElements * sizeof(char*));
arr[i] = malloc(256);
strcpy(arr[i],tempArr[0]);
You can run the above steps in a loop to copy values for all your pointers
I think that you mean the following
#include <string.h>
//...
size_t i;
char **arr = ( char** )malloc( numberOfElements * sizeof( char* ) );
for ( i = 0; i < numberOfElements; i++ ) arr[i] = malloc( 256 * sizeof( char ) );
for ( i = 0; i < sizeof( tempArr ) / sizeof( *tempArr ); i++ ) strcpy( arr[i], tempArr[i] );

Resources