receive a segmentation error when printing out words of array - c

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.

Related

Segmentation fault for malloc function of a 2D char array

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.

a c program which returns a pointer to array of 2 strings

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;
}

reading an input(int) and storing it into an array with malloc and realloc

I'm trying to read ints from stdin, but i don't know the length. I tried this but I have no idea why it doesn't work
#include <stdio.h>
#include <stdlib.h>
int main()
{
int *arr = (int *) malloc(sizeof(int));
int sizeCounter = 0;
int tmp = 0;
while(scanf("%d", &tmp) != EOF)
{
arr = (int *) realloc(arr, sizeof(arr)+sizeof(int));
arr[sizeCounter] = tmp;
sizeCounter++;
}
}
Error - realloc(): invalid pointer: 0xb76d8000 *
This line is wrong.
arr = (int *) realloc(arr, sizeof(arr)+sizeof(int));
sizeof(arr)+sizeof(int) is a constant. It is equal to sizeof(int*)+sizeof(int).
What you need is:
arr = (int *) realloc(arr, (sizeCounter+1)*sizeof(int));
R Sahu gave the correct answer on why this is not working.
However, seeing your code I cannot help but cringe at the inefficiency of reallocating the memory block on each read. If you want to use a memory block/dynamic array to store the read-in integers, allocate a reasonable amount of memory (this depends on how much input you expect in a typical case and is entirely application specific) to start. Then reallocate the block when it is full. Memory allocation is a very expensive operation and reallocating the block on each read is incredibly wasteful and therefore should never be done.

malloc() to concatenate 2 strings into third string - crash after compilation

So I'm working through "Sams Teach Yourself C Programming in One Hour a Day, Seventh Edition" Lesson 10 Exercise 7 which asks to "Write a function that accepts two strings. Use the malloc() function to allocate enough memory to hold the two strings after they have been concatenated (linked). Return a pointer to this new string."
I am sure there are much more elegant ways to go about this than what I have attempted below. I am mostly interested in why my solution doesn't work. I have only been learning C for a few months and have no significant programming background. Please let me know why this crashes on compilation. I am using Code Blocks on Win 7 with GNU GCC Compiler if that makes a difference. Thank you :)
#include <stdio.h>
#include <stdlib.h>
char * concatenated(char array1[], char array2[]);
int ctrtotal;
int main(void)
{
char *comboString;
char *array1 = "You\'re the man ";
char *array2 = "Now Dog!";
comboString = (char *)malloc(ctrtotal * sizeof(char));
concatenated(array1, array2);
if (comboString == NULL)
{
puts("Memory error");
exit(1);
}
puts(comboString);
free(comboString);
return 0;
}
char * concatenated(char array1[], char array2[])
{
char *array3;
int ctr;
int ctr2;
for (ctr = 0; array1[ctr] != '\0'; ctr++)
array3[ctr] = array1[ctr];
ctr2 = ctr;
for (ctr = 0; array2[ctr] != '\0'; ctr++)
{
array3[ctr2 + ctr] = array2[ctr];
}
array3[ctr2 + ctr + 1] = '\0';
ctrtotal = (ctr2 + ctr + 2);
return array3;
}
Thank you for the help. After reviewing everyone's feedback on my errors I revised the code to the following:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char * concatenated(char array1[], char array2[]);
int main(void)
{
char *array1 = "Testing Testing One Two ";
char *array2 = "Three. Finally, not crashing the mem o ry.";
char *comboString = malloc( (strlen(array1)+strlen(array2) + 1)*sizeof(char));
comboString = concatenated(array1, array2);
if (comboString == NULL)
{
puts("Memory error");
exit(1);
}
puts(comboString);
free(comboString);
return 0;
}
char * concatenated(char array1[], char array2[])
{
char *array3;
array3 = malloc( (strlen(array1)+strlen(array2) + 1)*sizeof(char) );
strcat(array3, array1);
strcat(array3, array2);
return array3;
}
If anyone sees any redundancies/unnecessary remaining code the could/should be deleted, please let me know. I recognize the benefit of being as concise as possible.
Your code has a bunch of issues:
int ctrtotal is never initialized, so you are mallocing 0 bytes
concatenated() is copying characters to an uninitialized array3. This pointer should point to a mallocd buffer.
If concatenated is allocating the memory, then main doesn't need to. Instead it should use the result of concatenated.
I don't want to give you the full code, and let you to miss out on this learning opportunity. So concatenated should look like this, in psuedo-code:
count = length_of(string1) + length_of(string2) + 1
buffer = malloc(count)
copy string1 to buffer
copy string2 to buffer, after string1
set the last byte of buffer to '\0' (NUL)
return buffer
In C, strings are represented as a NUL-terminated array of characters. That's why we allocate one additional byte, and terminate it with \0.
As a side-note, when dealing with strings, it is far easier to work with pointers, instead of treating them as arrays and accessing them via indices.
There's a lot of code here that just doesn't make any sense. I suggest that you first write this program on paper. Then, "execute" the program in your head, stepping through every line. If you get to something you don't understand, then you need to either fix your understanding, or your incorrect code. Don't try to write code that looks like some other bit of code.
There's also a library function called strcat which will make this task even easier. See if you can figure out how to use it here.
Spoiler --> #include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *concatenate2(const char* s1, const char* s2);
int main(void)
{
char *comboString;
char *array1 = "You're the man ";
char *array2 = "Now Dog!";
comboString = concatenate2(array1, array2);
if (comboString == NULL)
{
puts("Memory error");
exit(1);
}
puts(comboString);
free(comboString);
return 0;
}
char *concatenate2(const char* s1, const char* s2)
{
char *result;
result = malloc(strlen(s1) + strlen(s2) + 1);
*result = '\0';
strcat(result, s1);
strcat(result, s2);
return result;
}
You forgot to allocate memory for third, concatenated, array of chars (in function)
You should do something like this:
char *array3;
array3 = (char *)malloc( (strlen(array1)+strlen(array2) + 1)*sizeof(char) ); // +1 for '\0' character.
and then write chars from first and second array into third.
Perhaps a stroll through the question code is best.
#include <stdio.h>
#include <stdlib.h>
char * concatenated(char array1[], char array2[]);
int ctrtotal;
Notice that the above line declares ctrtotal to be an integer, but does not specify the value of the integer.
int main(void)
{
char *comboString;
char *array1 = "You\'re the man ";
char *array2 = "Now Dog!";
comboString = (char *)malloc(ctrtotal * sizeof(char));
Notice that the above line allocates memory and sets 'comboString' to point at that memory. However, how much memory is being allocated?
(ctrtotal[???] * sizeof(char)[1])
What is the value of (??? * 1) ? This is a problem.
concatenated(array1, array2);
The intent of the line above is that array1["You\'re the man "] and array2["Now Dog!"] will be joined to form a new string["You\'re the man Now Dog!"], which will be placed in allocated memory and returned to the caller.
Unfortunately, the returned memory containing the string is not captured here. For example, perhaps the above line should be:
comboString = concatenated(array1, array2);
While this make sense, for this line, it begs a question of the purpose of the lines:
comboString = (char *)malloc(ctrtotal * sizeof(char));
as well as the global variable:
int ctrtotal;
and the later reference:
ctrtotal = (ctr2 + ctr + 2);
Perhaps all of these 3 lines should be deleted?
if (comboString == NULL)
{
puts("Memory error");
exit(1);
}
puts(comboString);
free(comboString);
return 0;
}
char * concatenated(char array1[], char array2[])
{
char *array3;
Notice that '*array3' is now a defined pointer, but it is not pointing anywhere specific.
int ctr;
int ctr2;
The purpose of 'concatenated()' is to join array1 and array1 into allocated array3. Unfortunately, no memory is allocated to array3.
Below, the memory where array3 is pointing will be modified. Since array3 is not pointing anywhere specific, this is not safe.
Prior to modifying memory where array 3 is pointing, it is important to point array3 at memory where it is safe to modify bytes. I suggest that the following code be inserted here:
array3 = malloc(strlen(array1) + strlen(array2) + 1);
Now, array3 points to allocated memory, large enough to hold both strings plus the string termination character '\0'.
for (ctr = 0; array1[ctr] != '\0'; ctr++)
array3[ctr] = array1[ctr];
ctr2 = ctr;
for (ctr = 0; array2[ctr] != '\0'; ctr++)
{
array3[ctr2 + ctr] = array2[ctr];
}
array3[ctr2 + ctr + 1] = '\0';
ctrtotal = (ctr2 + ctr + 2);
return array3;
}
I am responding to your revised code. There are a few bugs in it.
...
char *array2 = "Three. Finally, not crashing the mem o ry.";
char *comboString = malloc( (strlen(array1)+strlen(array2) + 1)*sizeof(char));
comboString = concatenated(array1, array2);
...
The malloc is unnecessary here and actually a bug in your code. You are allocating a block of memory, but you then replace the value of the pointer comboString with the pointer from the call to concatenated. You lose the pointer to the block of memory allocated in main and thus never are able to free it. Although this will not be a problem in the code you have right now since main returns soon after, it could cause a memory leak in an application that ran for a longer time.
strcat(array3, array1);
This is also a bug. strcat is going to walk through array3 to find '\0' and then once it is found copy in array1 from that index on, replacing the '\0'. This works fine here since the memory block that was allocated for array3 is going to be zeroed out** as no block has yet been freed by your program. However, in a longer running program you can end up with a block that does not start with a '\0'. You might end up corrupting your heap, getting a segfault, etc.
To fix this, you should use strcpy instead, array3[0] = '\0', or *array3 = '\0'
** When the operating system starts your program it will initialize the memory segment it reserves for it with zeroes (this actually isn't a necessity but will be true on almost any operating system). As your program allocates and frees memory, you will eventually wind up with values that are not zero. Note that the same bug can occur with uninitialized local variables such as:
int i;
for (; i < 10; i++);
This loop will run 10 times whenever the space on the runtime stack where i is stored is already 0.
Overall, the takeaway is to be very careful with arrays and dynamic memory allocation in C. C offers you none of the protections that modern languages do. You are responsible for making sure you stay within the bounds of your array, initialize your variables, and properly allocate and free your memory. Neglecting these things will lead to obscure bugs that will take you hours to find, and most of the times these bugs will not appear right away.

Seg fault on my own version of getline

I'm trying to make a simple version of getline. It should read a line in from stdin, reallocating the size of the buffer as necessary. It should also return the number of characters read. It takes a char ** so that the reallocated buffer can be later freed. Why am I getting a segfault?
Heres my version:
int get_input_line(char **buff, int start_size) {
char c;
int stop = 0, length = 0, k = start_size;
while(!stop) {
if(length > k) {
k += 50;
buff = (char *)(realloc(buff, start_size + 1));
}
c = getchar();
if(c == '\n'){
stop = 1;
}
buff[length] = c;
length++;
}
return length;
}
And here's the call:
char *buff = (char *)(malloc(50 + 1));
get_input_line(&buff, 50);
printf("%s", buff);
You probably meant:
*buff = (realloc(*buff, new_size));
^ ^
And
(*buff)[length] = c;
You're also missing the 0 terminator.
EDIT
As nos points out, length > k should be length >= k .
You're not detecting EOF reliably. You need to save the result of getchar() in an int and not a char. And you should not try to store EOF in your buffer.
You're not checking your memory allocations.
You're not null terminating the output string, so the printf() in main() may crash.
You're confusing someone (maybe me, maybe the compiler, maybe yourself) by allocating 51 bytes and telling the function that it only has 50 bytes to play with.
And, most particularly, you need to be using *buff at most points inside the function, including, in particular, when adding a character:
(*buff)[length++] = c;
You really should be paying more attention to all those compiler warnings. If your compiler isn't giving you any, get a better compiler (or turn on the warning flags - but you should be being shrieked at by the compiler in its default mode).
Also, you are miscalling realloc() on three grounds. One is the *buff issue. The second is that you want the size to be k, not start_size + 1. The other is that you are assigning the result to the input parameter. This is a 'no-no' because if the allocation fails, you've lost your pointer to the previously (and still) allocated data. Always use the idiom:
void *new_data = realloc(old_data, new_size);
if (new_data == 0)
...deal with out of memory error...
else
{
old_data = new_data;
old_size = new_size;
}
Applied to your code, that means:
char *new_buff = (char *)realloc(*buff, k); // NOT start_size+1!!!
if (new_buff == 0)
...deal with out of memory error...
else
*buff = new_buff;
There are those who argue against the cast on malloc() and realloc() and calloc(); there are those who prefer the casts present. There are arguments on both sides, of differing degrees of validity. I prefer the cast - I respect those who prefer no cast. We reach our different conclusions for different reasons.
I have not studied the code for other 'off-by-one' errors. I suspect that there may be several of those, too.
The line
buff = (char *)(realloc(buff, start_size + 1));
should be
*buff = (char *)(realloc(*buff, k + 1));
Also
buf[length] = c
should be
*buf[length] = c
Moreover, I think you forgot to store a final '\0'.

Resources