I'm learning C through K & R. I have reached to section 1.10 External Variables and Scope.
In that section they have written and explained program regarding external variable and their scope. I typed that code myself and tried to execute it. It does not show any run time or compile time error. However, it does not print any output also, which should be longest line from given input. I did debug the program and I found that program is skipping 'printf()' statement. I tried both on sublime text 2 + gcc and Turbo c++ v4.5, but still I don't get an output. I'm using Windows xpsp 3.
Here is my code :
#include<stdio.h>
/* program to pring longest line using external variables */
#define MAXSIZE 1000
int max;
char line[ MAXSIZE ];
char longest[ MAXSIZE ];
int getline( void );
void copy( void );
main()
{
int len;
extern int max;
extern char longest[];
max = 0;
while( ( len = getline() ) > 0 )
{
if( len > max )
{
len = max;
copy();
}
}
if( max > 0)
printf("\n%s\n", longest); /* This line is skipped */
return 0;
}
int getline( void ) /* Check if there is line */
{
int c, i;
extern char line[];
for( i = 0; i < MAXSIZE -1 && ( c = getchar()) != EOF && c != '\n'; ++i )
line[ i ] = c;
if( c == '\n' )
{
line[ i ] = c;
++i;
}
line[ i ] = '\0';
return i;
}
void copy( void ) /* copy current line to longest if it is long */
{
int i = 0;
extern char line[];
extern char longest[];
while( ( longest[ i ] = line[ i ] ) != '\0' )
++i;
}
So my questions are :
Why is this happening?
What should I do so that program won't skip 'printf()' and will print an output?
Please help. Thank you.
The intent of this code is to start max at zero then, for every line longer than the current max, copy the line and update max to the longer value:
max = 0;
while( ( len = getline() ) > 0 )
{
if( len > max )
{
len = max;
copy();
}
}
However, the line that's supposed to update max is assigning in the wrong direction. It sets len to be the current value of max and never updates max at all. This is something that would have been obvious with a bit of "Debugging 101", placing the following line after the call to copy():
printf ("New long line, len = %d, str = '%s'\n", max, longest);
That fact that you would never have seen the length changing would have (hopefully) narrowed down the problem pretty fast. The line in question should instead be:
max = len;
Related
Starting C on my own following Kerningan & Ritchie 2nd edition ANSCI book.
Here, I am supposed to return the longest lign of a text.
very early in the book, so few functions are cited.
My program returns the ligns AFTER the longest lign
A lign being only defined by ending with '.'
I'm probably overstepping on this forum with my beginner level, but i'd appreciate the insight :) thanks a lot.
#include <stdio.h>
#include <stdlib.h>
#define MAXLEN 1000
void copcol(char cop[], char retour[]);
int main(void)
{
int nbmax, nbnew, c, i;
nbmax = nbnew = i = 0 ;
char lignmax[MAXLEN] ;
char lignnew[MAXLEN] ;
while((c=getchar()) != EOF)
{
lignnew[i] = c ;
i++;
nbnew++ ;
if( (c == '.') && (nbmax < nbnew) && ( c != '\0'))
{
nbmax = nbnew ;
copcol(lignmax, lignnew);
nbnew = 0 ;
i=0 ;
}
}
if ( nbmax > 0 )
printf("%s",lignmax);
return 0;
}
void copcol(char new[], char max[])
{
int i ;
i=0;
while((new[i] = max[i]) != '\0')
++i;
}
also if a forum is more apropriate for this kind of questions, feel free to let me know.
You need to skip shorter lines when you encounter period (.)
#include <stdio.h>
#include <stdlib.h>
#define MAXLEN 1000
void copcol (char new[], char max[]) {
int i = 0;
while ((new[i] = max[i]) != '\0')
++i;
}
int main (void) {
char lignmax[MAXLEN] ;
char lignnew[MAXLEN] ;
int nbmax, nbnew, c;
nbmax = nbnew = 0 ;
while ( (c = getchar()) != EOF) {
// nbnew also tracks the new-line-len
lignnew[nbnew++] = c ;
if ('.' == c) { // line ended, skip shorter, copy longer line
if (nbnew > nbmax) { // copying only when longer than current max-line
nbmax = nbnew ;
lignnew[nbnew] = '\0'; // terminate string
copcol (lignmax, lignnew);
}
//also ignores shorter-lines
nbnew = 0 ; // new line begins after the period (.)
}
}
if (nbmax > 0)
printf ("MaxLength: %d\n MaxLine: [%s]", nbmax, lignmax);
return 0;
}
Note: Input period(.) terminated lines cannot be longer than (MAXLEN -1), it'll cause buffer-overflow otherwise.
I have a long string and I want to store every string that starts and ends with a special word into an array, and then remove duplicate strings. In my long string, there is no space, , or any other separation between words so that I cannot use strtok. The start marker is start and the end marker is end. This is the code I have so far (but it doesn't work because it is using strtok()).
char buf[] = "start-12-3.endstart-12-4.endstart-13-3.endstart-12-4.end";
char *array[5];
char *x;
int i = 0, j = 0;
array[i] = strtok(buf, "start");
while (array[i] != NULL) {
array[++i] = strtok(NULL, "start");
}
//removeDuplicate(array[i]);
for (i = 0; i < 5; i++)
for (j = 0; j < 5; j++)
if (strcmp(array[i], array[j]) == 0)
x[i++] = array[i];
printf("%s", x[i]);
Example input:
start-12-3.endstart-12-4.endstart-13-3.endstart-12-4.end
Output equivalent to:
char *array[]= { "start-12-3.end", "start-12-4.end", "start-13-3.end" };
The second start-12-4.end string has been eliminated in the output.
*I've also used strstr but has some issue:
int main(int argc, char **argv)
{
char string[] = "This-one.testthis-two.testthis-three.testthis-two.test";
int counter = 0;
while (counter < 4)
{
char *result1 = strstr(string, "this");
int start = result1 - string;
char *result = strstr(string, "test");
int end = result - string;
end += 4;
printf("\n%s\n", result);
memmove(result, result1, end += 4);
counter++;
}
}
To put string into array and remove duplicate string, I've tried following code but it has issue:
int main(void)
{
char string[] = "this-one.testthis-two.testthis-three.testthis-two.test";
int counter = 0;
const char *b_token = "this";
const char *e_token = "test";
int e_len = strlen(e_token);
char *buffer = string;
char *b_mark;
char *e_mark;
char *a[50];
int i=0, j;
char *s;
while ((b_mark = strstr(buffer, b_token)) != 0 && (e_mark =strstr(b_mark, e_token)) != 0)
{
int length = e_mark + e_len - b_mark;
s = (char *) malloc(length);
strncpy(s, b_mark, length);
a[i]=s;
i++;
buffer = e_mark + e_len;
}
for (i=0; i<strlen(s); i++)
printf ("%s",a[i]);
free(s);
/*
//remove duplicate string
for (i=0; i<4; i++)
for (j=0; j<4; j++)
{
if (a[i] == NULL || a[j] == NULL || i == j)
continue;
if (strcmp (a[i], a[j]) == 0) {
free(a[i]);
a[i] = NULL;
}
printf("%s\n", a[i]);
*/
return 0;
}
Works with provided example of yours and tested in Valgrind for mem leaks, but might require further testing.
#include <malloc.h>
#include <stdio.h>
#include <string.h>
unsigned tokens_find_amount( char const* const string, char const* const delim )
{
unsigned counter = 0;
char const* pos = string;
while( pos != NULL )
{
if( ( pos = strstr( pos, delim ) ) != NULL )
{
pos++;
counter++;
}
}
return counter;
}
void tokens_remove_duplicate( char** const tokens, unsigned tokens_num )
{
for( unsigned i = 0; i < tokens_num; i++ )
{
for( unsigned j = 0; j < tokens_num; j++ )
{
if( tokens[i] == NULL || tokens[j] == NULL || i == j )
continue;
if( strcmp( tokens[i], tokens[j] ) == 0 )
{
free( tokens[i] );
tokens[i] = NULL;
}
}
}
}
void tokens_split( char const* const string, char const* const delim, char** tokens )
{
unsigned counter = 0;
char const* pos, *lastpos;
lastpos = string;
pos = string + 1;
while( pos != NULL )
{
if( ( pos = strstr( pos, delim ) ) != NULL )
{
*(tokens++) = strndup( lastpos, (unsigned long )( pos - lastpos ));
lastpos = pos;
pos++;
counter++;
continue;
}
*(tokens++) = strdup( lastpos );
}
}
void tokens_free( char** tokens, unsigned tokens_number )
{
for( unsigned i = 0; i < tokens_number; ++i )
{
free( tokens[ i ] );
}
}
void tokens_print( char** tokens, unsigned tokens_number )
{
for( unsigned i = 0; i < tokens_number; ++i )
{
if( tokens[i] == NULL )
continue;
printf( "%s ", tokens[i] );
}
}
int main(void)
{
char const* buf = "start-12-3.endstart-12-4.endstart-13-3.endstart-12-4.end";
char const* const delim = "start";
unsigned tokens_number = tokens_find_amount( buf, delim );
char** tokens = malloc( tokens_number * sizeof( char* ) );
tokens_split( buf, delim, tokens );
tokens_remove_duplicate( tokens, tokens_number );
tokens_print( tokens, tokens_number );
tokens_free( tokens, tokens_number );
free( tokens );
return 0;
}
Basic splitting — identifying the strings
In a comment, I suggested:
Use strstr() to locate occurrences of your start and end markers. Then use memmove() (or memcpy()) to copy parts of the strings around. Note that since your start and end markers are adjacent in the original string, you can't simply insert extra characters into it — which is also why you can't use strtok(). So, you'll have to make a copy of the original string.
Another problem with strtok() is that it looks for any one of the delimiter characters — it does not look for the characters in sequence. But strtok() modifies its input string, zapping the delimiter it finds, which is clearly not what you need. Generally, IMO, strtok() is only a source of headaches and seldom an answer to a problem. If you must use something like strtok(), use POSIX strtok_r() or Microsoft's strtok_s(). Microsoft's function is essentially the same as strtok_r() except for the spelling of the function name. (The Standard C Annex K version of strtok_s() is different from both POSIX and Microsoft — see Do you use the TR 24731 'safe' functions?)
In another comment, I noted:
Use strstr() again, starting from where the start portion ends, to find the next end marker. Then, knowing the start of the whole section, and the start of the end and the length of the end, you can arrange to copy precisely the correct number of characters into the new string, and then null terminate if that's appropriate, or comma terminate. Something like:
if ((start = strstr(source, "start")) != 0 && ((end = strstr(start, "end")) != 0)
then the data is between start and end + 2 (inclusive) in your source string. Repeat starting from the character after the end of 'end'.
You then said:
I've tried following code but it doesn't work fine; would u please tell me what's wrong with it?
#include <stdio.h>
#include <string.h>
int main(int argc, char **argv)
{
char string[] = "This-one.testthis-two.testthis-three.testthis-two.test";
int counter = 0;
while (counter < 4)
{
char *result1 = strstr(string, "This");
int start = result1 - string;
char *result = strstr(string, "test");
int end = result - string;
end += 4;
printf("\n%s\n", result);
memmove(result, result1, end += 4);
counter++;
}
}
I observed:
The main problem appears to be searching for This with a capital T but the string only contains a single capital T. You should also look at Is there a way to specify how many characters of a string to print out using printf()?
Even assuming you fix the This vs this glitch, there are other issues.
You print the entire string.
You don't change the starting point for the search.
Your moving code adds 4 to end a second time.
You don't use start.
The code should print from result1, not result.
With those fixed, the code runs but produces:
testthis-two.testthis-three.testthis-two.test
testtestthis-three.testthis-two.test
testtthis-two.test
test?
and a core dump (segmentation fault).
Code identifying the strings
This is what I created, based on a mix of your code and my commentary:
#include <stdio.h>
#include <string.h>
int main(void)
{
char string[] = "this-one.testthis-two.testthis-three.testthis-two.test";
int counter = 0;
const char *b_token = "this";
const char *e_token = "test";
int e_len = strlen(e_token);
char *buffer = string;
char *b_mark;
char *e_mark;
while ((b_mark = strstr(buffer, b_token)) != 0 &&
(e_mark = strstr(b_mark, e_token)) != 0)
{
int length = e_mark + e_len - b_mark;
printf("%d: %.*s\n", ++counter, length, b_mark);
buffer = e_mark + e_len;
}
return 0;
}
Clearly, this code does no moving of data, but being able to isolate the data to be moved is a key first step to completing that part of the exercise. Extending it to make copies of the strings so that they can be compared is fairly easy. If it is available to you, the strndup() function will be useful:
char *strndup(const char *s1, size_t n);
The strndup() function copies at most n characters from the string s1 always NUL terminating the copied string.
If you don't have it available, it is pretty straight-forward to implement, though it is more straight-forward if you have strnlen() available:
size_t strnlen(const char *s, size_t maxlen);
The strnlen() function attempts to compute
the length of s, but never scans beyond the first maxlen bytes of s.
Neither of these is a standard C library function, but they're defined as part of POSIX (strnlen()
and strndup()) and are available on BSD and Mac OS X; Linux has them, and probably other versions of Unix do too. The specifications shown are quotes from the Mac OS X man pages.
Example output:
I called the program stst (for start-stop).
$ ./stst
1: this-one.test
2: this-two.test
3: this-three.test
4: this-two.test
$
There are multiple features to observe:
Since main() ignores its arguments, I removed the arguments (my default compiler options won't allow unused arguments).
I case-corrected the string.
I set up constant strings b_token and e_token for the beginning and end markers. The names are symmetric deliberately. This could readily be transplanted into a function where the tokens are arguments to the function, for example.
Similarly I created the b_mark and e_mark variables for the positions of the begin and end markers.
The name buffer is a pointer to where to start searching.
The loop uses the test I outlined in the comments, adapted to the chosen names.
The printing code determines how long the found string is and prints only that data. It prints the counter value.
The reinitialization code skips all the previously printed material.
Command line options for generality
You could generalize the code a bit by accepting command line arguments and processing each of those in turn if any are provided; you'd use the string you provide as a default when no string is provided. A next level beyond that would allow you to specify something like:
./stst -b beg -e end 'kalamazoo-beg-waffles-end-tripe-beg-for-mercy-end-of-the-road'
and you'd get output such as:
1: beg-waffles-end
2: beg-for-mercy-end
Here's code that implements that, using the POSIX getopt().
#include <stdio.h>
#include <string.h>
#include <unistd.h>
int main(int argc, char **argv)
{
char string[] = "this-one.testthis-two.testthis-three.testthis-two.test";
const char *b_token = "this";
const char *e_token = "test";
int opt;
int b_len;
int e_len;
while ((opt = getopt(argc, argv, "b:e:")) != -1)
{
switch (opt)
{
case 'b':
b_token = optarg;
break;
case 'e':
e_token = optarg;
break;
default:
fprintf(stderr, "Usage: %s [-b begin][-e end] ['beginning-to-end...' ...]\n", argv[0]);
return 1;
}
}
/* Use string if no argument supplied */
if (optind == argc)
{
argv[argc-1] = string;
optind = argc - 1;
}
b_len = strlen(b_token);
e_len = strlen(e_token);
printf("Begin: (%d) [%s]\n", b_len, b_token);
printf("End: (%d) [%s]\n", e_len, e_token);
for (int i = optind; i < argc; i++)
{
char *buffer = argv[i];
int counter = 0;
char *b_mark;
char *e_mark;
printf("Analyzing: [%s]\n", buffer);
while ((b_mark = strstr(buffer, b_token)) != 0 &&
(e_mark = strstr(b_mark + b_len, e_token)) != 0)
{
int length = e_mark + e_len - b_mark;
printf("%d: %.*s\n", ++counter, length, b_mark);
buffer = e_mark + e_len;
}
}
return 0;
}
Note how this program documents what it is doing, printing out the control information. That can be very important during debugging — it helps ensure that the program is working on the data you expect it to be working on. The searching is better too; it works correctly with the same string as the start and end marker (or where the end marker is a part of the start marker), which the previous version did not (because this version uses b_len, the length of b_token, in the second strstr() call). Both versions are quite happy with adjacent end and start tokens, but they're equally happy to skip material between an end token and the next start token.
Example runs:
$ ./stst -b beg -e end 'kalamazoo-beg-waffles-end-tripe-beg-for-mercy-end-of-the-road'
Begin: (3) [beg]
End: (3) [end]
Analyzing: [kalamazoo-beg-waffles-end-tripe-beg-for-mercy-end-of-the-road]
1: beg-waffles-end
2: beg-for-mercy-end
$ ./stst -b th -e th
Begin: (2) [th]
End: (2) [th]
Analyzing: [this-one.testthis-two.testthis-three.testthis-two.test]
1: this-one.testth
2: this-th
$ ./stst -b th -e te
Begin: (2) [th]
End: (2) [te]
Analyzing: [this-one.testthis-two.testthis-three.testthis-two.test]
1: this-one.te
2: this-two.te
3: this-three.te
4: this-two.te
$
After update to question
You have to account for the trailing null byte by allocating enough space for length + 1 bytes. Using strncpy() is fine but in this context guarantees that the string is not null terminated; you must null terminate it.
Your duplicate elimination code, commented out, was not particularly good — too many null checks when none should be necessary. I've created a print function; the tag argument allows it to identify which set of data it is printing. I should have put the 'free' loop into a function. The duplicate elimination code could (should) be in a function; the string extraction code could (should) be in a function — as in the answer by pikkewyn. I extended the test data (string concatenation is wonderful in contexts like this).
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static void dump_strings(const char *tag, char **strings, int num_str)
{
printf("%s (%d):\n", tag, num_str);
for (int i = 0; i < num_str; i++)
printf("%d: %s\n", i, strings[i]);
putchar('\n');
}
int main(void)
{
char string[] =
"this-one.testthis-two.testthis-three.testthis-two.testthis-one.test"
"this-1-testthis-1-testthis-2-testthis-1-test"
"this-1-testthis-1-testthis-1-testthis-1-test"
;
const char *b_token = "this";
const char *e_token = "test";
int b_len = strlen(b_token);
int e_len = strlen(e_token);
char *buffer = string;
char *b_mark;
char *e_mark;
char *a[50];
int num_str = 0;
while ((b_mark = strstr(buffer, b_token)) != 0 && (e_mark = strstr(b_mark + b_len, e_token)) != 0)
{
int length = e_mark + e_len - b_mark;
char *s = (char *) malloc(length + 1); // Allow for null
strncpy(s, b_mark, length);
s[length] = '\0'; // Null terminate the string
a[num_str++] = s;
buffer = e_mark + e_len;
}
dump_strings("After splitting", a, num_str);
//remove duplicate strings
for (int i = 0; i < num_str; i++)
{
for (int j = i + 1; j < num_str; j++)
{
if (strcmp(a[i], a[j]) == 0)
{
free(a[j]); // Free the higher-indexed duplicate
a[j] = a[--num_str]; // Move the last element here
j--; // Examine the new string next time
}
}
}
dump_strings("After duplicate elimination", a, num_str);
for (int i = 0; i < num_str; i++)
free(a[i]);
return 0;
}
Testing with valgrind gives this a clean bill of health: no memory faults, no leaked data.
Sample output:
After splitting (13):
0: this-one.test
1: this-two.test
2: this-three.test
3: this-two.test
4: this-one.test
5: this-1-test
6: this-1-test
7: this-2-test
8: this-1-test
9: this-1-test
10: this-1-test
11: this-1-test
12: this-1-test
After duplicate elimination (5):
0: this-one.test
1: this-two.test
2: this-three.test
3: this-1-test
4: this-2-test
I don't know what is the matter.. it works great when I run on my pc but when I submit in uva OJ it says time limit exceeded please help
Here is my solution:
#include <stdio.h>
int main()
{
long int i,j,c,t,k,u,r;
scanf("%d %d",&i,&j);
printf("%d %d",i,j);
r = 0;
if(i>j){
t = i;
i = j;
j = t;
}
for(k = i; k<=j;k++){
c = 1;
u = k;
while(u>1){
if(u%2 == 0)
u = u/2;
else
u = 3*u+1;
c++;
if(c>=r)
r = c;
}
}
printf (" %d",r);
return 0;
}
The following code, on my ubuntu Linux 14.04 takes about 1 second to run, when invoked via:
./untitled > outfile.txt
so perhaps this could be useful.
Note: this will have to be modified significantly for the euler problem
Note: the problem says "UNDER" 1 million, but this code starts at 1 million rather than starting at 999999
// Longest Collatz sequence
// Problem 14
/*
* criteria
* The following iterative sequence is defined for the set of positive integers:
* n → n/2 (n is even)
* n → 3n + 1 (n is odd)
*
* example:
* Using the rule above and starting with 13, we generate the following sequence:
* 13 → 40 → 20 → 10 → 5 → 16 → 8 → 4 → 2 → 1
* It can be seen that this sequence (starting at 13 and finishing at 1) contains 10 terms.
* Although it has not been proved yet (Collatz Problem),
* it is thought that all starting numbers finish at 1.
*
* the question:
* Which starting number, under one million, produces the longest chain?
*
* Note:
* Once the chain starts the terms are allowed to go above one million.
*/
#include <stdio.h>
// prototypes
void fastWrite( size_t a );
int main( void )
{
#define MAX_START_VALUE (1000000)
size_t LongestChain = 0;
size_t LongestStartValue = 0;
for( size_t i=MAX_START_VALUE; i; i--)
{
size_t chainLength = 0;
size_t result = i;
// for debug
char buffer[] = "current start value:";
for( size_t j=0; buffer[j]; j++) putchar_unlocked( buffer[j] );
putchar_unlocked( ' ');
fastWrite( i );
// end debug
while( result != 1 )
{
chainLength++;
if( result&1 )
{ // then odd
result = 3*result +1;
}
else
{ // else even
result >>= 1;
}
// for debug
//./fastWrite( result );
// end debug
}
chainLength++;
// for debug
char buffer2[] = "chain length: ";
for( size_t k=0; buffer2[k]; k++) putchar_unlocked( buffer2[k] );
fastWrite( chainLength );
putchar_unlocked( '\n' );
// end debug
if ( chainLength > LongestChain )
{
LongestChain = chainLength;
LongestStartValue = i;
}
}
fastWrite( LongestStartValue );
putchar_unlocked('\n');
//putchar_unlocked('\n');
} // end function: main
inline void fastWrite(size_t a)
{
char snum[20];
//printf( "%s, %lu\n", __func__, a );
int i=0;
do
{
// 48 is numeric character 0
snum[i++] = (char)((a%10)+(size_t)48);
a=a/10;
}while(a>0);
i=i-1; // correction for overincrement from prior 'while' loop
while(i>=0)
{
putchar_unlocked(snum[i--]);
}
putchar_unlocked('\n');
} // end function: fastWrite
Just to be helpful with the time taken:
the following are good ways to speed up the I/O
#include <stdio.h>
void fastRead( size_t *a );
void fastWrite( size_t a );
inline void fastRead(size_t *a)
{
int c=0;
// note: 32 is space character
while (c<33) c=getchar_unlocked();
// initialize result value
*a=0;
// punctuation parens, etc are show stoppers
while (c>47 && c<58)
{
*a = (*a)*10 + (size_t)(c-48);
c=getchar_unlocked();
}
//printf( "%s, value: %lu\n", __func__, *a );
} // end function: fastRead
inline void fastWrite(size_t a)
{
char snum[20];
//printf( "%s, %lu\n", __func__, a );
int i=0;
do
{
// 48 is numeric character 0
snum[i++] = (char)((a%10)+(size_t)48);
a=a/10;
}while(a>0);
i=i-1; // correction for overincrement from prior 'while' loop
while(i>=0)
{
putchar_unlocked(snum[i--]);
}
putchar_unlocked('\n');
} // end function: fastWrite
and output characters via:
putchar_unlocked( char );
and always have a final, at end of each test case, the following line:
putchar_unlocked( '\n' );
to input a string of characters, call the following in a loop until a space or newline is encountered
char = getchar_unlocked()
and a final hint: most such problems are easily solved using size_t numeric values, which allows values to 4gig or more. (same as a unsigned long int)
For the current problem. as soon as a chain is calculated, save the chain, perhaps in an array, so you do not have to calculate it again.
Your could pre-calculate the first 'x' chains, say the first 10 for instance, to help with shortening the execution time.
This program is supposed to print an input string backwards. Every single time it happens, though, I get garbage characters such as \340 or of the like. Why is it doing that? Here's my code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char mattsentence[51];
mattsentence[50] = '\0';
gets(mattsentence);
char mask[sizeof(mattsentence)];
int i, j;
j = sizeof(mattsentence);
for (i = 0; i < sizeof(mask); i++)
{
j = j - 1;
mask[i] = mattsentence[j];
printf("%c", mask[i]);
}
printf("\n");
}
Your approach is wrong because you reverse the entire character array while it can be filled only partially. You should use standard C function strlen declared in header <string.h> that to determine the size of the entered string. Also to use gets is unsafe because you can overwrite memory beyond the character array. It now is excluded from the C Standard
Here is shown how the program can be written.
#include <stdio.h>
#include <string.h>
#define N 51
int main(void)
{
char mattsentence[N] = { '\0' };
char mask[N] = { '\0' };
fgets( mattsentence, sizeof( mattsentence ), stdin );
size_t n = strlen( mattsentence );
if ( n != 0 && mattsentence[n-1] == '\n' ) mattsentence[--n] = '\0';
for ( size_t i = 0; n != 0; i++ )
{
mask[i] = mattsentence[--n];
printf( "%c", mask[i] );
}
printf( "\n" );
return 0;
}
If to enter
Hello, Christiana S. F. Chamon
then the program output will be
nomahC .F .S anaitsirhC ,olleH
Take into account that to output a string in the reverse order there is no need to define a second character array.
If you want only to output the source string in the reverse order then the program can look like
#include <stdio.h>
#include <string.h>
#define N 51
int main(void)
{
char mattsentence[N] = { '\0' };
fgets( mattsentence, sizeof( mattsentence ), stdin );
size_t n = strlen( mattsentence );
if ( n != 0 && mattsentence[n-1] == '\n' ) mattsentence[n-1] = '\0';
while ( n != 0 )
{
printf( "%c", mattsentence[--n] );
}
printf( "\n" );
return 0;
}
sizeof() operator gives the size of the datatype. So, sizeof(mattsentence) will give you a value of 51. Then, sizeof(mask) will give you 51 again.
When you use that sizeof(mask) as for loop condition, you're basically going past the actual input values, thus pritning out garbage values.
What you want here is to use strlen() to find out the actual valid length of the entered string.
So, basically you need to take care of
Point 1: replace sizeof with strlen().
Point 2: Use of gets() is dangerous. Please use fgets() instead of gets().
Point 3: int main() should be int main(void). Put an expilicit return statement at the end of main(). Good Practice.
The modified code should look like
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
char mattsentence[51] = {0}; //always initalize local variables, here it's covering null termination , too.
fgets(mattsentence, 51, stdin); //fgets()
char mask[strlen(mattsentence) + 1]; // one more to store terminating '\0'
int i = 0, j = 0, k = 0;
j = strlen(mattsentence);
k = j;
for (i = 0; i < k; i++) // make use of k, don't call `strlen()` repeatedly
{
j = j - 1;
mask[i] = mattsentence[j];
printf("%c", mask[i]);
}
mask[i] = '\0'; // for proper string termination
printf("\n");
printf("%s\n", mask);
return 0; //added return statement
}
See changed code:
int main()
{
char mattsentence[51];
mattsentence[0] = '\0'; // initialization
gets(mattsentence);
char mask[strlen(mattsentence) + 1]; // +1 for string terminator '\0'
int i, j;
j = strlen(mattsentence);
for (i = 0; i < strlen(mattsentence); i++) // strlen of original string
{
j = j - 1;
mask[i] = mattsentence[j];
printf("%c", mask[i]);
}
mask[i] = '\0'; // for proper string termination
printf("\n");
printf("%s\n", mask);
}
There are several errors:
strlen() should be used to get length of string
for loop should be controlled according to input string, not output string
it is better to use fgets() instead of gets(): that way you can control how many character will be read from the input
Hey guy's last time I posted I was a bit sloppy. Hopefully this time it'll look a lot better . Thank you for your time if you decide to help me. I really need it. Anyways heres the question. I need to have wrap around for my Code and i heard you can do it with modulus but I am not sure i am doing it correctly because I do not get the right results.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
int main () {
char s[200]; //blank array//
int mess;
printf("Generations have wondered how the Ceasar Code works\n");
printf("Please choose a number to mess up (encode) the current file\n");
scanf("%d", &mess);
mess = mess % 26;
FILE *ptof = fopen("Rock.txt", "r");
char a[200];//fill array with characters from file//
int i=0;
while( (a[i++]=fgetc(ptof)) != EOF && i < 89) { //get character from file//
}
a[i] = '\0'; /* null-terminate the string */
i = 0;
do{
printf("%c",a[i++]);
} while (a[i] != '\0'); /* print until hit \0 */
int j = 0;
for (j = 0; j < 89; j++){
s[j] = a[j] + mess;
}
printf("%s\n", s);
fclose(ptof);
return 0;
}
s[j] = a[j] + mess needs a modulo operation as well
There's a lot of room for improvement here. Do you really want to map printable characters into (potentially) non-printable characters? Or do you merely want to do a ceaser shift on letters in the alphabet? Why the arbitrary limit of 90 characters of input? Using scanf is never a good idea (in 20 some years writing code, I have never used it since I left school). Passing the shift on stdin rather than as an argument makes it hard to use your program as a filter. For instance, it would be really nice if you could take a string and shift it by 4, then by 13, then by 9 and see that you get the original text back. (eg < file ceaser 4 | ceaser 13 | ceaser 9 | diff - file should report no diffs).
Here's a few ideas:
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
FILE *
xfopen( const char *path, const char *mode )
{
FILE *ifp = fopen( path, mode );
if( ifp == NULL ) {
perror( path );
exit( 1 );
}
return ifp;
}
int
main( int argc, char **argv )
{
int mess = argc > 1 ? strtol( argv[1], NULL, 10 ) % 26 : 13;
FILE *ptof = argc > 2 ? xfopen( argv[2], "r" ) : stdin;
int c;
while( ( c = fgetc( ptof )) != EOF ) {
if( isupper( c ))
c = 'A' + ( c - 'A' + mess ) % 26;
if( islower( c ))
c = 'a' + ( c - 'a' + mess ) % 26;
putchar( c );
}
return 0;
}