Can you give me advice to correct my code? It should initialize new_string from another string, with copying the n first letters from this string. Output should be string. But my code prints nothing. How can I fix it?
Here is my code:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main() {
char str[99];
int n, i, len;
printf("Enter a string:");
scanf("%s", str);
printf("enter n:");
scanf("%i", &n);
if (n > len) {
n = len;
}
char *new_string = malloc(n + 1);
for (int i = 0; i < n; i++) {
new_string[i] = str[i];
}
new_string[i] = '\0';
printf("STring:%s", new_string);
return 0;
}
You could use strncpy as suggested by d.j.yotta in the comments:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main (void)
{
char str[100];
printf("Enter string: ");
/*
* take spaces into account (optional),
* prevent buffer overflow and
* check return value of `scanf`
*/
if (scanf("%99[^\n]", str) != 1) {
fprintf(stderr, "Error: invalid input\n");
return EXIT_FAILURE;
}
int n;
printf("Enter index: ");
/* check return value of `scanf` */
if(scanf("%d", &n) != 1) {
fprintf(stderr, "Error: invalid input\n");
return EXIT_FAILURE;
}
/* initialize `len` */
int len = strlen(str);
if (n > len)
n = len;
char *new_str = malloc(n + 1);
strncpy(new_str, str, n);
printf("New string: %s\n", new_str);
return EXIT_SUCCESS;
}
Or you could make the changes explained in the following code's comments:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main (void)
{
char str[99];
printf("Enter string: ");
/*
* take spaces into account (optional),
* prevent buffer overflow and
* check return value of `scanf`
*/
if (scanf("%99[^\n]", str) != 1) {
fprintf(stderr, "Error: invalid input\n");
return EXIT_FAILURE;
}
int n;
printf("Enter index: ");
/* check return value of `scanf` */
if(scanf("%d", &n) != 1) {
fprintf(stderr, "Error: invalid input\n");
return EXIT_FAILURE;
}
/* initialize `len` */
int len = strlen(str);
if (n > len)
n = len;
char *new_str = malloc(n + 1);
for (int i = 0; i < n; ++i)
new_str[i] = str[i];
/* you don't need `i` here */
new_str[n + 1]= '\0';
printf("New string: %s\n", new_str);
return EXIT_SUCCESS;
}
The problem in your code is not easy to spot: you define two distinct local variables named i: one in the scope of the body of the main function in int n,i, len; and another one in the scope of the for loop: for (int i = 0; i < n; i++) { new_string[i] = str[i]; }. The latter one goes out of scope at the end of the loop and the first one is used to set the null terminator new_string[i]='\0';. This i variable is uninitialized so the statement has undefined behavior and new_string is not properly null terminated.
There are other problems:
you do not prevent buffer overflow in scanf("%s",str);
you do not check for input or conversion failure in scanf().
n is uninitialized in if (n > len) { n = len; }
you do not check for negative n.
you do check for allocation failure after char *new_string = malloc(n + 1);
you do not free new_string after use.
Here is a modified version:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main() {
char str[100];
int n, len;
printf("Enter a string:");
if (scanf("%99s", str) != 1)
return 1;
printf("enter n:");
if (scanf("%i", &n) != 1)
return 1;
len = strlen(str);
if (n > len) {
n = len;
} else
if (n < 0) {
n = 0;
}
char *new_string = malloc(n + 1);
if (new_string == NULL) {
fprintf(stderr, "allocation failure for %d bytes\n", n);
return 1;
}
for (int i = 0; i < n; i++) {
new_string[i] = str[i];
}
new_string[n] = '\0';
printf("String: %s\n", new_string);
free(new_string);
return 0;
}
Note also some alternatives to copy at most n characters from a string:
// assuming new_string points to an array of at least n+1 bytes
strncpy(new_string, str, n);
// assuming new_string points to an array of at least n+1 bytes
snprintf(new_string, n + 1, "%s", str);
// assuming new_string points to an array of at least new_string_size bytes
// and n has type int
snprintf(new_string, new_string_size, "%.*s", n, str);
Since you know that n >= 0 && n <= len, you can use memcpy:
memcpy(new_string, str, n);
new_string[n] = '\0';
You can also use the Posix function strndup() defined in <string.h> that combines allocating enough space, copying at most n bytes and setting the null terminator:
char *new_string = strndup(str, n);
strndup() will be part of the upcoming version of the C Standard (C2x) and is widely available on most platforms as it has been part of the Posix standard for more than 10 years.
#include <stdio.h>
#define N 100
int main(){
char str[N];
scanf("%s",str);
char str1[N];
int i;
for(i=0;i<N;i++){
str1[i]=str[i];
}
printf("%s",str1);
}
i think if you just want to copy a string in a new char variable you can do this please tell if you find anything wrong
I have had a problem with finding the longest common word in two strings for some time now. First I had an idea of doing it with "isspace" function, but couldn't figure out how to find a common word. Then "strcmp" came to my mind, but so far I was only able to compare two strings. I was thinking of some way to incorporate strcmp and isspace in order to find the different words and then use a temp value to find the longest one, but I couldn't think of the correct code to do so.
#include <stdio.h>
int strcmp(char s[],char t[]);
void main()
{
char s[20],t[20];
printf("Type in a string s.\n");
gets(s);
printf("Type in a string t.\n");
gets( t );
printf("The result of comparison=%d\n",strcmp(s,t));
return 0;
}
int strcmp(char s[],char t[])
{
int i;
for(i=0;s[i]==t[i];i++)
if(s[i]=='\0')
return( 0 );
return(s[i]-t[i]);
}
Please help me with this one. All ideas (and code) are welcomed and appreciated. Thank you in advance!
Edit::
I have been battling with this one for a while and I think I have the solution, however it's a very rigid method. The program has a bug, probably with array "ptrArray1", but I cannot fix it.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int returnArrayOfWords (char* str4Parsing, char* arrayParsed[])
{
// returns the length of array
char seps[] = " \t\n"; // separators
char *token = NULL;
char *next_token = NULL;
int i = 0;
// Establish string and get the first token:
token = strtok( str4Parsing, seps);
// While there are tokens in "str4Parsing"
while ((token != NULL))
{
// Get next token:
arrayParsed[i] = token;
//printf( " %s\n", arrayParsed[i] );//to be commented
token = strtok( NULL, seps);
i++;
}
return i;
}
void printArr(char *arr[], int n)
{
int i;
for ( i = 0; i < n; i++)
{
printf("Element %d is %s \n", i, arr[i]);
}
}
void findLargestWord(char *ptrArray1[], int sizeArr1, char *ptrArray2[], int sizeArr2)
{
int maxLength = 0;
char *wordMaxLength = NULL ;
int i = 0, j = 0;
char *w1 = NULL, *w2 = NULL; /*pointers*/
int currLength1 = 0, currLength2 = 0 ;
//printArr(&ptrArray1[0], sizeArr1);
//printArr(&ptrArray2[0], sizeArr2);
for (i = 0; i < sizeArr1; i++)
{
// to find the largest word in the array
w1 = (ptrArray1[i]); // value of address (ptrArray1 + i)
currLength1 = strlen(w1);
//printf("The word from the first string is: %s and its length is : %d \n", w1, currLength1); // check point
for (j = 0; j < sizeArr2; j++)
{
w2 = (ptrArray2[j]); // value of address (ptrArray2 + j)
currLength2 = strlen(w2);
//printf("The word from the second string is : %s and its length is : %d \n", w2, currLength2); // check point
if (strcoll(w1, w2) == 0 && currLength1 == currLength2)
// compares the strings
{
if (currLength2 >= maxLength)
// in the variable maxLength -> the length of the longest word
{
maxLength = currLength2;
wordMaxLength = w2;
printf("The largest word for now is : %s and its length is : %d \n", wordMaxLength, maxLength); // check point
}
}
}
}
printf("The largest word is: %s \n", wordMaxLength);
printf("Its length is: %d \n", maxLength);
}
int main ()
{
int n = 80; /*max number of words in string*/
char arrS1[80], arrS2[80];
char *ptrArray1 = NULL, *ptrArray2 = NULL;
int sizeArr1 = 0, sizeArr2 = 0;
// to allocate memory:
ptrArray1 = (char*)calloc(80, sizeof(char));
if(ptrArray1 == NULL)
{
printf("Error! Memory for Pointer 1 is not allocated.");
exit(0);
}
ptrArray2 = (char*)calloc(80, sizeof(char));
if(ptrArray2 == NULL)
{
printf("Error! Memory for Pointer 2 is not allocated.");
exit(0);
}
printf("Type your first string: ");
fgets(arrS1, 80, stdin);
sizeArr1 = returnArrayOfWords (arrS1, &ptrArray1); // sizeArr1 = number of elements in array 1
printf("Type your second string: ");
fgets(arrS2, 80, stdin);
sizeArr2 = returnArrayOfWords (arrS2, &ptrArray2); // sizeArr2 = number of elements in array 2
findLargestWord(&ptrArray1, sizeArr1, &ptrArray2, sizeArr2);
free(ptrArray1);
free(ptrArray2);
return 0;
}
I also tried to use the latter two posted soltuions, but I have a problem with working with them as stated below.
Any help with my code, fixing my problems with the latter solutions or coming up with new solutions is welcomed. Thank you all in advance!
PS. I'm sorry if my code is poorly placed. I'm still not very good with using the placement.
There are a large number of ways to approach the problem. Below, a pointer to each character in one of the strings is used to search the other for matching characters using strchr. After matching characters are found, a comparison loop runs advancing each of the pointers to devise the length of the common substring present, if any.
The routine, match characters, check substring length, repeat, continues so longs as strchr returns a valid pointer.Each time a longer substring is found, the max length is updated for return and the substring present is copied to r with strncpy and nul-terminated so that the text of the longest common string is available to the calling function, main here.
This is a rather brute force method, and there may be a few additional tweaks to improve efficiency. The function itself is:
/** return length of longest common substring in 'a' and 'b'.
* by searching through each character in 'a' for each match
* in 'b' and comparing substrings present at each match. the
* size of the longest substring is returned, the test of the
* longest common substring is copied to 'r' and made available
* in the calling function. (the lengths should also be passed
* for validation, but that is left as an exercise)
*/
size_t maxspn (const char *a, const char *b, char *r)
{
if (!a||!b||!*a||!*b) return 0; /* valdate parameters */
char *ap = (char *)a; /* pointer to a */
size_t max = 0; /* max substring char */
for (; *ap; ap++) { /* for each char in a */
char *bp = (char *)b; /* find match in b with strchr */
for (; *bp && (bp = strchr (bp, *ap)); bp++) {
char *spa = ap, *spb = bp; /* search ptr initialization */
size_t len = 0; /* find substring len */
for (; *spa && *spb && *spa == *spb; spa++, spb++) len++;
if (len > max) { /* if max, copy to r */
strncpy (r, ap, (max = len));
r[max] = 0; /* nul-terminate r */
}
}
}
return max;
}
The length max is returned, and then updates to r during function execution cause r to hold the string associated with the longest substring match.
Additional improvements were to remove gets which was removed in C11 without deprecation due to its security risk. It should no longer be used by any sane coder (that should cover about 40% of us). Putting the remaining bits together, a small bit of test code could be:
#include <stdio.h>
#include <string.h>
#define MAXC 128
size_t maxspn (const char *a, const char *b, char *r);
void rmlf (char *s);
int main (void) {
char res[MAXC] = "", s[MAXC] = "", t[MAXC] = "";
printf ("Type in a string 's': ");
if (!fgets (s, MAXC, stdin)) { /* validate 's' */
fprintf (stderr, "error: invalid input for 's'.\n");
return 1;
}
rmlf (s); /* remove trailing newline */
printf ("Type in a string 't': ");
if (!fgets (t, MAXC, stdin)) { /* validate 't' */
fprintf (stderr, "error: invalid input for 's'.\n");
return 1;
}
rmlf (t); /* remove trailing newline */
/* obtain longest commons substring between 's' and 't' */
printf ("\nThe longest common string is : %zu ('%s')\n",
maxspn (s, t, res), res);
return 0;
}
/** return length of longest common substring in 'a' and 'b'.
* by searching through each character in 'a' for each match
* in 'b' and comparing substrings present at each match. the
* size of the longest substring is returned, the test of the
* longest common substring is copied to 'r' and made available
* in the calling function. (the lengths should also be passed
* for validation, but that is left as an exercise)
*/
size_t maxspn (const char *a, const char *b, char *r)
{
if (!a||!b||!*a||!*b) return 0; /* valdate parameters */
char *ap = (char *)a; /* pointer to a */
size_t max = 0; /* max substring char */
for (; *ap; ap++) { /* for each char in a */
char *bp = (char *)b; /* find match in b with strchr */
for (; *bp && (bp = strchr (bp, *ap)); bp++) {
char *spa = ap, *spb = bp;
size_t len = 0; /* find substring len */
for (; *spa && *spb && *spa == *spb; spa++, spb++) len++;
if (len > max) { /* if max, copy to r */
strncpy (r, ap, (max = len));
r[max] = 0; /* nul-terminate r */
}
}
}
return max;
}
/** remove trailing newline from 's'. */
void rmlf (char *s)
{
if (!s || !*s) return;
for (; *s && *s != '\n'; s++) {}
*s = 0;
}
Example Use/Output
$ ./bin/strspn
Type in a string 's': a string with colors123456789 all blue
Type in a string 't': a string without colors1234567890 all red
The longest common string is : 16 (' colors123456789')
or, another that may be easier to visualize:
$ ./bin/strspn
Type in a string 's': green eel
Type in a string 't': cold blue steel
The longest common string is : 3 ('eel')
Look over the code and compare with the other answers. Let me know if you have any additional questions. There are a few other validations that should be added to insure text is not written beyond the ends of buffers, etc.. Hopefully this will provide a bit of help or an alternative approach.
Additional Substrings
Just to make sure you and I are seeing the same thing, I have included additional examples of use below. There is no error, and the code preforms as intended. If you are having trouble modifying the code, please let me know what you are attempting to do and I can help. Each of the pointer increments in my code above are validated. If you change anything regarding the pointer increment or nul-termination, the code will not work unless you account for the changes in the validations as well.
$ ./bin/strspn
Type in a string 's': 1
Type in a string 't':
The longest common string is : 0 ('')
$ ./bin/strspn
Type in a string 's': A man a plan a canal panama
Type in a string 't': a man a plan a river panama
The longest common string is : 14 (' man a plan a ')
$ ./bin/strspn
Type in a string 's': this is my favorite string
Type in a string 't': this is my favoritist string
The longest common string is : 18 ('this is my favorit')
$ ./bin/strspn
Type in a string 's': not the same until here
Type in a string 't': cant be equal till here
The longest common string is : 6 ('l here')
$ ./bin/strspn
Type in a string 's': some str with ten in the middle
Type in a string 't': a string often ignorded
The longest common string is : 5 ('ten i')
Longest Common Word
OK, after I finally understand what you are trying to accomplish, you can select the longest common word between the two strings 's' and 't' by tokenizing each string with strtok, saving a pointer to each word in each string in separate pointer arrays, and then simply iterating over the pointer arrays to select the longest common word (1st if multiple common words of the same length). Something as simple as the following is all you need.
NOTE strtok modifies the strings 's' and 't', so make a copy if you need to preserve the originals.
/** return length of longest common word in 'a' and 'b'.
* by tokenizing each word in 'a' & 'b' and iterating over
* each, returning the length of the logest match, and updating
* 'r' to contain the longest common word.
*/
size_t maxspnwhole (char *a, char *b, char *r)
{
if (!a||!b||!*a||!*b) return 0; /* valdate parameters */
char *arra[MAXC] = {NULL}, *arrb[MAXC] = {NULL};
char *ap = a, *bp = b; /* pointers to a & b */
char *delim = " .,-;\t\n"; /* word delimiters */
size_t i, j, len, max, na, nb; /* len, max, n-words */
len = max = na = nb = 0;
/* tokenize both strings into pointer arrays */
for (ap = strtok (a, delim); ap; ap = strtok (NULL, delim))
arra[na++] = ap;
for (bp = strtok (b, delim); bp; bp = strtok (NULL, delim))
arrb[nb++] = bp;
for (i = 0; i < na; i++) /* select longest common word */
for (j = 0; j < nb; j++)
if (*arra[i] == *arrb[j]) /* 1st chars match */
if (!strcmp (arra[i], arrb[j])) { /* check word */
len = strlen (arra[i]);
if (len > max) { /* if longest */
max = len; /* update max */
strcpy (r, arra[i]); /* copy to r */
}
}
return max;
}
Integrating it with the other code, you can compare the results like this:
#include <stdio.h>
#include <string.h>
#define MAXC 128
size_t maxspn (const char *a, const char *b, char *r);
size_t maxspnwhole (char *a, char *b, char *r);
void rmlf (char *s);
int main (void) {
char res[MAXC] = "", s[MAXC] = "", t[MAXC] = "";
printf ("Type in a string 's': ");
if (!fgets (s, MAXC, stdin)) { /* validate 's' */
fprintf (stderr, "error: invalid input for 's'.\n");
return 1;
}
rmlf (s); /* remove trailing newline */
printf ("Type in a string 't': ");
if (!fgets (t, MAXC, stdin)) { /* validate 't' */
fprintf (stderr, "error: invalid input for 's'.\n");
return 1;
}
rmlf (t); /* remove trailing newline */
/* obtain longest commons substring between 's' and 't' */
printf ("\nThe longest common string is : %zu ('%s')\n",
maxspn (s, t, res), res);
/* obtain longest commons word between 's' and 't' */
printf ("\nThe longest common word is : %zu ('%s')\n",
maxspnwhole (s, t, res), res);
return 0;
}
/** return length of longest common word in 'a' and 'b'.
* by tokenizing each word in 'a' & 'b' and iterating over
* each, returning the length of the logest match, and updating
* 'r' to contain the longest common word.
*/
size_t maxspnwhole (char *a, char *b, char *r)
{
if (!a||!b||!*a||!*b) return 0; /* valdate parameters */
char *arra[MAXC] = {NULL}, *arrb[MAXC] = {NULL};
char *ap = a, *bp = b; /* pointers to a & b */
char *delim = " .,-;\t\n"; /* word delimiters */
size_t i, j, len, max, na, nb; /* len, max, n-words */
len = max = na = nb = 0;
/* tokenize both strings into pointer arrays */
for (ap = strtok (a, delim); ap; ap = strtok (NULL, delim))
arra[na++] = ap;
for (bp = strtok (b, delim); bp; bp = strtok (NULL, delim))
arrb[nb++] = bp;
for (i = 0; i < na; i++)
for (j = 0; j < nb; j++)
if (*arra[i] == *arrb[j])
if (!strcmp (arra[i], arrb[j])) {
len = strlen (arra[i]);
if (len > max) {
max = len;
strcpy (r, arra[i]);
}
}
return max;
}
/** return length of longest common substring in 'a' and 'b'.
* by searching through each character in 'a' for each match
* in 'b' and comparing substrings present at each match. the
* size of the longest substring is returned, the test of the
* longest common substring is copied to 'r' and made available
* in the calling function. (the lengths should also be passed
* for validation, but that is left as an exercise)
*/
size_t maxspn (const char *a, const char *b, char *r)
{
if (!a||!b||!*a||!*b) return 0; /* valdate parameters */
char *ap = (char *)a; /* pointer to a */
size_t max = 0; /* max substring char */
for (; *ap; ap++) { /* for each char in a */
char *bp = (char *)b; /* find match in b with strchr */
for (; *bp && (bp = strchr (bp, *ap)); bp++) {
char *spa = ap, *spb = bp;
size_t len = 0; /* find substring len */
for (; *spa && *spb && *spa == *spb; spa++, spb++) len++;
if (len > max) { /* if max, copy to r */
strncpy (r, ap, (max = len));
r[max] = 0; /* nul-terminate r */
}
}
}
return max;
}
/** remove trailing newline from 's'. */
void rmlf (char *s)
{
if (!s || !*s) return;
for (; *s && *s != '\n'; s++) {}
*s = 0;
}
Example Use/Output
$ ./bin/strlongestcmn
Type in a string 's': I have a huge boat.
Type in a string 't': I have a small boat.
The longest common string is : 9 ('I have a ')
The longest common word is : 4 ('have')
Look it over and let me know if you have any further questions.
This example prints the longest substring given two input strings.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int *lcommon(char *str1, char *str2) {
int strlen1 = (unsigned) strlen(str1);
int strlen2 = (unsigned) strlen(str2);
int i, j, k;
int longest = 0;
int **ptr = malloc(2 * sizeof(int *));
static int *ret;
ret = calloc((unsigned) strlen1 + 1, sizeof(int));
for (i = 0; i < 2; i++)
ptr[i] = calloc((unsigned) strlen2, sizeof(int));
k = 0;
for (i = 0; i < strlen1; i++) {
memcpy(ptr[0], ptr[1], strlen2 * sizeof(int));
for (j = 0; j < strlen2; j++) {
if (str1[i] == str2[j]) {
if (i == 0 || j == 0) {
ptr[1][j] = 1;
} else {
ptr[1][j] = ptr[0][j-1] + 1;
}
if (ptr[1][j] > longest) {
longest = ptr[1][j];
k = 0;
ret[k++] = longest;
}
if (ptr[1][j] == longest) {
ret[k++] = i;
ret[k] = -1;
}
} else {
ptr[1][j] = 0;
}
}
}
for (i = 0; i < 2; i++)
free(ptr[i]);
free(ptr);
ret[0] = longest;
return ret;
}
int main(int argc, char *argv[]) {
int i, longest, *ret;
if (argc != 3) {
printf("usage: longest-common-substring string1 string2\n");
exit(1);
}
ret = lcommon(argv[1], argv[2]);
if ((longest = ret[0]) == 0) {
printf("There is no common substring\n");
exit(2);
}
i = 0;
while (ret[++i] != -1) {
printf("%.*s\n", longest, &argv[1][ret[i]-longest+1]);
}
exit(0);
}
Test
$ ./a.out computerprogramming javaprogrammer
programm
You can read more about the problem here.
You can also use an interactive program where you write the strings in the console:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int *lcommon(char *str1, char *str2) {
int strlen1 = (unsigned) strlen(str1);
int strlen2 = (unsigned) strlen(str2);
int i, j, k;
int longest = 0;
int **ptr = malloc(2 * sizeof(int *));
static int *ret;
ret = calloc((unsigned) strlen1 + 1, sizeof(int));
for (i = 0; i < 2; i++)
ptr[i] = calloc((unsigned) strlen2, sizeof(int));
k = 0;
for (i = 0; i < strlen1; i++) {
memcpy(ptr[0], ptr[1], strlen2 * sizeof(int));
for (j = 0; j < strlen2; j++) {
if (str1[i] == str2[j]) {
if (i == 0 || j == 0) {
ptr[1][j] = 1;
} else {
ptr[1][j] = ptr[0][j - 1] + 1;
}
if (ptr[1][j] > longest) {
longest = ptr[1][j];
k = 0;
ret[k++] = longest;
}
if (ptr[1][j] == longest) {
ret[k++] = i;
ret[k] = -1;
}
} else {
ptr[1][j] = 0;
}
}
}
for (i = 0; i < 2; i++)
free(ptr[i]);
free(ptr);
ret[0] = longest;
return ret;
}
int main(int argc, char *argv[]) {
int i, longest, *ret;
if (argc != 3) {
//printf("usage: longest-common-substring string1 string2\n");
char s[20], t[20];
printf("Type in a string s.\n");
fgets(s, 20, stdin);
printf("Type in a string t.\n");
fgets(t, 20, stdin);
ret = lcommon(s, t);
if ((longest = ret[0]) == 0) {
printf("There is no common substring\n");
exit(2);
}
i = 0;
while (ret[++i] != -1) {
printf("%.*s\n", longest, &s[ret[i] - longest + 1]);
}
//printf("The result of comparison=%d\n", strcmp(s, t));
exit(0);
} else { }
ret = lcommon(argv[1], argv[2]);
if ((longest = ret[0]) == 0) {
printf("There is no common substring\n");
exit(2);
}
i = 0;
while (ret[++i] != -1) {
printf("%.*s\n", longest, &argv[1][ret[i] - longest + 1]);
}
exit(0);
}
Test
Type in a string s.
string1
Type in a string t.
string2
string
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.
I'm trying to modify a previous program I wrote using pure pointer notation. It's a program that generates a random string of 40 uppercase letter, takes input of up to 20 uppercase letter, and input of a character. The program replaces reoccurring characters in the generated string with the character entered. Right now, I'm trying to pass the parameters of the randomly generated string so I can access them in the second function and can't figure out how to do it.
Thank you for the help.
#include <stdio.h>
#include <stdlib.h>
/* Function prototypes */
void fillS1(char * x);
void fillS2(char * x, char * y, char z);
void strFilter(char * a, char * b, char c);
int main(int argc, const char * argv[])
{
char s1[41];
char s2[21];
char x = 0;
char * pointerToS1;
char * pointerToS2;
pointerToS1 = s1;
pointerToS2 = s2;
fillS2(pointerToS2, pointerToS1, x);
return 0;
}
/* Function to generate a random string of 40 uppercase letters */
void fillS1(char * randomlyGeneratedPointer)
{
char randomlyGeneratedArray[41];
randomlyGeneratedPointer = randomlyGeneratedArray;
int i;
for (i = 0; i < 40; i++) {
*(randomlyGeneratedPointer + i) = 'A' + rand() % 26;
}
}
/* Function to get user input of characters */
void fillS2(char * userStringPointer, char * randomStringPointer, char replacementCharacter)
{
char userstring[21];
char randomString[41];
char copyString[42];
//char * pointerToCopyString = copyString;
userStringPointer = userstring;
int i = 0;
int n = 0;
int lowercaseCheck = 0;
char loopContinue = 0;
fillS1(randomStringPointer); //here is the function call for the randomly generated string.
printf("This is the random string: %s", randomStringPointer);
do {
/* For loop to copy the first randomly generated string */
for(i = 0; i < 42; i++)
*(randomStringPointer + i) = copyString[i];
randomStringPointer = copyString;
i = 0;
lowercaseCheck = 0;
/* While loop to to get user input */
printf("Please enter at least 2 capital letters and a maximum of 20.\n");
while ((((*(userStringPointer + i)) = getchar()) != '\n')) {
/* Counter to determine how many characters were entered */
i++;
}
/* Adding 1 to add to add null character */
i++;
*(userStringPointer + i) = '\0';
//printf("This is the user's string %s", userStringPointer);
/* Capital letter check */
for (n = 0; n < 20; n++) {
if (((*(userStringPointer + n)) >= 'a') && (*(userStringPointer + n) <= 'z')) {
lowercaseCheck++;
}
}
if (--i < 3) {
printf("You need at least two letters\n");
}
else if (i > 21){
printf("You cannot have more than twenty letters\n");
}
else if (lowercaseCheck == 0) {
puts(userStringPointer);
printf("Enter a character to replace occuring letters.\n");
scanf("%c", &replacementCharacter);
getchar();
//printf("this is the copy string before strFilter: %s", randomStringPointer);
//printf("This is the replacement character %c", replacementCharacter);
strFilter(randomStringPointer, userStringPointer, replacementCharacter);
}
else
printf("You must have 2 capital letters.\n");
printf("Would you like to enter another string (y/n)?\n");
loopContinue = getchar();
getchar();
} while (loopContinue != 'n' && loopContinue != 'N');
}
/* Function to replace letters with the character chosen by the user */
void strFilter(char * replacementCopyStringPointer, char * replacementUserStringPointer, char c)
{
int i = 0;
int n = 0;
while (n < 20) {
for (i = 0; i < 40; i++) {
if ((*(replacementCopyStringPointer + i)) == *(replacementUserStringPointer + n)){
*(replacementCopyStringPointer + i) = c;
}
}
i = 0;
n++;
}
puts(replacementCopyStringPointer);
}
randomlyGeneratedArray array in fillS1 would get destroyed once fillS1 function returns.
You should allocate the memory from heap for randomlyGeneratedArray.
randomlyGeneratedArray = (char *)malloc(sizeof(char)*41)
Also do the same for userStringPointer in fillS2.
That should solve the problem.
For difference between stack and heap read this question What and where are the stack and heap?