I am getting segmentation fault in C and I have no idea what is the reason. As far as I know segmentation fault occurs when system run our of memory. I checked my loops and they seem to have clear termination conditions. Thus, I am confused what causes my code to crash. As I checked this fault should occurs in mygetline or readlines functions.
Is there any debugger that I can use to find our why program crashes?
#include <stdio.h>
#include <string.h>
#define MAXLINE 100
#define MAXLINENUM 10
int readlines(char *lines[]);
int mygetline(char line[]); /* getline: read a line into s, returns length */
void writelines(char *lines[], int nlines);
int main()
{
int i = 0;
char *lines[MAXLINE];
i = readlines(lines);
writelines(lines, i);
return 0;
}
int mygetline(char line[]){
int i, c;
for(i = 0; i < MAXLINE-1 && (c = getchar()) != '\n' && c != EOF; i++){
line[i] = c;
}
line[i] = '\0';
return i;
}
int readlines(char *lines[]){
int i, c;
i = 0;
while((c = mygetline(lines++)) > 0 && i < MAXLINENUM){ //line[i]
i++;
}
lines[--i] = '\0';
return i;
}
void writelines(char *lineptr[], int nlines) {
int i;
for (i = 0; i < nlines; i++)
printf("%s\n", lineptr[i]);
}
The reason for the segmentation fault is that you don't allocate any storage for the strings. You declare an array of char* here:
char *lines[MAXLINE];
But nowhere do you ever allocate memory to hold the actual strings.
To continue using an array of char*, allocated that way, you'd need to use malloc to allocate memory for the actual strings.
lines[i] = malloc(...);
Obviously you'll need to:
Decide how much memory to allocate for each string.
Call free to dispose of the memory when you are done with it.
Add some code to check that you don't write beyond the end of any of your buffers.
You created an array char *lines[MAXLINE] which is an array of pointers. However, you've not initialized those pointers, so they're pointing to garbage. You then pass the garbage pointer into mygetline which writes to the garbage pointer, and this is the problem.
Not only do you need to allocate memory for the line to be stores in, but you also need to get mygetline how many characters it can read. If you allocate space for 10 characters, but the user enters 20 you're going to have a similar problem.
The reason that you get a segfault is that your code reads the data into lines without allocating any memory for the characters that you read.
Your main allocates memory for the pointers to strings, but it does not initialize these pointers. You need to add code to set these pointers to valid blocks of memory, for example, by allocating some max number of characters with malloc:
while(i < MAXLINENUM) {
lines[i] = malloc(MAXLINE);
if (!mygetline(lines[i++])) {
break;
}
}
Also note that you confused MAXLINE with MAXLINENUM in the declaration of lines.
The reason for the segmentation fault is the memory allocation.
You can not allocate memory like char *lines[MAXLINE];.
Try the following code
If you are Using 1D array
char *lines;
lines=(char *)malloc(MAXLINE*sizeof(char));
If you are using 2D array go with this code
char **lines;
lines=(char **)malloc(MAXLINENUM*sizeof(char *));
for(i=0;i<MAXLINENUM;i++)
lines[i]=(char *)malloc(MAXLINE*sizeof(char));
Related
How can I implement a function that will concatenate something to a char* (not char array)?
Example of what I want:
#include <stdio.h>
#include <string.h>
int main() {
char* current_line;
char temp[1];
sprintf(temp, "%c", 'A');
// This causes a seg fault. I of course don't want that, so how do I get this to work properly?
strcat(current_line, temp);
return 0;
}
How can I fix this to work properly (and please, tell me if I need to add anything to my question or point me in the right direction because I couldn't find anything)?
Edit: I made this but it seg faults
char* charpointercat(char* mystr, char* toconcat) {
char ret[strlen(mystr) + 1];
for(int i = 0; mystr[i] != '\0'; i++) {
ret[i] = mystr[i];
}
return ret;
}
You have 3 problems:
You do not allocate memory for current_line at all!
You do not allocate enough memory for temp.
You return a pointer to a local variable from charpointercat.
The first one should be obvious, and was explained in comments:
char *current_line only holds a pointer to some bytes, but you need to allocate actual bytes if you want to store something with a function like stracat.
For the secoond one, note that sprintf(temp, "%c", 'A'); needs at least char temp[2] as it will use one byte for the "A", and one byte for terminating null character.
Since sprintf does not know how big temp is, it writes beyond it and that is how you get the segfault.
As for your charpointercat once the function exits, ret no longer exists.
To be more precise:
An array in C is represented by a pointer (a memory address) of its first item (cell).
So, the line return ret; does not return a copy of all the bytes in ret but only a pointer to the first byte.
But that memory address is only valid inside charpointercat function.
Once you try to use it outside, it is "undefined behavior", so anything can happen, including segfault.
There are two ways to fix this:
Learn how to use malloc and allocate memory on the heap.
Pass in a third array to the function so it can store the result there (same way you do with sprintf).
From the first code you posted it seems like you want to concatenate a char to the end of a string... This code will return a new string that consists of the first one followed by the second, it wont change the parameter.
char* charpointercat(char* mystr, char toconcat) {
char *ret = (char*) malloc(sizeof(char)*(strlen(mystr) + 2));
int i;
for(i = 0; mystr[i] != '\0'; i++) {
ret[i] = mystr[i];
}
ret[i] = toconcat;
ret[i + 1] = '\0';
return ret;
}
This should work:
char* charpointercat(char* mystr, char* toconcat) {
size_t l1,l2;
//Get lengths of strings
l1=strlen(mystr);
l2=strlen(toconcat);
//Allocate enough memory for both
char * ret=malloc(l1+l2+1);
strcpy(ret,mystr);
strcat(ret,toconcat);
//Add null terminator
ret[l1+l2]='\0';
return ret;
}
int main(){
char * p=charpointercat("Hello","World");
printf("%s",p);
//Free the memory
free(p);
}
I am new to C and still trying to figure out pointer.
So here is a task I am stuck in: I would like to assign 10 fruit names to a pointer of array and print them out one by one. Below is my code;
#include <stdio.h>
#include <string.h>
int main(){
char *arr_of_ptrs[10];
char buffer[20];
int i;
for (i=0;i<10;i++){
printf("Please type in a fruit name:");
fgets(buffer,20,stdin);
arr_of_ptrs[i]= *buffer;
}
int j;
for (j=0;j<10;j++){
printf("%s",*(arr_of_ptrs+j));
}
}
However after execution this, it only shows me the last result for all 10 responses. I tried to consult similar questions others asked but no luck.
My understanding is that
1) pointer of array has been allocated memory with [10] so malloc() is not needed.
2) buffer stores the pointer to each individual answer therefore I dereference it and assign it to the arr_of_ptrs[i]
I am unsure if arr_of_ptrs[i] gets me a pointer or a value. I thought it is definitely a pointer but I deference it with * the code and assign it to *buffer, program would get stuck.
If someone could point out my problem that would be great.
Thanks in advance
Three erros, 1. You must allocate memory for elements of elements of arr_of_ptrs, now you only allocate the memory for elements of arr_of_ptrs on stack memory. 2. arr_of_ptrs[i]= *buffer; means all of the arr_of_ptrs elements are pointed to same memory address, which is the "buffer" pointer. So all the elements of arr_of_ptrs will be same to the last stdin input string. 3. subsequent fgets() call has potential problem, one of the explaination could be here
A quick fix could be,
#include <stdio.h>
#include <string.h>
int main(){
const int ARR_SIZE = 10, BUFFER_SIZE = 20;
char arr_of_ptrs[ARR_SIZE][BUFFER_SIZE];
char *pos;
int i, c;
for (i = 0; i < ARR_SIZE; ++i) {
printf ("Please type in a fruit name: ");
if (fgets (arr_of_ptrs[i], BUFFER_SIZE, stdin) == NULL) return -1;
if ((pos = strchr(arr_of_ptrs[i], '\n')))
*pos = 0;
else
while ((c = getchar()) != '\n' && c != EOF) {}
}
for (i = 0; i < ARR_SIZE; ++i)
printf("%s\n", arr_of_ptrs[i]);
return 0;
}
The misunderstanding is probably that "Dereferencing" an array of characters, unlike dereferencing a pointer to a primitive data type, does not create a copy of that array. Arrays cannot be copied using assignment operator =; There a separate functions for copying arrays (especially for 0-terminated arrays of char aka c-strings, and for allocating memory needed for the copy):
Compare a pointer to a primitive data type like int:
int x = 10;
int *ptr_x = &x;
int copy_of_x = *ptr_x; // dereferences a pointer to x, yielding the integer value 10
However:
char x[20] = "some text"; // array of characters, not a single character!
char *ptr_x = &x[0]; // pointer to the first element of x
char copy_of_first_char_of_x = *ptr_x; // copies the 's', not the entire string
Use:
char x[20] = "some text";
char *ptr_x = &x[0];
char *copy_of_x = malloc(strlen(ptr_x)+1); // allocate memory large enough to store the copy
strcpy(copy_of_x,ptr_x); // copy the string.
printf("%s",copy_of_x);
Output:
some text
I come from the Java world and have developed a penchant towards C lately. I was going through the chapter on pointers in K&R and there's an example wherein the authors input N lines in an array of pointers and then sorts it. Here's my readLines(..) method:
void readlines(char *lines[]) {
/*read 5 lines*/
for(int i = 0; i < 5; i++) {
char line[MAXLENGTH];
printf("%p\n",line);
readNewLine(line,MAXLENGTH);
/*make the ith pointer in the array point to this line*/
*(lines + i) = line;
}
}
What I have tried to do here is input 5 lines into lines. For each line (i), I get some space, print its address (for debugging) and then read a line into that space. Then I make the ith pointer point to the start of that memory location. When I run the program, I see the same virtual memory address. Shouldn't a new memory space be allocated with each loop on the heap with line pointing to it? Why do I see the same address then?
Also, K&R's solution is much more complicated and elegant. My version seems just too simple. What is it that I am missing here?
Edit:
Here's the caller:
int main(int argc, char *argv[]) {
char *lines[5];
readlines(lines);
//print all the input lines
for(int i = 0; i < 5; i++) {
char *line = lines[i];
while(*line) {
printf("%c",*line);
line++;
}
}
return 0;
}
This prints the last line that I entered. Now as mentioned in the comments, the buffer in the callee is allocated on the stack, which should be destroyed once the function returns. Where is the last line getting stored then?
in this code you have a lots of issues. You use the same buffer, and this buffer is local so it will not exist if you leave the scope.
You need to allocate a line buffer for every single line you're going to read.
void readlines(char *lines[]) {
/*read 5 lines*/
for(int i = 0; i < 5; i++) {
char *line = malloc(MAXLENGTH);
printf("%p\n",(void *)line);
readNewLine(line,MAXLENGTH);
/*make the ith pointer in the array point to this line*/
*(lines + i) = line;
}
}
I'm writing a small program that reads multiple input lines from the user:
#include <stdio.h>
#include <stdlib.h>
#define MAXINPUT 256
#define MAXLINES 32
/* Reads at most maxLines inputs from stdin. Returns number of lines. */
int readlines(char** buffer, int maxLines, size_t maxInput);
/* Gets input from stdin with maxInput as the limit. Returns size of string. Terminates at newline. */
int getstdline(char* buffer, int maxInput);
int main(int argc, char** argv) {
char** buffer = malloc((sizeof buffer[0]) * MAXLINES);
int numlines = readlines(buffer, MAXLINES, MAXINPUT);
/* free memory that was allocated for each str */
for(int i = 0; i < numlines; ++i) {
free(*(buffer++));
}
/* free memory that was allocated to hold all the strings */
free(buffer);
}
int readlines(char** buffer, int maxLines, size_t maxInput) {
int linecount = 0;
while(maxLines--) {
char* tmp = malloc(maxInput);
/* if empty string, exit loop */
if(getstdline(tmp, maxInput) <= 0) {
free(tmp);
break;
}
*buffer = tmp;
++linecount;
++buffer;
}
return linecount;
}
My question is regarding the call to malloc() in readlines(char**,int,size_t). I obviously can't free() the memory within the function so to free it at the end of the program, I tried to loop through the array of char* and free them individually. I then also free char** buffer in main() because it was also allocated using malloc().
Looping through each of them gives me the error :
object was probably modified after being freed.
Freeing char** buffer at the end works fine.
So it seems there is a concept of dynamic memory I am not quite understanding. Why is this happening and what would be the correct way to handle memory in this specific program?
The problem is that you are modifying the buffer pointer by running buffer++ so when you call free(buffer) you are passing in the wrong pointer. You can rewrite your loop to not modify that pointer.
Hallo the following code read the stdin and put it into stdout, but in reverse. I used for this a static array, because I know how much characters are in the input.txt. My question is how can I change my array in a dynamic array(pointer) with using malloc and realloc? All my tries failed.
#include <stdio.h>
#include <stdlib.h>
int main()
{
char ch;
int i,counter;
char array[50];
counter = 0;
i = 0;
while((ch=getchar()) != EOF)
{
array[i] = ch;
i++;
counter++;
}
for(i = (counter + 1); i >= 0; i--)
{
printf("%c",array[i]);
}
printf("\n");
return 0;
}
Even if you know that the input you use never has more than 50 characters, you should enforce that limit. When the program is run with arbitrary input, you will eventually access data beyond the array's end.
Anyway, here's your program core, extracted into a function:
void rev1()
{
char array[50]; // Allocate 50 bytes on the stack
int i = 0;
char ch;
while (i < 50 && (ch = getchar()) != EOF) array[i++] = ch;
while (i--) putchar(array[i]);
printf("\n");
// Do nothing - array goes out of scope
}
If you just want to use the same fixed-length buffer on the heap, the code is very similar. You should define a pointer to char instead of the array and then call malloc in order to obtain the required memory. After you are done using that memory, you must release it with free.
Here's a second version that uses memory on the heap:
void rev2()
{
char *array;
int i = 0;
char ch;
array = malloc(50 * sizeof(*array)); // Allocate on the heap
if (array == NULL) exit(1); // Check for failure
while (i < 50 && (ch = getchar()) != EOF) array[i++] = ch;
while (i--) putchar(array[i]);
printf("\n");
free(array); // Explicitly release data after use
}
Things to note:
sizeof(*array) is sizeof(char) in this case, which is always 1 and therefore often is omitted. But p = malloc(count * sizeof(*p)) is a very useful allocation pattern for allocating an array of count elements that will still work if you change the type of the things pointed to.
Memory allocation on the heap may fail; malloc will then return NULL. You must cater for such cases. The simple strategy is to just print an error message and abort the program. Depending on what you need the memory for, you might chose other failure strategies.
Note how the core of the function, the loop is exactly the same as in the first version.
You also must enforce the limit of 50 chars. The array is on the heap, but it doesn't grow.
Free the memory after use. If you don't you "leak memory", i.e. you keep chunks of memory blocked. Here, array - the pointer variable that holds the array, not the array itself - is a local variable that goes out of scope. Forgetting to free the memory here will mean that you lose its address and can't access it again.
The variable array points to the start of the memory. This variable must be passed to free. Don't change this variable, e.g. by incrementing it, otherwise you will lose your "key" to the memory.
A slightly more involved version re-allocates memory as needed. You can use realloc instead of malloc if your array grows. The already allocated data stays in place, even if the memory is not the same:
void rev3()
{
char *array = NULL; // Initially unallocated NULL array
size_t size = 0; // Allocated size, initially 0
int i = 0;
char ch;
while ((ch = getchar()) != EOF) {
if (i >= size) { // Check current bounds
size += 50; // Increase memory
array = realloc(array, // Reallocate
size * sizeof(*array));
if (array == NULL) exit(1);
}
array[i++] = ch;
}
while (i--) putchar(array[i]);
printf("\n");
free(array); // Explicitly release data after use
}
Notes:
realloc(NULL, size) behaves like malloc(size). Therefore you can implement a reallocation scheme easily by starting with a NULL pointer.
Although the kernel keeps track of the allocated size internally, you have no means to know it, so you must keep track of this information yourself, in this case with size.
Again, you must ensure the the allocation was successful. I've used quick-and-dirty (and silent) program termination above, but you can chose other strategies.
In this case, the core loop is somewhat more involved. Before appending to the memory, you must check whether you should increase it. After you have populated your memory, access (within the allocated bounds) is as usual.
The obvious solution:
#include <stdlib.h>
#include <stdio.h>
void readandprint(void)
{
int c = getchar();
if (c == EOF)
return;
readandprint();
printf("%c", c);
return;
}
int main()
{
readandprint();
printf("\n");
return 0;
}
#include <stdio.h>
#include <stdlib.h>
int main(void){
int ch;//It must be int for comparison with the EOF.
int i, counter;
char *array = malloc(50);
int size = 50;
counter = 0;
while((ch=getchar()) != EOF){
array[counter++] = ch;
if(counter == size){
char *temp = realloc(array, size += 50);
if(temp==NULL){
free(array);
fprintf(stderr, "realloc error!\n");
return -1;
}
array = temp;
}
}
while(counter){
printf("%c", array[--counter]);
}
free(array);
return 0;
}