I was wondering is it possible to create one endless array which can store endlessly long strings?
So what I exactly mean is, I want to create a function which gets i Strings with n length.I want to input infinite strings in the program which can be infinite characters long!
void endless(int i){
//store user input on char array i times
}
To achieve that I need malloc, which I would normally use like this:
string = malloc(sizeof(char));
But how would that work for lets say 5 or 10 arrays or even a endless stream of arrays? Or is this not possible?
Edit:
I do know memory is not endless, what I mean is if it where infinite how would you try to achieve it? Or maybe just allocate memory until all memory is used?
Edit 2:
So I played around a little and this came out:
void endless (char* array[], int numbersOfArrays){
int j;
//allocate memory
for (j = 0; j < numbersOfArrays; j++){
array[j] = (char *) malloc(1024*1024*1024);
}
//scan strings
for (j = 0; j < numbersOfArrays; j++){
scanf("%s",array[j]);
array[j] = realloc(array[j],strlen(array[j]+1));
}
//print stringd
for (j = 0; j < numbersOfArrays; j++){
printf("%s\n",array[j]);
}
}
However this isn't working maybe I got the realloc part terrible wrong?
The memory is not infinite, thus you cannot.
I mean the physical memory in a computer has its limits.
malloc() will fail and allocate no memory when your program requestes too much memory:
If the function failed to allocate the requested block of memory, a null pointer is returned.
Assuming that memory is infinite, then I would create an SxN 2D array, where S is the number of strings and N the longest length of the strings you got, but obviously there are many ways to do this! ;)
Another way would be to have a simple linked list (I have one in List (C) if you need one), where every node would have a char pointer and that pointer would eventually host a string.
You can define a max length you will assume it will be the max lenght of your strings. Otherwise, you could allocate a huge 1d char array which you hole the new string, use strlen() to find the actual length of the string, and then allocate dynamically an array that would exactly the size that is needed, equal of that length + 1 for the null-string-terminator.
Here is a toy example program that asks the user to enter some strings. Memory is allocated for the strings in the get_string() function, then pointers to the strings are added to an array in the add_string() function, which also allocates memory for array storage. You can add as many strings of arbitrary length as you want, until your computer runs out of memory, at which point you will probably segfault because there are no checks on whether the memory allocations are successful. But that would take an awful lot of typing.
I guess the important point here is that there are two allocation steps: one for the strings and one for the array that stores the pointers to the strings. If you add a string literal to the storage array, you don't need to allocate for it. But if you add a string that is unknown at compile time (like user input), then you have to dynamically allocate memory for it.
Edit:
If anyone tried to run the original code listed below, they might have encountered some bizarre behavior for long strings. Specifically, they could be truncated and terminated with a mystery character. This was a result of the fact that the original code did not handle the input of an empty line properly. I did test it for a very long string, and it seemed to work. I think that I just got "lucky." Also, there was a tiny (1 byte) memory leak. It turned out that I forgot to free the memory pointed to from newstring, which held a single '\0' character upon exit. Thanks, Valgrind!
This all could have been avoided from the start if I had passed a NULL back from the get_string() function instead of an empty string to indicate an empty line of input. Lesson learned? The source code below has been fixed, NULL now indicates an empty line of input, and all is well.
#include <stdio.h>
#include <stdlib.h>
char * get_string(void);
char ** add_string(char *str, char **arr, int num_strings);
int main(void)
{
char *newstring;
char **string_storage;
int i, num = 0;
string_storage = NULL;
puts("Enter some strings (empty line to quit):");
while ((newstring = get_string()) != NULL) {
string_storage = add_string(newstring, string_storage, num);
++num;
}
puts("You entered:");
for (i = 0; i < num; i++)
puts(string_storage[i]);
/* Free allocated memory */
for (i = 0; i < num; i++)
free(string_storage[i]);
free(string_storage);
return 0;
}
char * get_string(void)
{
char ch;
int num = 0;
char *newstring;
newstring = NULL;
while ((ch = getchar()) != '\n') {
++num;
newstring = realloc(newstring, (num + 1) * sizeof(char));
newstring[num - 1] = ch;
}
if (num > 0)
newstring[num] = '\0';
return newstring;
}
char ** add_string(char *str, char **arr, int num_strings)
{
++num_strings;
arr = realloc(arr, num_strings * (sizeof(char *)));
arr[num_strings - 1] = str;
return arr;
}
I was wondering is it possible to create one endless array which can store endlessly long strings?
The memory can't be infinite. So, the answer is NO. Even if you have every large memory, you will need a processor that could address that huge memory space. There is a limit on amount of dynamic memory that can be allocated by malloc and the amount of static memory(allocated at compile time) that can be allocated. malloc function call will return a NULL if there is no suitable memory block requested by you in the heap memory.
Assuming that you have very large memory space available to you relative to space required by your input strings and you will never run out of memory. You can store your input strings using 2 dimensional array.
C does not really have multi-dimensional arrays, but there are several ways to simulate them. You can use a (dynamically allocated) array of pointers to (dynamically allocated) arrays. This is used mostly when the array bounds are not known until runtime. OR
You can also allocate a global two dimensional array of sufficient length and width. The static allocation for storing random size input strings is not a good idea. Most of the memory space will be unused.
Also, C programming language doesn't have string data type. You can simulate a string using a null terminated array of characters. So, to dynamically allocate a character array in C, we should use malloc like shown below:
char *cstr = malloc((MAX_CHARACTERS + 1)*sizeof(char));
Here, MAX_CHARACTERS represents the maximum number of characters that can be stored in your cstr array. The +1 is added to allocate a space for null character if MAX_CHARACTERS are stored in your string.
Related
Here is my code snippet to create the 2D array that holds char array. It would be great if someone could find out what could be the reason. I have tried using both malloc() and calloc() to allocate memory to the 2D array, yet no positive signs.
Code Snippet:
char** attrNames = (char **)malloc(3*sizeof(char*))
for (m = 0; m < 3; m++) {
attrNames[m] = (char *)malloc(2 * sizeof(char*));
strcpy(schema->attrNames[m], temp_buff2[m]);
}
I am trying to allocate the memory and then going on a loop and again allocating memory and copy the data from a variable called temp_buff2 (has character data) into the char array.
Try the code below. Even though memory allocation error in your project might be unlikely, now is a good time to develop a good error handling reflex - it will save your bacon when you move on to more serious projects.
Note that char* pointer needs a buffer that is equal to the length of the string plus one extra byte. sizeof(char*) is a small value, only 8 on a 64-bit architecture - it just stores the value of the memory address where the string starts. Note that we need +1 on top of strlen() because strcpy() will store one extra byte (\0) as a string terminator.
char** attrNames = (char **)malloc(3*sizeof(char*));
if (!attrName)
{
// handle memory error
}
for (m = 0; m < 3; m++) {
attrNames[m] = (char *)malloc(strlen(temp_buff2[m])+1);
if (!attrNames[m])
{
// handle memory error
}
strcpy(schema->attrNames[m], temp_buff2[m]);
}
Memory error can be handled by returning an error code from your function or via a fatal exit like this:
fprintf(stderr, "Out of memory\n");
exit(1);
You will need to #include <stdlib.h> for the prototype of exit().
You need to reserve enough space for whatever you have inside "temp_buff2". For example:
char** attrNames = (char **)malloc(3*sizeof(char*))
for (m = 0; m < 3; m++) {
attrNames[m] = (char *)malloc( strlen(temp_buff2[m]) + 1 );
strcpy(schema->attrNames[m], temp_buff2[m]);
}
Notice that I am adding 1 to the strlen result, this is because we need to reserve an additional byte for the null char terminator.
In my application, we take in char values one at a time and we need to be able to but them into a string. We are assembling these strings one by one by putting the char values into a char array, then clearing the array. However the strings are each different lengths and we are unable to determine the size of the string. How can we change the sizes of the array to add more space as we need it?
Also, how can we print out the array?
If the array was dynamically allocated with malloc, you can resize it with realloc:
int array_size = 1024;
char *array = (char *) malloc(array_size);
int n = 0;
char c;
while ((c = getchar()) != EOF) {
array[n++] = c;
if (n >= array_size) {
array_size += 1024;
array = (char *) realloc(array_size);
}
}
array[n] = '\0';
For printing out the contents of the array, you can simply pass it to printf or puts:
printf("%s\n", array);
puts(array);
if you don'y know the size you are going to need and are adding one character at a time you can consider using a linked list. It can grow as much as you need it to. The disadvntages would be lookup is kind of slow, and if you need to free the memory, or clear it you would have to do this for each element, one at a time.
You can also take the dynamic array approach: allocate a certain size which you consider large enough and when that is 80% full, allocate a new buffer, twice as large and copy the contents of the old one in the new, larger one.
I need to fill an c array with a number of objects which I don't know before the process of filling is completed.
It's an array of strings.
Another addition: I'm dividing a string into it's words so I know the size of the string. Cloud this be helpful to guess the right size?
I need to have something like an mutable array.
How can I achieve this?
Update
Given that you're chunking the string (dividing it into words), you could count the number of spaces, giving you an idea of how big an array you'll need:
char givenString[] = "The quick brown fox jumps over the lazy dog";
int i;
for (i=0;givenString[i];givenString[i] == ' ' ? ++i : givenString++);
++i;// + 1 for the last word
Now i will tell you how many words there are in the given string. Then you can simply do:
char **words = malloc(i*sizeof(char *));
And set about your business. Of course, you'll still have to allocate each word pointer, and free it. Perhaps this is a decent use-case for strtok, BTW:
//assuming i still holds the word-count
words[0] = strtok(givenString, " ");//
for (int j=1;j<i;++j)
{
words[j] = strtok(NULL, " ");
}
You might want to look into strtok_r if you're going to be doing a lot of this string-splitting business, though.
You could use realloc for that. realloc changes the size of the block of memory that a given pointer points to. If the pointer points to NULL, realloc behaves like malloc
char **ptr_array = NULL;
for (int i=1;i<argc;++i)
{
ptr_array = realloc(ptr_array, i*sizeof(char *));
ptr_array[i-1] = calloc(strlen(argv[i]) + 1, sizeof(char));
strncpy(ptr_array[i-1], argv[i], strlen(argv[i]));
}
This code will copy all arguments to heap memory, one by one allocating memory for the memory required. Don't forget the free calls, mind you!
Here's an example in full (including free-calls)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char **ptr_array = NULL;//pointer to pointers
int i, argc = 5;//fake argc, argv
char *argv[5] = {"me","foo","bar","zar", "car"};//dummy strings
for (i=1;i<argc;++i)
{
ptr_array = realloc(ptr_array, i*sizeof(char *));//(re-)allocate mem
ptr_array[i-1] = calloc(strlen(argv[i]) + 1, sizeof(char));//alloc str
strncpy(ptr_array[i-1], argv[i], strlen(argv[i]));//copy
}
--argc;
for(i=0;i<argc;++i)
{
printf("At index %d: %s\n", i, ptr_array[i]);//print
free(ptr_array[i]);//free string mem
}
free(ptr_array);//free pointer block
return 0;
}
I've tested this code, and the output was, as you'd expect:
At index 0: foo
At index 1: bar
At index 2: zar
At index 3: car
You could use realloc to declare your array and change its size when needed.
myStrArray = realloc(myStrArray, MaxArray * sizeof(char*));
Realloc will return the same block of memory in most cases until it's "full" and then it will move the memory and contents to somewhere else.
Please note this is an array of pointers and so the strings themselves will need to be allocated or assigned to it. To allocate a 100 char string to the first element, for example:
myStrArray[0] = calloc(100, sizeof(char));
And always free your allocated memory with free (realloc, calloc, malloc).
Since you don't know a priori the size of the array, you must use malloc() to dynamically allocate the memory for the array and for the strings contained in it.
You then must use free() to release this memory when it is no longer needed.
To have good locality, you may want to allocate a single chunk of memory for the strings in the array, considering a data structure like double-NUL terminated strings.
char* username[30];
memset(username,0x00,30);
scanf("%s",&username);
would this make pointers point to random place in memory or it's safe to use ?
char *username[30] is an array of pointers, not characters. So your code is very wrong (as in not safe). To get an array of characters you need:
char username[30];
char* username[30]; //is array of char pointers.
//Allocate memory for these pointers using calloc(). so no need of memset().
memset(username,0x00,30);//can be removed.
scanf("%s",&username);//It should be scanf("%s",username[i]);
#perreal, Sample added.
#define SIZE 100 //100 chars...
char* username[30];
int i;
for(i = 0; i < 30; i++)
{
username[i] = calloc(SIZE, sizeof(char)); //Add Fail checks if needed.
scanf("%s",username[i]);
}
so with the above code, you can get 30 strings. If you need only one string with 30 char then
char username[30];
memset(username,0x00,30);
scanf("%s",username);
is enough.
with
memset(username,0x00,30);
you are initializing the first 30 bytes of your array of pointers and not the whole array
memset(username,0, sizeof(username));
would set everything to 0 although a simple loop is clearer for the reader (IMHO)
for (int i = 0; i < 30; username[i++] = NULL) {;}
don't do this:
scanf("%s",&username);
scanf doesn't magically allocate anything -- "username" is an array of pointers and are NULL pointers, how should scanf know how to allocate memory etc? Instead do a loop, let user enter a string, allocate memory for that string (+1), copy the string to the allocated memory and assign it to "username[i]".
What you PROBABLY want is:
int i;
char* username[30];
for(i = 0; i < 30; i++)
{
username[i] = calloc(100, sizeof(char)); // or whatever size your string is.
scanf("%s",username[i]);
}
... Code using usernames ...
for(i = 0; i < 30; i++)
{
free(username[i]);
}
But personally, I'd probably go for:
int i;
char username[30][100];
for(i = 0; i < 30; i++)
{
scanf("%s",username[i]);
}
Saves on having to free the pointers later.
That will read 30 strings into your username array.
If you want to just read one username:
char username[30] = {0}; // Same as memset, but shorter to write!
scanf("%s", username);
Although as others have suggested, scanf() is't the best function to read "user generated input" - it's fine for data that your program has already "checked" (that is, it contains no "funny stuff", fits in the length provided, etc) and written to a file [using fscanf()]. For user input, use fgets() to read a line of text, and then work through it in whatever way is suitable to get the actual data out of the string.
For example, if some username has more than 100 characters [or thirty in the last example], the string will overflow, and nothing good will ever come from that [and in really bad cases, you won't notice until MUCH later, which makes it hard to debug - if you are lucky, it crashes immediately].
char* username[30];
memset(username,0x00,30);
scanf("%s",&username);
the above your code will get crash , because you are trying to input into pointer for which memory is not allocated. so first you allocate memory for the pointers and then you read into that memory location.
char *username[30]
This is an array of pointers to characters..
go for char username[30]
Context: I'm trying to do is to make a program which would take text as input and store it in a character array. Then I would print each element of the array as a decimal. E.g. "Hello World" would be converted to 72, 101, etc.. I would use this as a quick ASCII2DEC converter. I know there are online converters but I'm trying to make this one on my own.
Problem: how can I allocate an array whose size is unknown at compile-time and make it the exact same size as the text I enter? So when I enter "Hello World" it would dynamically make an array with the exact size required to store just "Hello World". I have searched the web but couldn't find anything that I could make use of.
I see that you're using C. You could do something like this:
#define INC_SIZE 10
char *buf = (char*) malloc(INC_SIZE),*temp;
int size = INC_SIZE,len = 0;
char c;
while ((c = getchar()) != '\n') { // I assume you want to read a line of input
if (len == size) {
size += INC_SIZE;
temp = (char*) realloc(buf,size);
if (temp == NULL) {
// not enough memory probably, handle it yourself
}
buf = temp;
}
buf[len++] = c;
}
// done, note that the character array has no '\0' terminator and the length is represented by `len` variable
Typically, on environments like a PC where there are no great memory constraints, I would just dynamically allocate, (language-dependent) an array/string/whatever of, say, 64K and keep an index/pointer/whatever to the current end point plus one - ie. the next index/location to place any new data.
if you use cpp language, you can use the string to store the input characters,and access the character by operator[] , like the following codes:
std::string input;
cin >> input;
I'm going to guess you mean C, as that's one of the commonest compiled languages where you would have this problem.
Variables that you declare in a function are stored on the stack. This is nice and efficient, gets cleaned up when your function exits, etc. The only problem is that the size of the stack slot for each function is fixed and cannot change while the function is running.
The second place you can allocate memory is the heap. This is a free-for-all that you can allocate and deallocate memory from at runtime. You allocate with malloc(), and when finished, you call free() on it (this is important to avoid memory leaks).
With heap allocations you must know the size at allocation time, but it's better than having it stored in fixed stack space that you cannot grow if needed.
This is a simple and stupid function to decode a string to its ASCII codes using a dynamically-allocated buffer:
char* str_to_ascii_codes(char* str)
{
size_t i;
size_t str_length = strlen(str);
char* ascii_codes = malloc(str_length*4+1);
for(i = 0; i<str_length; i++)
snprintf(ascii_codes+i*4, 5, "%03d ", str[i]);
return ascii_codes;
}
Edit: You mentioned in a comment wanting to get the buffer just right. I cut corners with the above example by making each entry in the string a known length, and not trimming the result's extra space character. This is a smarter version that fixes both of those issues:
char* str_to_ascii_codes(char* str)
{
size_t i;
int written;
size_t str_length = strlen(str), ascii_codes_length = 0;
char* ascii_codes = malloc(str_length*4+1);
for(i = 0; i<str_length; i++)
{
snprintf(ascii_codes+ascii_codes_length, 5, "%d %n", str[i], &written);
ascii_codes_length = ascii_codes_length + written;
}
/* This is intentionally one byte short, to trim the trailing space char */
ascii_codes = realloc(ascii_codes, ascii_codes_length);
/* Add new end-of-string marker */
ascii_codes[ascii_codes_length-1] = '\0';
return ascii_codes;
}