I think I've got everything fixed now. I made the mistake of incrementing the environ variable instead of treating it like an array and iterating across it. The following is what I have now and it should be good to go.
extern char **environ;
int main(int argc, char *argv[]) {
// determine number of environment variables
int n = 0;
char *c = NULL;
while ((c = environ[n++]) != NULL) {
printf("%s\n", c);
}
printf("%s\n%d\n\n", c, n);
// allocate array to store character pointers to environment array
char **new_c;
printf("This prints\n");
if ((new_c = malloc(n * sizeof(*c))) == NULL) {
printf("Error\n");
exit(EXIT_FAILURE);
}
printf("This prints now too\n");
free(c);
// sort array of character pointers
// parse each environment variable and output
exit(0);
}
To start, I've read through a couple dozen malloc & segmentation fault questions on here and none seem to be the same as mine. That being said, if this is a duplicate question would you mine pointing me to the solution?
Hi all, I'm having a problem using malloc. I compiled and ran my program once and malloc worked. I then began filling in more code to solve the problem and since that first run I have received a Segmentation Fault. Below is my code in it's last working state (still giving a seg fault error though):
extern char **environ;
int main(int argc, char *argv[]) {
// determine number of environment variables
int n = 0;
char *c = *environ;
while ((c = *environ++) != NULL) {
n++;
printf("%s\n", c);
}
printf("%s\n%d\n\n", c, n);
// allocate array to store character pointers to environment array
printf("This prints\n");
if ((c = malloc((size_t) n)) == NULL) {
perror("Unable to allocate memory\n");
}
printf("This does not print\n");
free(c);
// sort array of character pointers
// parse each environment variable and output
exit(0);
}
The program is supposed to allocate memory for a char array that will then be used to sort, parse, and print the name-value or value-name pairs depending on what the FORMAT value is set to. The first loop works and iterates through the environ variable and prints out each name-value pair. The two printf statements I included state what I see in the terminal. Does anyone have any ideas what I'm doing wrong?
Also, I have tried using the following malloc lines:
char *new_c = malloc((size_t) n);
char *new_c = malloc(n);
char *new_c = malloc(1);
char *new_c = malloc(sizeof(n));
int *ptr = malloc((size_t) n);
There are probably a few others I tried but I'm still baffled. There are so few lines of code that I'm not sure how I could be messing anything up this early on. Also, for giggles here's what I get when I use free in the terminal (showing I have memory available):
total used free shared buff/cache available
Mem: 3036836 1404340 902852 104712 729644 1491248
Swap: 0 0 0
I've also tried calling malloc outside of the if statement as such:
c = malloc((size_t) n);
if (c == NULL) {
perror("Unable to allocate memory\n");
}
Here you are modifying the global environ:
while ((c = *environ++) != NULL) {
After the while loop, environ points to uninitialized memory.
malloc() looks for some environment variables which can modify its behaviour and is now dereferencing a pointer to uninitialized memory.
Use this:
int i = 0;
while ((c = environ[i++]) != NULL) {
This should fix the segmentation fault.
Two things with this:
if ((c = malloc((size_t) n)) == NULL) {
perror("Unable to allocate memory\n");
}
You are allocating n bytes, here. It sounds like you want to allocate space for n pointers to char, so you should replace with:
malloc(n * sizeof(char *))
If this is indeed what you're trying to do, then c should be char **, not char *, and better still would be:
c = malloc(n * sizeof *c)
Incidentally, you appear to be using c for two completely different things. It's generally better not to do this with variables - since it makes your program harder to understand - and instead to use one variable to loop through to print your environment variables, and a different one to store your dynamically allocated array.
Also, you call perror() if malloc() fails, but then you just continue right on with your program as if there was no error. You should actually respond to a failure of this nature, if nothing else by calling exit(EXIT_FAILURE) after reporting it.
Related
First of all Thanks for visiting my question... :)
I am interested in competitive programming, so I daily do some amount of problem-solving, however, I only know C language at a decent level, and I often face problems while dynamically allocating something as usual, especially for strings and 2D arrays.
But I somehow manage to find ways (thanks to StackOverflow), for example, I wanted to create a function that scans string dynamically until the user enters space or new line, so I came up with the solution below and it works perfectly:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
// scanf("%[^\n]%*c", str);
char *create_string(char *ptr)
{
ptr = (char *)malloc(0 * sizeof(char));
unsigned int size = 0;
char c = 0;
while (1)
{
scanf("%c", &c);
if (c == 32 || c == 10)
{
break;
}
size++;
ptr = (char *)realloc(ptr, size * sizeof(char));
ptr[size - 1] = c;
}
ptr = (char *)realloc(ptr, (size + 1) * sizeof(char));
ptr[size] = '\0';
return ptr;
}
int main()
{
char *str;
str = create_string(str);
printf("%s", str);
printf("\n%lu", strlen(str));
return 0;
}
And now for curiosity purposes, I want to know how can I do this same thing using the void function?, something like:
char *str;
create_string(&str);
should start storing everything in the dynamic memory which is pointed by str.
Also, please if you have more knowledge to show in DMA for 2D array, then please show me it, feel free to give examples with different problems.
And also How can I stop scanning the string (which was allocated dynamically) with specific string ending? for example, scanning(any kind of scanning, i.e. int, bool, custom structures etc...) should stop if user enters string "STOP", Please feel free to give pictorial examples.
Because I am sure that this question is burning like a fire in beginner's and intermediate C programmers' minds.
As C passes arguments by value, to return something via an out parameter, you need to pass in a pointer to it. So to return a char * it would:
void create_string(char **s) {
*s = malloc(42);
}
Here is your refactored code. I changed the following:
Eliminate return value of update caller.
Initialize *ptr = malloc(1) for the trailing '\0'. It eliminates an unnecessary and implementation defined malloc(0). This also eliminates the (*ptr)[size] = ... which looks wrong as the last index is expected to be size - 1. Alternatively initialize it to NULL.
Use character constants instead of magic values (32, 10).
sizeof(char) is defined as 1 so leave it out.
Reduced scope of variable c.
free() memory allocated.
(cosmetic) Use size_t size instead of unsigned int size.
(cosmetic) Avoid the noise of casting casting void *.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void create_string(char **ptr) {
*ptr = malloc(1);
size_t size = 1;
for(;;) {
char c;
scanf("%c", &c);
if (c == ' ' || c == '\n') break;
(*ptr)[size-1] = c;
size++;
*ptr = realloc(*ptr, size);
}
(*ptr)[size-1] = '\0';
}
int main() {
char *str;
create_string(&str);
printf("%s\n", str);
printf("%zu\n", strlen(str));
free(str);
}
I didn't fix these issue:
Check return value of malloc(), realloc().
v = realloc(v, ...) is unsafe and will leak memory if realloc() fails. You need to do char *tmp = realloc(v,...); if(!tmp) { // err }; v = tmp;.
Check return value of scanf() otherwise you may be operating on uninitialized data.
Use scanf("%s", ..) instead of for(;;) { scanf("%c", ...). It's more efficient to allocate a chunk at a time instead of per byte.
If user enters ctrl-d (EOF) the program will go into an infinite loop.
It's good idea to separate i/o from logic (i.e. let caller do the scanf(). That way create_string() is much more reusable.
This question already has answers here:
How to qsort an array of pointers to char in C?
(9 answers)
C library function to perform sort
(9 answers)
Dynamically create an array of strings with malloc
(4 answers)
Closed 5 years ago.
So I'm trying to make a program that takes in certain number of strings from stdin and then output into a text file.
The code I have so far is:
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
int cmpstr(const void * a, const void *b){
const char* aa = (const char*) a;
const char* bb = (const char*) b;
return strcmp (aa, bb);
}
int main(int argc, char *argv[]){
int i =0;
int scount;
char ** data = NULL;
FILE * ofile;
if (argc != 3){
printf("%s \n", "The format to use this is: mySort <#of strings> <output filename>",argv[0]);
exit(EXIT_FAILURE);
}
scount = atoi(argv[1]);
if(!scount){
printf("%s \n", "Invalid number.");
exit(EXIT_FAILURE);
}
data = (char **) malloc(scount * sizeof(char*));
if(NULL == data){
printf("Memory allocation failed\n");
exit(EXIT_FAILURE);
}
for(i = 0; i< scount; i++){
if(NULL == fgets(data[i], (int) sizeof(data), stdin)){
printf("Could not get line\n");
exit(EXIT_FAILURE);
}
}
qsort(data, scount, sizeof(char*), cmpstr);
ofile = fopen(argv[2], "w+");
if(ofile == NULL){
printf("Could not open output file. \n");
}
for(i = 0; i<scount; i++){
fputs(data[i], ofile);
}
fclose(ofile);
for(i=0; i<scount; i++){
if(data[i]) free(data[i]);
}
if (data) free(data);
exit (EXIT_SUCCESS);
return 0;
}
However, when I compiled it it gave me a segmentation fault. I tried using the gdb debugger to try and debug it but it did not give me anything really and I barely understand how to use gdb. But my takeaway from the usage of gdb is that there is not enough memory allocated which confuses me since I allocated memory using malloc.
data = (char **) malloc(scount * sizeof(char*));
Here you allocate memory for an array of pointers. You never initialize the contents of that array. Therefore, when you access data[0] below by passing it to fgets, you're accessing an uninitialized pointer object. If you're lucky, the contents of that uninitialized memory constitutes an invalid address, and when fgets attempts to store data there, your program crashes. If you're unlucky, the contents of that uninitialized memory happens to be the address of some block of memory that's used by some other object and you get memory corruption that's really hard to debug.
You need to initialize the pointers allocated by malloc. Like any other pointer object, depending on what you want to do, you can initialize them to NULL, to a pointer to an existing object, or to the result of calling a function such as malloc. In this program, you need to obtain storage for the lines that you're going to read, therefore you'll need to call malloc on each of the lines. Since you don't know in advance how long a line will be, this is best done at the time you read the line.
It would be a good idea to first set all the elements to NULL, as soon as you've allocated the array of pointers, and later allocate memory for the individual lines. You don't have to, but it's easier then to keep track of which elements of the array have been initialized and which ones haven't. In particular, that lets you call free on all the array elements without having to worry how many you've already reached.
fgets(data[i], (int) sizeof(data), stdin)
Passing sizeof(data) here doesn't make sense. The variable data is a pointer to char*, so sizeof(data) is just the size of a pointer. It isn't the size of the array that the pointer points to: that size isn't known at compile time, it's the argument you pass to malloc. And even that size is not relevant here: the size is the maximum number of lines you can read (multiplied by the size of a pointer to a line's contents), but what fgets needs is the size of the memory that's allocated for the line.
To keep things simple, let's say you have a maximum line length max_line_length.
data = (char **) malloc(scount * sizeof(char*));
if (data == NULL) ... // omitted error checking
for (i = 0; i < scount; i++)
data[i] = NULL;
for (i = 0; i < scount; i++) {
data[i] = malloc(max_line_length+2); // +2 for line break character and null byte to terminate the string
if (data[i] == NULL) ... // omitted error checking
if(NULL == fgets(data[i], max_line_length, stdin)) ... // omitted error checking
...
}
After this you'll run into another issue as described in the comments, in that cmpstr receives pointers to pointers to line contents, not pointers to line contents. This is explained in How to qsort an array of pointers to char in C?
I created a function designed to get user input. It requires that memory be allocated to the variable holding the user input; however, that variable is returned at the end of the function. What is the proper method to free the allocated memory/return the value of the variable?
Here is the code:
char *input = malloc(MAX_SIZE*sizeof(char*));
int i = 0;
char c;
while((c = getchar()) != '\n' && c != EOF) {
input[i++] = c;
}
return input;
Should I return the address of input and free it after it is used?
Curious as to the most proper method to free the input variable.
It's quite simple, as long as you pass to free() the same pointer returned by malloc() it's fine.
For example
char *readInput(size_t size)
{
char *input;
int chr;
input = malloc(size + 1);
if (input == NULL)
return NULL;
while ((i < size) && ((chr = getchar()) != '\n') && (chr != EOF))
input[i++] = chr;
input[size] = '\0'; /* nul terminate the array, so it can be a string */
return input;
}
int main(void)
{
char *input;
input = readInput(100);
if (input == NULL)
return -1;
printf("input: %s\n", input);
/* now you can free it */
free(input);
return 0;
}
What you should never do is something like
free(input + n);
because input + n is not the pointer return by malloc().
But your code, has other issues you should take care of
You are allocating space for MAX_SIZE chars so you should multiply by sizeof(char) which is 1, instead of sizeof(char *) which would allocate MAX_SIZE pointers, and also you could make MAX_SIZE a function parameter instead, because if you are allocating a fixed buffer, you could define an array in main() with size MAX_SIZE like char input[MAX_SIZE], and pass it to readInput() as a parameter, thus avoiding malloc() and free().
You are allocating that much space but you don't prevent overflow in your while loop, you should verify that i < MAX_SIZE.
You could write a function with return type char*, return input, and ask the user to call free once their done with the data.
You could also ask the user to pass in a properly sized buffer themselves, together with a buffer size limit, and return how many characters were written to the buffer.
This is a classic c case. A function mallocs memory for its result, the caller must free the returned value. You are now walking onto the thin ice of c memory leaks. 2 reasons
First ; there is no way for you to communicate the free requirement in an enforceable way (ie the compiler or runtime can't help you - contrast with specifying what the argument types are ). You just have to document it somewhere and hope that the caller has read your docs
Second: even if the caller knows to free the result he might make a mistake, some error path gets taken that doesnt free the memory. This doesnt cause an immediate error, things seem to work, but after running for 3 weeks your app crashes after running out of memory
This is why so many 'modern' languages focus on this topic, c++ smart pointers, Java, C#, etc garbage collection,...
Expanding array dynamicly after user enter string in function dynamic_array My Problem seems to be when i try to use the extended array agian in main after i dynamic_array returns true.
After function call i try to print input with printf("main string: %s\n", input) the program will crash. It seems like the *input in main never gets extended.
int dynamic_array(char *input, int *string_current_len){
int string_len = 0;
char temp_c;
input = (char *) malloc(sizeof(char));
if(input == NULL) {
printf("Could not allocate memory!");
exit(1);
}
printf("File to search in: ");
while((temp_c = getchar()) != '\n') {
realloc(input, (sizeof(char)));
input[string_len++] = temp_c;
}
input[string_len] = '\0';
printf("\nYou entered the string: %s\n", input);
printf("length of string is %d.\n", string_len);
*string_current_len = string_len;
return 1;
}
int main(void) {
int string_len = 0;
char *input;
printf("enter #q as filename or word to quit.\n");
if(!dynamic_array(input, &string_len)){
return 0;
}
printf("main string: %s\n", input);
return 0;
}
This:
realloc(input, (sizeof(char)));
is wrong. The realloc() function doesn't modify the given pointer (it can't!), it returns the new pointer. It can also fail, and return NULL.
Also, the second argument doesn't make any sense at all, it should be the new desired total size of the previously allocated buffer, but you're always passing (a very obscure) 1. It's not "grow this by this amount", it's the rather more low-level "attempt to grow this to this new size, and return the new location of the grown buffer".
Please read the documentation very carefully.
realloc(input, (sizeof(char)));
You are reallocating with same size (i.e 1 byte). It shoud be:
while((temp_c = getchar()) != '\n') {
realloc(input, (string_len + 1) * (sizeof(char)));
input[string_len++] = temp_c;
if(!dynamic_array(input, &string_len)){
return 0;
}
"input" variable is used without initialization.
realloc(input, (sizeof(char)));
Above "realloc" is returning bad pointer. It may be totally bogus, or it may have been allocated from another heap. The pointer MUST come from the 'local' heap.
C has a call-by-value semantics. So any changes to formal input inside dynamic_array is not propagated to the caller (e.g. your main).
Your main does not initialize input. If you compiled with all warnings and debug info (as you should), e.g. with gcc -Wall -g, you'll get a warning about that.
I actually recommend to initialize every local variable. This makes the debugging easier (since runs are more reproductible). Useless initializations will be removed by the optimizer.
You could initialize input inside your main with
char* input = NULL;
and you should redesign your program, perhaps by having a grow_array function (instead of your dynamic_array) which you would call in your main like
grow_array (&input, &string_len);
I leave up to you to declare and implement grow_array correctly. I'm too lame to do your homework.
Inside your grow_array you want to call malloc and test it:
*pptr = malloc(newsize);
if (!*pptr) { perror ("malloc"); exit (EXIT_FAILURE); };
Don't forget to use the debugger (gdb) to run your program step by step.
I don't recommend using realloc because error handling could be tricky. I would suggest using malloc and free and cleverly copying the data using mempcy.
Read the documentation of every function that you are using, e.g. malloc(3), printf(3)
couple of things that I noticed.
int dynamic_array(char *input, int *string_current_len) should change to
int dynamic_array(char **input, int *string_current_len)
since this function is trying to modify a pointer.
also the call to the function here
if(!dynamic_array(input, &string_len)){
return 0;
}
needs to be:
if(!dynamic_array(&input, &string_len)){
return 0;
}
Not sure why I'm getting a segmentation fault here:
//I define the variables used for input
int *numberOfDonuts;
numberOfDonuts = (int *)malloc(sizeof(int));
char *charInput;
charInput = (char *)malloc(sizeof(char));
int *numberOfMilkshakes;
numberOfMilkshakes = (int *)malloc(sizeof(int));
//Then attempt to read input
scanf("%c %d %d", &*charInput, &*numberOfDonuts, &*numberOfMilkshakes);
Then I get a segmentation fault on this line. Can't work out what I'm doing wrong?
You're overcomplicating things with the way you're allocating your variables.
This should do what you want:
int numberOfDonuts;
char charInput;
int numberOfMilkshakes;
scanf("%c %d %d", &charInput, &numberOfDonuts, &numberOfMilkshakes);
With basic types like int and char you don't have to explicitly allocate memory for them. The compiler handles that for you.
Even allocating them the way you did, though, what you end up with is a pointer to the value rather than the value itself. Given that scanf wants a bunch of pointers there's no need to dereference the pointer and then get it's address again, which is what you're trying to do. The following will work as well:
int *numberOfDonuts;
numberOfDonuts = malloc(sizeof(int));
char *charInput;
charInput = malloc(sizeof(char));
int *numberOfMilkshakes;
numberOfMilkshakes = malloc(sizeof(int));
scanf("%c %d %d", charInput, numberOfDonuts, numberOfMilkshakes);
As far as I can tell, this code is valid.
It compiles on my system and works as expected.
Is this your whole program?
You should also note that all those pointers are not required.
You could just write it like this:
int numberOfDonuts;
char charInput;
int numberOfMilkshakes;
//Then attempt to read input
scanf("%c %d %d", &charInput, &numberOfDonuts, &numberOfMilkshakes);
printf("char=%c donuts=%d milkshakes=%d\n",
charInput, numberOfDonuts, numberOfMilkshakes);
Segmentation faults occur when the program tries to access invalid memory locations.
Since you use malloc in your program to allocate memory, it is always best to check whether a valid memory location is returned before attempting to store a value in that location. Include this check every time malloc is used in your program to resolve the error.
For eg:
int *numberOfDonuts = (int *)malloc(sizeof(int));
if(numberOfDonuts == NULL)
{
printf("Memory allocation Failure\n");
return;
}