Segmentation fault storing input in an array - c

I have written a C program that takes multiple inputs in the following format: rounds -> rows -> col -> array initial values
I have no issue with the following input: 2 2 2 0 0 0 0
but once put into the other format which looks like this
2
2 2
0 0
0 0
I get a segmentation fault, which I'm not sure why. I feel like I have newlines accounted for. Here is a snippet of my code where I think the error is happening:
int counter = 1;
char *num;
char *str;
long nums;
char line[BUFFER];
fgets (line, BUFFER, stdin);
num = strtok(line, " "); //getting first input that is separated by a space
int rounds = atoi(num); //changes input into a number
num = strtok(NULL, " ");
int row = atoi(num);
num = strtok(NULL, " ");
int col = atoi(num);
int grid[row][col];
for (int i = 0; i < row && !stop; i++){
for (int j = 0; j < col && !stop; j++){
num = strtok(NULL, " \n");
if (num == NULL){ //if the next character after whitespace is null/eof
printf("Invalid input 1");
stop = true;
}else{
nums = strtol(num, &str, 10);
if (*str != '\0' && *str != '\n'){
printf("Invalid input\n");
return 1;
}
int curr = nums;
grid[i][j] = curr;
}
}
}
EDIT: I realize the problem here now, but how would I distinguish if the input is put in the format of a single line vs if the input were on multiple lines so I could use fgets?

If one doesn't care about whitespace, one could completely decouple the input from the parsing. In this modified code, number takes a Buffer, and calls next_int; if this fails, (it will the first time because the buffer is empty,) the line buffer is refilled by calling next_line until it gets at least one number. In this way, it's kind of a singleton producer-consumer pattern.
#include <stdlib.h> /* EXIT malloc free strtol */
#include <stdio.h> /* printf fgets perror */
#include <assert.h> /* assert */
#include <errno.h> /* errno */
#include <string.h> /* strlen */
#include <limits.h> /* INT LONG */
#include <ctype.h> /* isspace */
/** Returns true if `line` was filled up, at most to `size` from `stdin`, thus
this limits the input we can get from `stdin` on top of `fgets`, (embedded
NULs don't work.) If false, `errno` will be set. */
static int next_line(char *line, const size_t size) {
assert(line && size > 2);
if(!fgets(line, size, stdin)) {
if(!ferror(stdin)) fprintf(stderr, "Not enough numbers.\n");
if(!errno) errno = EDOM; /* This is an error in this application. */
return 0;
}
if(line[0] == '\0' || line[strlen(line) - 1] != '\n')
return errno = ERANGE, 0; /* Line too long. */
return 1;
}
/** If EOF, line contained no non-whitespace characters, otherwise, if true,
`*input_ptr` is a whitespace and then number in the range of
`[MIN_INT, MAX_INT]`; it gets moved ahead that amount and `*output_ptr`
contains the number. If false, `errno` will be set. */
static int next_int(char **const input_ptr, int *const output_ptr) {
long l;
assert(input_ptr && output_ptr);
/* We could skip this, but then `errno` would possibly be set. */
while(isspace(**input_ptr)) (*input_ptr)++;
if(**input_ptr == '\0') return EOF;
/* Perform the conversion to `int` using a `long`. */
errno = 0;
l = strtol(*input_ptr, input_ptr, 0);
if((l == 0 || l == LONG_MAX || l == LONG_MIN) && errno) return 0;
if(l > INT_MAX || l < INT_MIN) return errno = ERANGE, 0;
*output_ptr = (int)l;
return 1;
}
/* `sizeof str` is the maximum line. */
struct Buffer { char str[256], *line; };
/** A true return means that we filled the buffer `in` as needed to get an
input `int` which is stored in `no`. Otherwise, `errno`. */
static int number(struct Buffer *const in, int *const no) {
int success;
assert(in && in->line >= in->str && in->line <= in->str + sizeof in->str);
while((success = next_int(&in->line, no)) == EOF) {
if(!next_line(in->str, sizeof in->str)) return 0;
in->line = in->str;
}
return success;
}
int main(void) {
int success = EXIT_FAILURE;
int row, col, *array = 0, i, j;
size_t n = 0, n_max;
struct Buffer in = { "", 0 };
in.line = in.str; /* Complete the `struct Buffer` contract. */
if(!number(&in, &row) || !number(&in, &col)) goto catch;
if(row <= 0 || col <= 0
|| (size_t)row > (size_t)-1 / col
|| (size_t)row * col > (size_t)-1 / sizeof *array)
{ errno = ERANGE; goto catch; } /* Overflow data types. */
n_max = row * col;
if(!(array = malloc(sizeof *array * n_max))) goto catch;
for(n = 0; n < n_max; n++) if(!number(&in, array + n)) goto catch;
for(j = 0; j < col; j++) {
for(i = 0; i < row; i++) {
printf("%s%4d", i ? ", " : "", array[j * row + i]);
}
fputc('\n', stdout);
}
success = EXIT_SUCCESS;
goto finally;
catch:
perror("array");
finally:
free(array);
return success;
}
Also changed,
strtol is used instead of atoi, which is equivalent, but it updates the pointer, has more error reporting, and can handle octal and hex.
C99 varible-length arrays are going to cause stack overflow if one makes them too big. In C17, they are optional. The code above uses malloc instead.

Related

An Array of Arrays

I want to store a group of arrays containing 2 numbers in an array. But I only want 2 numbers to be stored when 5 followed by a comma and another number is entered. Essentially, what I want my program to do is read from this array of arrays and perform tasks accordingly. So if the user enters 2, I want to store (2,0) in one space of my array and move on to ask my user for the second number. But if the user types 5,10 I want the program to store (5,10) in that same array. Then my program could filter which array has only one value and which has 2 and do different tasks accordingly. My assignment requires us to not ask 2 numbers for each array which would have made it easier.
This is what I have so far and I know I'm wrong I just don't know where to go from here:
int main(void)
{
int size = 0;
int input;
int factor;
int mdArrays[100][2];
for (size_t i = 0; i < 100; i++)
{
size = i;
scanf("%d,%d", &input, &factor);
if (input != 5 && input != 9)
{
factor = 0;
for (size_t j =0 ; j< 2; j++)
{
mdArrays[i] = input;
mdArrays[j] = factor;
}
}
else if (input == 9)
{
break;
}
else
{
for(int j = 0; j< 2; j++)
{
mdArrays[i] = input;
mdArrays[j] = factor;
}
}
}
for (size_t i =0; i < size; i++)
{
for(size_t j = 0; j < 2; j++)
{
printf("%d,%d", mdArrays[i[j]]);
}
}
}
There were a few issues.
size is one too short (it should be i + 1).
It may be possible to handle 5 vs 5,23 using scanf. But, I prefer to use fgets and strtol and check the delimiter (e.g. whether it's , or not).
The if/else ladder logic can be simplified if we make the first test against input == 9 to stop the loop.
According to your code, you want to force a factor of zero if input != 5. That doesn't make much sense to me, but I've kept that logic [for now].
That may not be what you want/need, but it was my best interpretation of your code. The main purpose is to differentiate how many numbers are on a given line. So, adjust the rest as needed.
I think the way you're storing/displaying the array is incorrect. I believe you want to store input into mdArrays[i][0] and factor into mdArrays[i][1]. Using j makes no sense to me.
As I mentioned [in my top comments], the printf in the final loop is invalid.
Note that the code is cleaner if we don't hardwire the dimensions with a literal 100 in multiple places (e.g. once in the myArrays declaration and again in the outer for loop). Better to use (e.g.) #define MAXCOUNT 100 and replace 100 elsewhere with MAXCOUNT (see below).
I created three versions. One that is annotated with original and fixed code. Another that removes the original code. And, a third that organizes the data using a struct.
Here's the refactored code. I've bracketed your/old code [vs. my/new code] with:
#if 0
// old code
#else
// new code
#endif
I added a debug printf. Anyway, here's the code with some annotations:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int
main(void)
{
int size = 0;
int input;
int factor;
int mdArrays[100][2];
for (size_t i = 0; i < 100; i++) {
#if 0
size = i;
scanf("%d,%d",&input,&factor);
#else
// get line
char buf[100];
char *cp = fgets(buf,sizeof(buf),stdin);
if (cp == NULL)
break;
// strip newline -- only needed for debug print
cp = strchr(buf,'\n');
if (cp != NULL)
*cp = 0;
// decode first number
input = strtol(buf,&cp,10);
// decode second number if it exists -- otherwise, use a sentinel
if (*cp == ',')
factor = strtol(cp + 1,&cp,10);
else
factor = -1;
printf("DEBUG: buf='%s' input=%d factor=%d\n",buf,input,factor);
#endif
// stop input if we see the end marker
if (input == 9)
break;
// remember number of array elements
size = i + 1;
// only use a non-zero factor if input is _not_ 5
if (input != 5) {
factor = 0;
#if 0
for (size_t j = 0; j < 2; j++) {
mdArrays[i] = input;
mdArrays[j] = factor;
}
continue;
#endif
}
#if 0
for (int j = 0; j < 2; j++) {
mdArrays[i] = input;
mdArrays[j] = factor;
}
#else
mdArrays[i][0] = input;
mdArrays[i][1] = factor;
#endif
}
for (size_t i = 0; i < size; i++) {
#if 0
for (size_t j = 0; j < 2; j++) {
printf("%d,%d",mdArrays[i[j]]);
}
#else
printf("%d,%d\n",mdArrays[i][0],mdArrays[i][1]);
#endif
}
return 0;
}
Here's the sample input I used to test:
5,3
7,6
8,9
5,37
5
9,23
Here's the program output:
DEBUG: buf='5,3' input=5 factor=3
DEBUG: buf='7,6' input=7 factor=6
DEBUG: buf='8,9' input=8 factor=9
DEBUG: buf='5,37' input=5 factor=37
DEBUG: buf='5' input=5 factor=-1
DEBUG: buf='9,23' input=9 factor=23
5,3
7,0
8,0
5,37
5,-1
Here's a slightly cleaned up version:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXCOUNT 100
int
main(void)
{
int size = 0;
int input;
int factor;
int mdArrays[MAXCOUNT][2];
for (size_t i = 0; i < MAXCOUNT; i++) {
// get line
char buf[100];
char *cp = fgets(buf,sizeof(buf),stdin);
if (cp == NULL)
break;
// strip newline -- only needed for debug print
#ifdef DEBUG
cp = strchr(buf,'\n');
if (cp != NULL)
*cp = 0;
#endif
// decode first number
input = strtol(buf,&cp,10);
// decode second number if it exists -- otherwise, use a sentinel
if (*cp == ',')
factor = strtol(cp + 1,&cp,10);
else
factor = -1;
#ifdef DEBUG
printf("DEBUG: buf='%s' input=%d factor=%d\n",buf,input,factor);
#endif
// stop input if we see the end marker
if (input == 9)
break;
// remember number of array elements
size = i + 1;
// only use a non-zero factor if input is _not_ 5
if (input != 5)
factor = 0;
mdArrays[i][0] = input;
mdArrays[i][1] = factor;
}
for (size_t i = 0; i < size; i++)
printf("%d,%d\n",mdArrays[i][0],mdArrays[i][1]);
return 0;
}
You might benefit from using a struct [YMMV], so here's a version that keeps things organized that way:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXCOUNT 100
typedef struct {
int input;
int factor;
} data_t;
int
main(void)
{
int size = 0;
data_t mdArrays[MAXCOUNT];
data_t *data;
for (size_t i = 0; i < MAXCOUNT; i++) {
// get line
char buf[100];
char *cp = fgets(buf,sizeof(buf),stdin);
if (cp == NULL)
break;
// strip newline -- only needed for debug print
#ifdef DEBUG
cp = strchr(buf,'\n');
if (cp != NULL)
*cp = 0;
#endif
data = &mdArrays[i];
// decode first number
data->input = strtol(buf,&cp,10);
// decode second number if it exists -- otherwise, use a sentinel
if (*cp == ',')
data->factor = strtol(cp + 1,&cp,10);
else
data->factor = -1;
#ifdef DEBUG
printf("DEBUG: buf='%s' input=%d factor=%d\n",buf,input,factor);
#endif
// stop input if we see the end marker
if (data->input == 9)
break;
// remember number of array elements
size = i + 1;
// only use a non-zero factor if input is _not_ 5
if (data->input != 5)
data->factor = 0;
}
for (size_t i = 0; i < size; i++) {
data = &mdArrays[i];
printf("%d,%d\n",data->input,data->factor);
}
return 0;
}
Read a line of user input with fgets() and then parse it to see if it is one number, two comma separated numbers or something else.
I recommend using `"%n" to detect when and how scanning finished.
int get_numbers(int *input, int *factor) {
char buf[80];
if (fgets(buf, sizeof buf, stdin)) {
int n = 0;
sscanf(buf, "%d %n", input, &n);
if (n > 0 && buf[n] == '\0') return 1;
n = 0;
sscanf(buf, "%d ,%d %n", input, factor, &n);
if (n > 0 && buf[n] == '\0') return 2;
return 0; // Invalid input
}
return EOF; // No input
}
Usage
// scanf("%d,%d", &input, &factor);
switch (get_numbers(&input, &factor)) {
case 2: printf("%d %d\n", input, factor); break;
case 1: printf("%d\n", input); break;
case 0: printf("Invalid input\n"); break;
case EOF: printf("No input\n"); break;
}

How do I remove the "incompatible pointer type" warning from my code?

This code reads an input text file, and creates an output file based on its contents.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define OUT 0
#define IN 1
#define MAX 28
#define BLOCK 4000
/* Check whether the character is alphanumeric */
int isAlphanumeric(char c) {
return ('a' <= c && c <= 'z') ||
('A' <= c && c <= 'Z') ||
('0' <= c && c <= '9');
}
int main(int argc, char *argv[]) {
int c, state = OUT, length = 0, i, j, counter[MAX];
char word[30], longest_word[30];
FILE *input, *output; /* FILE pointers to open the file */
/* Initialize the counter */
for (i = state; i < MAX; i++)
counter[i] = 0;
/* Open the file */
input = fopen("complete_shakespeare.txt", "r");
output = fopen("word_length_histogram.txt", "w");
/* Keep reading the character in the file */
while ((c = getc(input)) != EOF) {
/* If the character is alphanumeric, record it */
if (isAlphanumeric(c)) {
strncat(word, &c, 1);
}
/* If the character is not alphanumeric, increment the corresponding counter, and additionally, record longest word. */
else {
length = strlen(word);
if (length == 27) strcpy(longest_word, word);
counter[length] += 1;
memset(word, 0, sizeof(word));
}
}
/* If the file ends with a word, record its length */
if (isAlphanumeric(word[0])){
length = strlen(word);
counter[length] += 1;
}
/* print the longest word to the file */
fprintf(output, "%s\n\n", longest_word);
/* Make the histogram */
for (i = 1; i < MAX; i++) {
int dividend = counter[i] / 4000 + 1;
fprintf(output, "%2d %6d ", i, counter[i]);
for (j = dividend; j >= 1; j--){
if (counter[i] != 0)
fprintf(output, "*");
}
fprintf(output, "\n");
}
/* Don't forget to close the FILEs */
fclose(input);
fclose(output);
return 0;
}
It produces the correct output file, but this error comes up whenever I compile it.
B:\CodeBlocks\Projects\Programming in C\hw_4\Homework_4\main.c|44|warning: passing argument 2 of 'strncat' from incompatible pointer type [-Wincompatible-pointer-types]|
The warning seems to come from the only line with strncat. Does anyone know how this can be remedied?
The variable c is declared as having the type int.
int c, state = OUT, length = 0, i, j, counter[MAX];
^^^^^^
So the expression &c used in this call
strncat(word, &c, 1);
has the type int * instead of the type char *.
There is no sense to call strncat for one character. Moreover the array word has indeterminate values because it was not initialized.
char word[30], longest_word[30];
You could write
char word[30], longest_word[30];
word[0] = '\0';
And then something like the following
size_t n = 0;
while ((c = getc(input)) != EOF) {
/* If the character is alphanumeric, record it */
if (isAlphanumeric(c)) {
word[n] = ( char )c;
word[++n] = '\0';
}
/* If the character is not alphanumeric, increment the corresponding counter, and additionally, record longest word. */
else {
if (n == 27) strcpy(longest_word, word);
counter[n] += 1;
n = 0;
word[n] = '\0';
}
}
That is, the variable n will keep track of the current length of the string stored in the array word.

C program with fully justification of text from file

Here is my problem statement:
I have a small question related to a portion of code which I can't find a proper solution to. Again I'm not necessarily asking for a full solution I just hit a deadend. I need to read from a file lines (Don't know their lengths) find the maximum length of a line and add spaces between words on each line, evenly, so that they are fully justified (all lines have the same size as the max one).
Here is my code so far:
#include <stdio.h>
#include <stdlib.h>
int main() {
FILE *f;
char *word;
int j, i, m, n, c, k, z;
char aux[255] = "", aux1[255];
i = 0;
j = 0;
char file[100][100];
char s[100];
f = fopen("user_input.txt", "r");
m = 0;
while (fgets(file[i], sizeof(file[i]), f)) {
if (m < strlen(file[i]) - 1)
m = strlen(file[i]) - 1;
i++;
}
for (j = 0; j < i; j++) {
n = 0;
for (k = 0; k < strlen(file[j]); k++)
if (file[j][k] == ' ')
n++;
c = (m - strlen(file[j])) / n;
for (z = 0; z < c; z++)
aux[z] = ' ';
for (k = 0; k < strlen(file[j]); k++)
if (file[j][k] == ' ') {
strcpy(aux1, file[j] + k + 1);
strcat(file[j], aux);
strcat(file[j], aux1);
}
printf("%s", file[j]);
}
}
Your code is broken for multiple reasons:
you forgot to include <string.h>
you have hard coded limits to the maximum line length and the number of lines, both causing a penalty of 0.5p
you do not test for fopen() success, causing undefined behavior upon failure to open the file.
you do not test array boundaries when reading lines, causing undefined behavior if the file has more than 100 lines or 99 byte fragments thereof.
your computation of c = (m - strlen(file[j])) / n; is rounded down. You will not insert enough spaces for full text justification in many cases.
aux is not properly null terminated, it will keep growing up to the largest number of spaces to insert for any given line.
the insertion operation will corrupt the line and ultimately leave just the last word with some spaces inserted before.
the code was badly formated and since you do not use {} for non trivial statement, it is difficult to read and easy to break.
Here is a modified version that does not have such limitations:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
const char *filename = "user_input.txt";
FILE *f;
char *line;
int c, i, len, maxlen, skip, nw, spaces, ns;
/* open the file */
if ((f = fopen(filename, "r")) == NULL) {
fprintf(stderr, "cannot open %s\n", filename);
return 1;
}
/* first pass: determine the maximum line length */
for (maxlen = len = 0;;) {
c = getc(f);
if (c == '\n' || c == EOF) {
if (maxlen < len)
maxlen = len;
len = 0;
if (c == EOF)
break;
} else {
len++;
}
}
/* allocate the line buffer: maxlen characters plus newline plus '\0' */
if ((line = malloc(maxlen + 2)) == NULL) {
fprintf(stderr, "cannot allocate memory for %d bytes\n", maxlen + 2);
fclose(f);
return 1;
}
/* second pass: read one line at a time */
rewind(f);
while (fgets(line, maxlen + 2, f)) {
len = strlen(line);
if (len > 0 && line[len - 1] == '\n') {
/* strip the newline if any */
line[--len] = '\0';
}
/* skip and output initial spaces */
for (skip = 0; line[skip] == ' '; skip++) {
putchar(line[skip]);
}
/* count the words */
for (nw = 0, i = skip; i < len; i++) {
if (line[i] == ' ')
nw++;
}
/* output the text, expanding spaces */
spaces = maxlen - len;
for (i = skip; i < len; i++) {
if (line[i] == ' ') {
ns = spaces / nw;
printf("%*s", ns, "");
spaces -= ns;
nw--;
}
putchar(line[i]);
}
putchar('\n');
}
free(line);
fclose(f);
return 0;
}

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

How to output my results all the way at the end of my program versus at the end of each iteration? (Updated version of previous query)

So my program takes a string, and then outputs it as a marquee sign. I have a for loop so that it may take multiple strings and then outputs each of the strings as a sign.
My problem is: after each iteration, it outputs the sign, and then continues to prompt me for the next string when I want it to just take in all my inputs at once, and then output every sign at the very end. Here is what I'm talking about:
Current Input:
3
Hello World!
5
Sign #1: (This is the output)
[Hello]
[ello ]
[llo W]
[lo Wo]
[o Wor]
[ Worl]
[World]
[orld!]
[rld! ]
[ld! H]
[d! He]
[! Hel]
[ Hell]
Activist
10
Sign #2: (This is the output)
[Activist ]
LOL
2
Sign #3: (This is the output)
[LO]
[OL]
[L ]
[ L]
This is what I want it to do:
Input:
3
Hello World!
5
Activist
10
LOL
2
Output:
Sign #1:
[Hello]
[ello ]
[llo W]
[lo Wo]
[o Wor]
[ Worl]
[World]
[orld!]
[rld! ]
[ld! H]
[d! He]
[! Hel]
[ Hell]
Sign #2:
[Activist ]
Sign #3:
[LO]
[OL]
[L ]
[ L]
Here is my ORIGINAL code:
#include <stdio.h>
#include <string.h>
void ignoreRestOfLine(FILE *fp) {
int c;
while ((c = fgetc(fp)) != EOF && c != '\n');
}
int main() {
int num_times, count = 0;
int marq_length, sign = 0;
scanf("%d ", &num_times);
char s[100];
for (count = 0; count < num_times; count++) {
if (fgets(s, sizeof(s), stdin) == NULL) {
// Deal with error.
}
if (scanf("%d", &marq_length) != 1) {
// Deal with error.
}
ignoreRestOfLine(stdin);
size_t n = strlen(s) - 1;
int i, j;
if (s[strlen(s)-1] == '\n')
s[strlen(s)-1] = '\0';
printf("Sign #%d:\n", ++sign);
if (n <= marq_length) {
printf("[%-*s]\n", marq_length, s);
} else {
for (i = 0; i < n + 1; i++) {
putchar('[');
for (j = 0; j < marq_length; j++) {
char c = s[(i + j) % (n + 1)];
if (!c)
c = ' ';
putchar(c);
}
printf("]\n");
}
}
}
return 0;
}
Here is my UPDATED code, where I added the part of my code that actually outputs the string in a marquee sign into a function. I just don't know how to properly call it back to the main function so it can output all the signs at the very end:
#include <stdio.h>
#include <string.h>
void ignoreRestOfLine(FILE* fp){
int c;
while ( (c = fgetc(fp)) != EOF && c != '\n');
}
char getSign(char s[100], int marq_length);
char getSign(char s[100], int marq_length){
int count =0;
int sign =0;
//char s[100];
if ( fgets(s, sizeof(s), stdin) == NULL )
{
// Deal with error.
}
if ( scanf("%d", &marq_length) != 1 )
{
// Deal with error.
}
ignoreRestOfLine(stdin);
size_t n = strlen(s)-1;
int i,j;
if(s[strlen(s)-1] == '\n')
s[strlen(s)-1] = '\0';
printf("Sign #%d:\n", ++sign);
if (n <= marq_length) {
printf("[%-*s]\n", marq_length, s);
} else {
for (i = 0; i < n + 1; i++) {
putchar('[');
for (j = 0; j < marq_length; j++) {
char c = s[(i + j) % (n + 1)];
if (!c)
c = ' ';
putchar(c);
}
printf("]\n");
}
}
}
int main(){
int i, num_times, sign_length;
char string[100];
scanf("%d", &num_times);
//char *results=malloc(num_times * sizeof(char));
for(i=0 ;i<num_times;i++){
scanf("%s", string);
scanf("%d", &sign_length);
printf((getSign(string, sign_length)));
}
return 0;
}
I think it is good to read all input and then print results because input is short and these size are easy to predict.
Your main() function should be like this
int main(void){
int i, num_times, *sign_length;
char (*string)[100];
/* read number of test cases */
scanf("%d", &num_times);
/* allocate buffer to store input */
sign_length = malloc(sizeof(*sign_length) * num_times);
string = malloc(sizeof(*string) * num_times);
if (sign_length == NULL || string == NULL) {
free(sign_length);
free(string);
return 1;
}
/* read input */
for(i=0 ;i<num_times;i++){
scanf("%99s", string[i]);
scanf("%d", &sign_length[i]);
}
/* process and print */
for(i=0 ;i<num_times;i++){
getSign(string[i], sign_length[i]);
}
/* cleanup */
free(string);
free(sign_length);
return 0;
}
and the part that are trying to destroy the input in getSign()
if ( fgets(s, sizeof(s), stdin) == NULL )
{
// Deal with error.
}
if ( scanf("%d", &marq_length) != 1 )
{
// Deal with error.
}
ignoreRestOfLine(stdin);
have to be deleted.
#include <stdlib.h> have to be added to the head of your code to use malloc() and free().
UPDATE: Here is a program with problems fixed.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void getSign(char s[100], int marq_length, int case_number);
void getSign(char s[100], int marq_length, int case_number){
size_t n = strlen(s)-1;
size_t i,j;
if (strlen(s) < n) n = 0;
if(s[n] == '\n')
s[n] = '\0';
else
n++;
printf("Sign #%d:\n", case_number);
if (n <= (size_t)marq_length) {
printf("[%-*s]\n", marq_length, s);
} else {
for (i = 0; i < n + 1; i++) {
putchar('[');
for (j = 0; j < (size_t)marq_length; j++) {
char c = s[(i + j) % (n + 1)];
if (!c)
c = ' ';
putchar(c);
}
printf("]\n");
}
}
}
int main(void){
int i, num_times, *sign_length;
char (*string)[100];
/* read number of test cases */
if(scanf("%d", &num_times) != 1) return 1;
/* allocate buffer to store input */
sign_length = malloc(sizeof(*sign_length) * num_times);
string = malloc(sizeof(*string) * num_times);
if (sign_length == NULL || string == NULL) {
free(sign_length);
free(string);
return 1;
}
/* read input */
for(i=0 ;i<num_times;i++){
int dummy;
while((dummy = getchar()) != '\n' && dummy != EOF); /* skip rest of previous line */
if(scanf("%99[^\n]%d", string[i], &sign_length[i]) != 2) {
free(sign_length);
free(string);
return 1;
}
}
/* process and print */
for(i=0 ;i<num_times;i++){
getSign(string[i], sign_length[i], i + 1);
}
/* cleanup */
free(string);
free(sign_length);
return 0;
}
The approach I'd take here is to either store the input until all input is read and only then to generate the output, or to store the output and defer it's printing until the end.
The first is IMHO opinion the better approach, because the amount of data to store is less. OTOH is storing the output a good first step to parallelize taking input and generating output. I go with the later as this is closer to the wording in your question.
OK, your output is basically a C string. So you need to store one of these for each input that you get. Luckily you know even before the first iteration how many inputs you'll get, so you can just allocate the correct amount of space beforehand:
char const ** outputs; // A pointer to (an array of) constant C strings
outputs = malloc(sizeof(*outputs) * numInputs);
Then, you read input as you do it and generate your output into a C string. You've been using a stack allocated (constant size) buffer for that. To be able to reuse that buffer in each iteration you need to copy your result out of it:
char * result = malloc(strlen(sign) + 1);
strcpy(result, sign);
And the store that into your array of outputs:
outputs[currentIteration] = result;
Finally, at the end you print each output and free the allocated memory when done with it:
for (size_t o = 0; o < numOutputs; ++o) {
printf("%s\n", outputs[o]);
free(outputs[o]);
}
At the end, don't forget to also free the array that has been allocated for the outputs:
free(outputs);
Notes: You should check each and every allocation whether it succeeded. Moreover, using a constant sized buffer (on the stack) is OK only if you make absolutely sure that this buffer will never overflow! You should try to pack as much of the above and your sign generation in (small) functions.
Sketch of the overall code:
int main() {
// read how many inputs you'll get
// allocate outputs
// iterate, so that for each input:
// you read the input
// generate the sign
// copy the result into the outputs array
// iterate over all outputs
// print output
// free allocated memory of that output
// free memory for outputs
}
Reading the input and generating the sign should be done in two distinct functions (so its neither the original nor the updated code). Basically I think having these functions should give you a reasonable code structure:
// Read both the string and length, allocating memory for the string
bool read_input(char **string, unsigned * marq_length);
// Could alternatively be done with a fixed buffer
bool read_input(char * string, size_t max_string_size, unsigned * marq_length);
// Note: for bool include stdbool, or use a char instead
And one to generate the sign:
// Store the result in the fixed size buffer at dest, check for overflow!
void generate_sign(char * dest, size_t max_dest_size, char const * input, unsigned marq_length);
Things like printing the outputs could be done directly in main, or in a dedicated function.

Resources