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.
Related
I got an assignment from my teacher to write a code that compares a given word to a bunch of words located in an array of strings.
If the word in the array is lexicography smaller than the word given, I need to put it inside a new array.
else, I'm moving to the next word.
for example;
given word: hello
arr=bus, alpha, world, java.
new array=bus,alpha.
I wrote a code that does that using STRCMP, but the computer throws me out when it gets to the strcpy part.
this is my code
char** LowerSTR(char* arr[], int size_arr, char* str, int* size_res)
size_res = 0;
char** newArr= (char**)calloc(size_arr, sizeof(char));
for (int i = 0; i < size_arr; i++)
{
if (strcmp(str, arr[i])==1)
{
for (int k = 0; k <size_arr;k++)
{
strcpy(newArr[k], arr[i]);
}
size_res++;
}
}
if (size_res == 0)
return NULL;
else return newArr;}
maybe I should use STRCAT instead?
please help :\
In calling strcpy with newArr[k] as an argument you're dereferencing a NULL pointer.
Recall that we allocate newArr as follows:
char** newArr= (char**)calloc(size_arr, sizeof(char));
There's actually multiple errors here. The first is that we calloc with sizeof(char) when we in fact want a region of char*s. So corrected1
we have
char** newArr= calloc(size_arr, sizeof(char*));
As we've calloc'd this piece of memory, all of it is zeroed. Thus when strcpy internally accesses newArr[k] (itself of type char*) it points to memory address 0, which is likely reversed by the OS, and in any case, not a valid address in the context of our program.
In order to resolve this, we need to allocate for each string. For instance, one might do
newArr[k] = malloc(strlen(arr[i]) + 1); // The +1 is for the \0 termination character
the line before we strcpy.
You also have a bug with size_res as you just treat it as an int instead of an int* as you need to dereference it when you want to change or read the value to which it points.
1 See here for why I've removed the cast.
You should scan newArr and print all strings inside, something like:
for (int i = 0; i < *size_res; i++) // !
{
printf("%s\n",newArr[i]);
}
(!) 'size_res' is passed to the function as a pointer to int,
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.
I'm currently trying to make a program in c which will return a pointer to an array of 2 strings. The first is the characters of the string s that are in the odd position and the second are the characters in the even position. I'm not experienced in C so I need a bit of help with this program. I've been trying to code using what I know from python and java but it doesn't seem to follow the same principles with pointers. Here is my code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char **parity_strings(const char *s){
char dest[malloc((char)sizeof(s)/2 + 1)][malloc((char)sizeof(s)/2 + 1)]; //trying to allocate memory to an array of size 2 which will hold 2 strings.
int i;
for(i = 0; i < sizeof(s); i+= 2){ //iterating through odd strings
s[0] += dest[i];
}
for(i= 2; i< sizeof(s); i += 2){ //iterating through even strings (I suppose i could have just appended using 1 for loop but oh well
s[1] += dest[i];
}
return dest;
}
int main(int argc, char **argv) {
char **r = parity_strings(argv[1]);
printf("%s %s %s\n", r[0], r[1], argv[1]);
return 0;
}
memory allocation is just a pain too...I have no clue if it's doing what I intend on it doing. I'm trying to allocate the size of the string in bytes + 1 byte into each index of the array Dest.
any ideas on how to fix this? Thanks.
This line will not do anything good:
char dest[malloc((char)sizeof(s)/2 + 1)][malloc((char)sizeof(s)/2 + 1)];
malloc returns a pointer to the newly allocated memory. In your line above, the square brackets in dest[][] need unsigned integers. Pointers can be casted to integers, but that isn’t what you want there at all. It might compile, but it probably won’t run, and certainly won’t do what you want.
Also, sizeof(s) returns the size of the pointer to s, not the length of the string. Strings in C are really just null-terminated arrays of chars, and arrays are passed to functions with a pointer, not their entire contents. To get the length of a string, use strlen(s) instead.
You could do something like this:
char *destodd = malloc((strlen(s)/2 + 2));
char *desteven = malloc((strlen(s)/2 + 2));
char **dest = malloc(sizeof(char *) * 2);
dest[0] = desteven;
dest[1] = destodd;
I changed your + 1 above to +2. A string of length 3 needs 3 characters in destodd: one for character 1, one for character 3, and one for the NUL terminator.
It’s tricky to malloc a multi-dimensional array in C. A one-dimensional array, on the other hand, is easy. Just treat destodd and desteven like they’re arrays, even though they’re really pointers:
for (i = 0; i < strlen(s); i += 2){
desteven[i] = 'a'; // Fix this
destodd[i] = 'b';
}
The code in your for loops didn’t look like it would work. It looks like you may have been trying to use += to concatenate strings, but it only does addition of numbers. I couldn’t quickly figure out what you should set in the for loop, so 'a' and 'b' are just placeholders.
You have a few issues. As your compiler should tell you, char dest[malloc()] requires a pointer-to-unsigned cast, which is legal but is not what you want. More importantly, returning a pointer to an array allocated on the stack results in undefined behavior if you dereference the pointer, because the compiler may have already deallocated the memory. I'm not exactly sure what the intended output of the function is, but in terms of filling two char arrays, in my opinion the easiest way to do it is this:
char **parity_strings(char* buf) //Please avoid single letter variable names for anything but loop control
{
size_t buflen = strlen(buf);
if (NULL == char** dest = malloc(2 * sizeof(*dest)))
;//handle memory allocation error
if (NULL == dest[0] = malloc(buflen * sizeof(*buf)))
;//handle memory allocation error
if (NULL == dest[1] = malloc(buflen * sizeof(*buf)))
;//handle memory allocation error
//Note that you would do the above two lines in a loop for a variable sized multidimensional array
strncpy(dest[0], buf, 500);
strncpy(dest[1], buf, 500); //If you need strings larger than 500 change as necessary, mostly only needed if you are taking input from someone else but it's good practice to use strncpy over strcpy)
return dest;
}
I am trying to write a basic CSV parser in C that generates a dynamic array of char* when given a char* and a separator character, such as a comma:
char **filldoc_parse_csv(char *toparse, char sepchar)
{
char **strings = NULL;
char *buffer = NULL;
int j = 0;
int k = 1;
for(int i=0; i < strlen(toparse); i++)
{
if(toparse[i] != sepchar)
{
buffer = realloc(buffer, sizeof(char)*k);
strcat(buffer, (const char*)toparse[i]);
k++;
}
else
{
strings = realloc(strings, sizeof(buffer)+1);
strings[j] = buffer;
free(buffer);
j++;
}
}
return strings;
}
However, when I call the function as in the manner below:
char **strings = filldoc_parse_csv("hello,how,are,you", ',');
I end up with a segmentation fault:
Program received signal SIGSEGV, Segmentation fault.
__strcat_sse2 () at ../sysdeps/x86_64/multiarch/../strcat.S:166
166 ../sysdeps/x86_64/multiarch/../strcat.S: No such file or directory.
(gdb) backtrace
#0 __strcat_sse2 () at ../sysdeps/x86_64/multiarch/../strcat.S:166
#1 0x000000000040072c in filldoc_parse_csv (toparse=0x400824 "hello,how,are,you", sepchar=44 ',') at filldocparse.c:20
#2 0x0000000000400674 in main () at parsetest.c:6
The problem is centered around allocating enough space for the buffer string. If I have to, I will make buffer a static array, however, I would like to use dynamic memory allocation for this purpose. How can I do it correctly?
Various problems
strcat(buffer, (const char*)toparse[i]); attempts to changes a char to a string.
strings = realloc(strings, sizeof(buffer)+1); reallocates the same amount of space. sizeof(buffer) is the size of the pointer buffer, not the size of memory it points to.
The calling function has no way to know how many entries in strings. Suggest andding a NULL sentinel.
Minor: better to use size_t rather than int. Use more descriptive names. Do not re-call strlen(toparse) repetitively. Use for(int i=0; toparse[i]; i++) . Make toparse a const char *
You have problems with your memory allocations. When you do e.g. sizeof(buffer) you will get the size of the pointer and not what it points to. That means you will in the first run allocate five bytes (on a 32-bit system), and the next time the function is called you will allocate five bytes again.
There are also many other problems, like you freeing the buffer pointer once you assigned the pointer to strings[j]. The problem with this is that the assignment only copies the pointer and not what it points to, so by freeing buffer you also free strings[j].
Both the above problems will lead to your program having undefined behavior, which is the most common cause of runtime-crashes.
You should also avoid assigning the result of realloc to the pointer you're trying to reallocate, because if realloc fails it will return NULL and you loose the original pointer causing a memory leak.
The following is a piece of code where the user enters unknown amounts of words until 'E' is entered, whereupon the program should stop and print out all of the entered words. However, when run this program produces a segmentation error. Did I access some memory I shouldn't have?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define CAPACITY 10
#define NUM_OF_WORDS 10
int main(void)
{
int num_words = 10;
char *word= malloc(CAPACITY*sizeof(char));
char **w=(char **) malloc(num_words*sizeof(char));
int i;
for(i = 0 ; scanf("%s", word)==1; ++i)
{
if(*word == 'E')
break;
if( i == num_words-1)
w = (char **)realloc(w, (num_words *=2) * sizeof(char));
w[i] =(char *) malloc(strlen(word)+1 * sizeof(char));
strcpy(w[i], word);
}
int x = 0;
for(x = 0 ; x<num_words ; x++)
printf("%s", w[x]);
return 0;
}
Your initial allocation code reads:
char *word = malloc(CAPACITY*sizeof(char));
char **w = (char **) malloc(num_words*sizeof(char));
Both these allocate 10 bytes of memory. Your second one should read:
char **w = (char **) malloc(num_words*sizeof(char *));
or:
char **w = malloc(num_words*sizeof(*w));
These both allocate enough memory for 10 pointers (which might be eight times as much memory as your original code). The second is arguably better style; the first is indubitably the classic style. In C, the cast on malloc() is not necessary; in C++, it is.
This may not be the whole problem; it is almost certainly a contributory factor.
Also, you aren't checking your memory allocations; that is not advisable. You should always check them.
This code:
if (i == num_words-1)
w = (char **)realloc(w, (num_words *=2) * sizeof(char));
is playing with fire on two accounts (plus a repeat of the previously diagnosed problem):
The assignment within the argument list is...not generally reckoned to be a good idea. I wouldn't write code with that in place, and I'd send back code I was asked to review that contained it. It isn't technically wrong; it will work. But it does not make life easier for the maintenance programmers who come after.
You should never reallocate a pointer such as w and assign the new space to the same pointer. If the memory allocation fails, you'll get back a null pointer, so you've lost the only pointer to the previous data, which is still allocated. That's a memory leak. Also, if the memory allocation fails, you have to undo the assignment within the argument list because the allocated space is still at the original size. I think you'd be better off using:
if (i == num_words - 1)
{
size_t new_size = (num_words * 2);
char **new_data = realloc(w, new_size * sizeof(*new_data));
if (new_data == 0)
...handle error; w is still valid, and num_words is still correct too...
num_words = new_size;
w = new_data;
}
Your variable num_words holds the current maximum size of the w array, but that isn't the same as the number of words actually in the array.
When you loop through the w array you are looping through too many items - some elements of the w do not have a valid string in them - trying to print them will cause a segfault.