Segmentation fault in C program using array of char * and malloc - c

Silly little C program, but for the life of me I can't figure out why I keep getting a segmentation fault. I believe I'm allocating enough memory with malloc. Any help would be much appreciated. The code is supposed to read a day of the month and 'reminder' string from the user, and then reads these into data pointed to by the array reminders and allocated memory space with malloc.
/* Prints a one-month reminder list (dynamic string version) */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_REMIND 50 /* maximum number of reminders */
#define MSG_LEN 60 /* maximum length of reminder message */
int read_line(char str[], int n);
int main(void)
{
char *reminders[MAX_REMIND];
char day_str[3], msg_str[MSG_LEN+1];
int day, i, j, num_remind = 0;
for (;;) {
if (num_remind == MAX_REMIND) {
printf("-- no space left --\n");
break;
}
printf("Enter day and reminder: ");
scanf("%2d", &day);
if (day == 0) {
break;
}
sprintf(day_str, "%2d", day);
read_line(msg_str, MSG_LEN);
for (i = 0; i < num_remind; i++) {
if (strcmp(day_str, reminders[i]) < 0) {
break;
}
}
for (j = num_remind; j > i; j--) {
reminders[j] = reminders[j-1];
}
reminders[i] = malloc(2 + strlen(msg_str) + 10);
if (reminders[i] = NULL) {
printf("-- No Space Left --\n");
break;
}
strcpy(reminders[i], day_str);
strcat(reminders[i], msg_str);
num_remind++;
}
printf("\nDay Reminder\n");
for (i = 0; i < num_remind; i++) {
printf(" %s\n", reminders[i]);
}
return 0;
}
int read_line(char str[], int n) {
int ch, i = 0;
while ((ch = getchar()) != '\n') {
if (i < n) {
str[i++] = ch;
}
}
str[i] = '\0';
return i;
}

if (reminders[i] = NULL) {
You set reminders[i] to NULL before you dereference it.

The dreaded assignment/comparison typo! This is a hint that your compiler warning levels are not set high enough or that you are ignoring the warnings.
// Should be '==' not '='
if (reminders[i] = NULL) {
printf("-- No Space Left --\n");
break;
}
Also, your read_line function is similar to fgets, which may simplify things.
Lastly, always validate your user input. Make sure scanf returns the number of items that you've asked for (usually 1 for simple one-item input). Otherwise, you're likely to venture into undefined behaviour.

wrong:
if (reminders[i] = NULL) {
right:
if (reminders[i] == NULL) {
also, you are concatenating day_str & msg_str, so it's better to alloc:
reminders[i] = malloc(2 + strlen(msg_str) + strlen(day_str));

You are doing assignment in if clause. It should be like this:
if (reminders[i] == NULL) {
printf("-- No Space Left --\n");
break;
}

Related

C strcpy segmentation fault when copying from another function [duplicate]

This question already has an answer here:
Segmentation fault when returning pointers [duplicate]
(1 answer)
Closed 3 months ago.
This is a snippet of the code from a project made in the programming class at my college, and my problem is that I get a segmentation fault error when I get to the strcpy part and I have no idea why.
I don't know if it's relevant or not, but I am coding in vs code under linux.
Here's the code:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
typedef struct Teams {
char country[20];
char sponsor[20];
char group;
int points;
} E;
char *sponsor_generator(char *country) {
int i, k = 0;
char sp[20];
for (i = strlen(country) - 1; i >= 0; i--) {
sp[k] = country[i];
k++;
}
sp[k] = '\0';
return sp;
}
void read(E *ec, int *n) {
(*n)++;
printf("Country: ");
scanf("%s", (ec + *n)->country);
(ec + *n)->group = (ec + *n)->country[0];
do {
printf("Number of points: ");
scanf("%d", &(ec + *n)->points);
} while ((ec + *n)->points >= 10);
strcpy((ec + *n)->sponsor, sponsor_generator((ec + *n)->country));
}
int main() {
int n = -1;
E ec[64];
read(ec, &n);
return 0;
}
I tried to look up any solutions, but I didn't find something that would work.
There are multiple problems in your code:
function sponsor_generator returns a pointer to a local array that become invalid as soon as the function returns. sponsor_generator should take the destination array as an argument.
naming the next function read probably clashes with the POSIX system call by the same name. Use a different name.
scanf("%s", (ec + *n)->country); may cause a buffer overflow if the input exceeds 19 characters. Always specify a limit and test the return value:
if (scanf("%19s", (ec + *n)->country) != 1) {
printf("premature end of file\n");
exit(1); // or return an error code to the caller
}
using the array syntax would make the code more readable.
naming the type E is a bad idea: using the structure tag Team would improve readability.
passing the address of the array element and relying on the function return value to increment the number of entries simplifies the code.
Here is a modified version:
#include <stdio.h>
#include <string.h>
typedef struct Team {
char country[20];
char sponsor[20];
char group;
int points;
} Team;
char *sponsor_generator(char *sp, const char *country) {
int i, k;
for (i = strlen(country), k = 0; i-- > 0; k++) {
sp[k] = country[i];
}
sp[k] = '\0';
return sp;
}
/* flush the remainder of the input line:
return EOF at end of file or on read error
return '\n' otherwise
*/
int flush_line(FILE *fp) {
int c;
while ((c = getc(fp)) != EOF && c != '\n')
continue;
return c;
}
int read_team(Team *team) {
int c, points, res;
printf("Country: ");
res = scanf("%19s", team->country);
flush_line(stdin);
if (res != 1) {
return -1;
}
for (;;) {
printf("Number of points: ");
res = scanf("%d", &points);
c = flush_line(stdin);
if (res != 1) {
printf("invalid input\n");
if (c == EOF) {
return -1;
}
} else {
if (points >= 0 && points < 10)
break;
printf("number of points must be between 0 and 9\n");
}
}
team->points = points;
team->group = team->country[0];
sponsor_generator(team->sponsor, team->country);
return 0;
}
void print_team(const Team *team) {
printf("country: %s, sponsor: %s, group: %c, points: %d\n",
team->country, team->sponsor, team->group, team->points);
}
int main() {
Team ec[64];
int n;
for (n = 0; n < 64; n++) {
if (read_team(&ec[n]) < 0) {
printf("premature end of file\n");
break;
}
}
for (int i = 0; i < n; i++) {
print_team(&ec[n]);
}
return 0;
}

free(); and malloc(); keeps crashing (C)

I built this code to practice pointers and the program keeps crashing.it seems it crashes when I enter a big number to counter. 1-5 doesn't affect it apparently, but when you enter 30 it keeps crashing, sometimes on the allocation itself malloc(... and sometime in the free(names[i]); function.
What's the problem here?
#include "stdafx.h"
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <string.h>
int main() {
char **names;
char buffer[100];
int i, bufferLen, counter;
printf("how many names? ");
scanf_s("%d", &counter);
if (counter < 0) {
printf("wrong choice\n");
return 1;
}
names = (char**)malloc(77 * sizeof(char));
if (names == NULL) {
printf("failed...\n");
return 1;
}
for (i = 0; i < counter; i++) {
printf("write the name!! (up to 100 chars): \n");
gets_s(buffer, sizeof(char) * 100);
bufferLen = strlen(buffer) + 1;
names[i] = (char*)malloc(sizeof(char)*bufferLen);
if (names[i] == NULL) {
printf("failed...\n");
return 1;
}
strcpy_s(names[i], sizeof(char)*bufferLen, buffer);
}
for (i = counter-1; i >= 0; i--) { //print names
printf("no. %d, ptr no. %d (size: %d bytes): \n", i+1, (int)(names[i]), sizeof(names[i]));
puts(names[i]);
}
for (i = 0; i < counter; i++) {
if (names[i] != NULL)
free(names[i]);
}
if (names != NULL)
free(names);
return 0;
}
This:
names = (char**)malloc(77 * sizeof(char));
is wrong, sizeof (char) is 1 which is not what you want.
It should be:
names = malloc(77 * sizeof *names);
This is the same as 77 * sizeof (char *) since names is char ** which makes the type of *names be char *.
The cast is not necessary and should be omitted in my opinion.
It's very strange (and an obvious code smell) to use a literal 77 instead of count for the array length, of course.
You probably want names = (char**)malloc(counter * sizeof(char*));.
Also free handles null pointers, no need to check the pointer for null before calling it.

word scramble with pointers in an array. Crashes when run

I am new to arrays with pointers, and I am trying to make an array of pointers word scramble game that allows 3 tries to guess the word before the game ends. Basically, I have created a function that scrambles a string. Then, that string is sent to a new string, which is shown to the user. The user then enters their guess. I am getting no signal from my compiler on what is wrong.. It just crashes when it is run. I believe the error is when I am sending the pointer to the method. Could someone please tell me why this error is happening? Thanks.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <ctype.h>
void scramble(char *strings)
{
int length = strlen(strings), i, randomNum;
char temp;
for(i = 0; i < length/2; i++)
{
randomNum = rand()%length;
temp = strings[i];
strings[i] = strings[length - randomNum];
strings[length - randomNum] = temp;
}
}
int main()
{
int i, tries, NUMWORDS;
char *words[] = { "pumpkin", "cantalope", "watermelon", "apple", "kumquat" };
char *scramWords, *user;
NUMWORDS = strlen(words);
srand(time(NULL));
for(i = 0; i < NUMWORDS; i++)
{
scramWords[i] = words[i];
scramble(scramWords[i]);
}
printf("How to play: You get 3 tries to guess each scrambled word.\n");
for(i = 0; i < NUMWORDS; i++)
{
tries = 0;
while(tries !=4)
{
if(tries == 3)
{
printf("You Lose\n");
return 0;
}
printf("Unscramble: %s\n", scramWords[i]);
gets(user);
if(strcmp(user, words[i]) == 0)
{
printf("Correct!\n");
break;
}
else
{
tries++;
}
}
}
printf("You Win!");
return 0;
}
You must not try to modify string literals, or you will invoke undefined behavior. Copy strings before editing them instead of just assigning pointers.
length - randomNum may be length when randomNum is 0.
strlen(words) won't be the number of elements in words. You can use sizeof(words) / sizeof(*words).
You must allocate some buffer to scramWords and user before writing anything there.
You shouldn't use gets(), which has unavoidable risk of buffer overrun, deprecated in C99 and removed from C11.
Try this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <ctype.h>
void scramble(char *strings)
{
int length = strlen(strings), i, randomNum;
char temp;
for(i = 0; i < length/2; i++)
{
randomNum = rand()%length;
temp = strings[i];
strings[i] = strings[length - randomNum - 1];
strings[length - randomNum - 1] = temp;
}
}
int main(void)
{
int i, tries, NUMWORDS;
char *words[] = { "pumpkin", "cantalope", "watermelon", "apple", "kumquat" };
char **scramWords, user[1024], *lf;
NUMWORDS = sizeof(words) / sizeof(*words);
srand(time(NULL));
scramWords = malloc(sizeof(*scramWords) * NUMWORDS);
if(scramWords == NULL)
{
perror("malloc");
return 1;
}
for(i = 0; i < NUMWORDS; i++)
{
scramWords[i] = malloc(strlen(words[i]) + 1); /* +1 for terminating null-character */
if(scramWords[i] == NULL)
{
perror("malloc");
return 1;
}
strcpy(scramWords[i], words[i]);
scramble(scramWords[i]);
}
printf("How to play: You get 3 tries to guess each scrambled word.\n");
for(i = 0; i < NUMWORDS; i++)
{
tries = 0;
while(tries !=4)
{
if(tries == 3)
{
printf("You Lose\n");
return 0;
}
printf("Unscramble: %s\n", scramWords[i]);
if(fgets(user, sizeof(user), stdin) == NULL)
{
puts("fgets failed");
return 1;
}
if((lf = strchr(user, '\n')) != NULL)
{
*lf = '\0'; /* remove newline character after string read */
}
if(strcmp(user, words[i]) == 0)
{
printf("Correct!\n");
break;
}
else
{
tries++;
}
}
}
printf("You Win!");
return 0;
}
you have a few issues in your code:
1), scramblegets a char * but here
scramWords[i] = words[i];
scramble(scramWords[i]);
you provide it with a char so define your scramWords as a char** instead of char*
2) You don't allocate space when declaring a pointer - that could lead to segfault. Use malloc or before accessing the pointer.
3) When assigning strings from one pointer to another use strcpy, not = operator
4) Use sizeof(words)/sizeof(*words) instead of NUMWORDS = strlen(words);
That should leave you with a working piece of code, but, as said in comments - take care of your warnings!

returning string in C function [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
I was trying to solve CountAndSay problem at one of the online coding site but I am not able to get why my program is printing NULL. I am sure I am doing some conceptual mistake but not getting it.
Here is my code :
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char* countAndSay(int A) {
int i,j,k,f,count;
char a;
char *c = (char*)malloc(sizeof(char)*100);
char *temp = (char*)malloc(sizeof(char)*100);
c[0] = 1;c[1] = '\0';
for(k=2; k<=A; k++)
{
for(i=0, j=0; i<strlen(c); i++)
{
a = c[i];
count = 1;
i++;
while(c[i] != '\0')
{
if(c[i]==a)
{
count++;
i++;
}
else if(c[i] != a)
{
i--;
break;
}
else
{
break;
}
}
temp[j] = count;
temp[j+1] = a;
j += 2;
}
*(temp+j) = '\0';
if(k<A)
{
for(j=0; j<strlen(temp); j++)
{
c[j] = temp[j];
}
c[j] = '\0';
}
}
return temp;
}
int main(void) {
// your code goes here
char *c = countAndSay(8);
printf("%s\n",c);
return 0;
}
The idea is not that bad, the main errors are the mix-up of numerical digits and characters as shown in the comments.
Also: if you use dynamic memory, than use dynamic memory. If you only want to use a fixed small amount you should use the stack instead, e.g.: c[100], but that came up in the comments, too. You also need only one piece of memory. Here is a working example based on your code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// ALL CHECKS OMMITTED!
char *countAndSay(int A)
{
int k, count, j;
// "i" gets compared against the output of
// strlen() which is of type size_t
size_t i;
char a;
// Seed needs two bytes of memory
char *c = malloc(2);
// Another pointer, pointing to the same memory later.
// Set to NULL to avoid an extra malloc()
char *temp = NULL;
// a temporary pointer needed for realloc()-ing
char *cp;
// fill c with seed
c[0] = '1';
c[1] = '\0';
if (A == 1) {
return c;
}
// assuming 1-based input, that is: the first
// entry of the sequence is numbered 1 (one)
for (k = 2; k <= A; k++) {
// Memory needed is twice the size of
// the former entry at most.
// (Averages to Conway's constant but that
// number is not usable here, it is only a limit)
cp = realloc(temp, strlen(c) * 2 + 1);
temp = cp;
for (i = 0, j = 0; i < strlen(c); i++) {
//printf("A i = %zu, j = %zu\n",i,j);
a = c[i];
count = 1;
i++;
while (c[i] != '\0') {
if (c[i] == a) {
count++;
i++;
} else {
i--;
break;
}
}
temp[j++] = count + '0';
temp[j++] = a;
//printf("B i = %zu, j = %zu\n",i,j-1)
//printf("B i = %zu, j = %zu\n",i,j);
}
temp[j] = '\0';
if (k < A) {
// Just point "c" to the new sequence in "temp".
// Why does this work and temp doesn't overwrite c later?
// Or does it *not* always work and fails at one point?
// A mystery! Try to find it out! Some hints in the code.
c = temp;
temp = NULL;
}
// intermediate results:
//printf("%s\n\n",c);
}
return temp;
}
int main(int argc, char **argv)
{
// your code goes here
char *c = countAndSay(atoi(argv[1]));
printf("%s\n", c);
free(c);
return 0;
}
To get a way to check for sequences not in the list over at OEIS, I rummaged around in my attic and found this little "gem":
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <limits.h>
char *conway(char *s)
{
char *seq;
char c;
size_t len, count, i = 0;
len = strlen(s);
/*
* Worst case is twice as large as the input, e.g.:
* 1 -> 11
* 21 -> 1211
*/
seq = malloc(len * 2 + 1);
if (seq == NULL) {
return NULL;
}
while (len) {
// counter for occurrences of ...
count = 0;
// ... this character
c = s[0];
// as long as the string "s"
while (*s != '\0' && *s == c) {
// move pointer to next character
s++;
// increment counter
count++;
// decrement the length of the string
len--;
}
// to keep it simple, fail if c > 9
// but that cannot happen with a seed of 1
// which is used here.
// For other seeds it might be necessary to
// use a map with the higher digits as characters.
// If it is not possible to fit it into a
// character, the approach with a C-string is
// obviously not reasonable anymore.
if (count > 9) {
free(seq);
return NULL;
}
// append counter as a character
seq[i++] = (char) (count + '0');
// append character "c" from above
seq[i++] = c;
}
// return a proper C-string
seq[i] = '\0';
return seq;
}
int main(int argc, char **argv)
{
long i, n;
char *seq0, *seq1;
if (argc != 2) {
fprintf(stderr, "Usage: %s n>0\n", argv[0]);
exit(EXIT_FAILURE);
}
// reset errno, just in case
errno = 0;
// get amount from commandline
n = strtol(argv[1], NULL, 0);
if ((errno == ERANGE && (n == LONG_MAX || n == LONG_MIN))
|| (errno != 0 && n == 0)) {
fprintf(stderr, "strtol failed: %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
if (n <= 0) {
fprintf(stderr, "Usage: %s n>0\n", argv[0]);
exit(EXIT_FAILURE);
}
// allocate space for seed value "1" plus '\0'
// If the seed is changed the limit in the conway() function
// above might need a change.
seq0 = malloc(2);
if (seq0 == NULL) {
fprintf(stderr, "malloc() failed to allocate a measly 2 bytes!?\n");
exit(EXIT_FAILURE);
}
// put the initial value into the freshly allocated memory
strcpy(seq0, "1");
// print it, nicely formatted
/*
* putc('1', stdout);
* if (n == 1) {
* putc('\n', stdout);
* free(seq0);
* exit(EXIT_SUCCESS);
* } else {
* printf(", ");
* }
*/
if (n == 1) {
puts("1");
free(seq0);
exit(EXIT_SUCCESS);
}
// adjust count
n--;
for (i = 0; i < n; i++) {
// compute conway sequence as a recursion
seq1 = conway(seq0);
if (seq1 == NULL) {
fprintf(stderr, "conway() failed, probably because malloc() failed\n");
exit(EXIT_FAILURE);
}
// make room
free(seq0);
seq0 = NULL;
// print sequence, comma separated
// printf("%s%s", seq1, (i < n - 1) ? "," : "\n");
// or print sequence and length of sequence, line separated
// printf("%zu: %s%s", strlen(seq1), seq1, (i < n-1) ? "\n\n" : "\n");
// print the endresult only
if (i == n - 1) {
printf("%s\n", seq1);
}
// reuse seq0
seq0 = seq1;
// not necessary but deemed good style by some
// although frowned upon by others
seq1 = NULL;
}
// free the last memory
free(seq0);
exit(EXIT_SUCCESS);
}

segmentation fault after a new line

I'm running in to a segmentation fault on the line enclosed with **.
I pipe this output:
|status: OK|
|version: 0.85|
|author: PBrooks|
|nitems: 0|
in to my code below and it gives me a segmentation fault after I print out the '\n' in my printf statement. I don't know how to debug this though.. Does anyone have a clue?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
char string[300];
struct NameValue {
char *name;
char *value;
};
struct NameValue *pairs;
void ReadStdin(int argc, char *argv) {
int x;
fread(string, sizeof (char), 300, stdin);
printf("%s\n", string);
}
void ParseInput() {
int x, num = 0; //figure out how many i need
for (x = 0; x < 300; x++) {
if (string[x] == '|') {
num++;
}
}
num /= 2; //num = how many i need
pairs = (malloc(num)); //allocate the array
int pipe = 0, i, j = 0, tempCounter = 0;
char tempName[50], tempValue[50];
printf("%lu \n", sizeof (string) / sizeof (string[0]));
if (pairs != 0) {
for (i = 0; i <= num; i++) { //counts pairs
printf("i = %i\n", i);
printf("j = %i, pipe: %i \n", j, pipe);
if (string[j] == '|') {
printf("there's a pipe\n");
pipe++;
j++;
}
while (string[j] != ':') {
printf("counter for main string: %i\n tempCounter: %i\n", j, tempCounter);
tempName[tempCounter] = string[j];
tempCounter++;
j++;
if (string[j] == ':') {
tempName[tempCounter] = '\0';
tempCounter = 0;
**printf("~~~~tempName\n is: %s", tempName);**
break;
}
}
while (string[j] != '|') {
j++;
tempValue[tempCounter] = string[j];
tempCounter++;
if (string[j] == '|') {
tempValue[tempCounter] = '\0';
tempCounter = 0;
strcpy(pairs[i].value, tempValue);
pipe++;
break;
}
}
}
}
}
int main(int argc, char *argv) {
ReadStdin(argc, argv);
ParseInput();
return (EXIT_SUCCESS);
}
edit: Sorry! I removed the null terminate character line by accident. It is in there but it's still giving me the error.
edit: a bit more information: The j variable gets incremented up to 6 and and the temp counter gets incremented up to 5 before the program spits out a segmentation fault.
You never null terminate the string tempName. Then you try printing it here:
if (string[j] == ':') {
tempCounter = 0;
**printf("~~~~tempName\n is: %s", tempName);**
break;
}
Strings in C are a series of characters in memory, terminated by a null byte (i.e. '\0'). You're copying bytes into a buffer, but you never yourself create this null terminator, hence printf runs off the end and into undefined memory.
Instead, at the end of the while loop, you need to assign the next character in tempName to '\0', probably inside the while loop just before printing it.
Before tempCounter = 0, just put tempName[tempCounter] = '\0';.
I figured it out. Not only did I need to malloc the pairs but I also need to malloc the member variables inside each malloc's pairs.
I ended up using my tempCounter to see how many characters I needed and malloc'd the correct amount for the member variables.

Resources