I got a almost good working program to count words from standard input.
The word what has to be count is a program argument.
The problem is that I use a white space to see a word but I also must count within th word itself.
Example: if my input is aa aaaa #EOF, and I want to count aa the result should be 4. My code result 2.
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <math.h>
int word_cnt(const char *s, char *argv[])
{
int cnt = 0;
while(*s != '\0')
{
while(isspace(*s))
++s;
if(*s != '\0')
{
if(strncmp(s, argv[1], strlen(argv[1])) == 0)
++cnt;
while(!isspace(*s) && *s != '\0')
++s;
}
}
return cnt;
}
int main(int argc, char *argv[])
{
char buf[1026] = {'\0'};
char *p="#EOF\n";
int tellen = 0;
if (argc != 2)
{
printf("Kan het programma niet uitvoeren, er is geen programma argument gevonden\n");
exit(0);
}
while((strcmp(buf, p) !=0))
{
fgets (buf, 1025, stdin);
tellen += word_cnt(buf, argv);
}
printf("%d", tellen);
return 0;
}
Where you have this:
if(strncmp(s, argv[1], strlen(argv[1])) == 0)
++cnt;
while(!isspace(*s) && *s != '\0')
++s;
Try this:
/* if it matches, count and skip over it */
while (strncmp(s, argv[1], strlen(argv[1])) == 0) {
++cnt;
s += strlen(argv[1]);
}
/* if it no longer matches, skip only one character */
++s;
int word_cnt(const char *s, char *argv[])
{
int cnt = 0;
int len = strlen(argv[1]);
while(*s)
{
if(strncmp(s, argv[1], len) == 0)
++cnt;
++s;
}
return cnt;
}
Try strncmp() in a loop.
/* UNTESTED */
unsigned wc(const char *input, const char *word) {
unsigned count = 0;
while (*input) {
if (strncmp(input, word, strlen(word)) == 0) count++;
input++;
}
return count;
}
Related
I have a task to get a char array from one text file and put this text in another file. I must use two functions. They must look like this:
int writeText(FILE *wp, char text[])
int readText(FILE *wp, char text[], int max)
I must use my own strlen function (_strlen).
In the function readText they said that I must remember to put '\0' at the end and check that I don't put too many signs in the array (more than the array size).
This is my code
#include <stdio.h>
#include <stdlib.h>
int _strlen (char *text)
{
int i;
for (i = 0; text[i] != '\0'; ++i);
return i;
}
int writeText(FILE *wp, char text[])
{
int len = _strlen(text);
for (int i = 0; i < len; i++) {
fputc (text[i], wp);
}
return _strlen(text);
}
int readText(FILE *wp, char text[], int max)
{
int length = _strlen(text);
int c;
int i = 0;
max = 10000;
while( (c = fgetc(wp)) != EOF && i <= max )
{
fputc (text[i], wp);
i++;
}
if (i > max)
{
printf("This array is too big.");
}
text[i] = '\0';
return _strlen(text);
}
int main (int argc, char *argv[])
{
if (argc != 3) {
printf("You should run program in this way:\n");
printf("%s file_source file_result\n",argv[0]);
exit(1);
}
int sum;
const char source[] = "source.txt"; // plik wejściowy
const char result[] = "result.txt"; // plik wyjściowy
FILE *wz, *wc; // wskaźnik do pliku
if( (wz= fopen(source,"r")) == NULL) {
printf("Open error %s\n", source);
exit(1);
}
if( (wc= fopen(result,"w")) == NULL) {
printf("Open error %s\n",result);
exit(2);
}
char tab1[1000];
readText(wz, tab1, 1000);
writeText(wc, tab1);
int fclose(FILE *wp);
int fclose(FILE *wc);
}
After I run this program I get something like that:
p\E2\B4&\FF
And I dont know why.
fputc writes a char to a specified stream. You want to read a char and put that char in a char array. Remove fputc and just assign the char from fgetc to the array at the specific index. There is no need to reassign the max variable. As you had it, it would write over memory not assigned to the array if the input file was larger than your array size. You also want the loop to terminate at two less than max if you want to add a null terminating character at max - 1 or the last index in the allocated array.
int readText(FILE *wp, char text[], int max)
{
int c, i = 0;
while((c = fgetc(wp)) != EOF && i < max - 1 )
{
text[i] = c;
++i;
}
text[i] = '\0';
return _strlen(text);
}
I am supposed to write a program to extract Web addresses starting with www. and ending with .edu. The program displays Web address contained in the input entered by the user. If the input does not contain a web address that starts with www. and ends with .edu, the program should display a message that indicates such a web address cannot be found.
Input: http://www.usf.edu/admission
Output: www.usf.edu
Input: https://www.facebook.com/
Output: Web address starting with www. and ending with .edu not found
However when my program runs, it is not displaying the correct output. I don't have any compiler errors or warnings so I'm not sure where the issue could be.
// This program extracts the text from the website URL
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define STR_LEN 1000
void read_line(char *str, int n);
void pass_check(char *str);
void extract(char *s1, char *s2);
int main(void)
{
char instr[STR_LEN + 1];
char outstr[STR_LEN + 1];
printf("Please enter a URL: ");
read_line(instr, STR_LEN);
extract(instr, outstr);
puts(outstr);
pass_check(outstr);
return 0;
}
void extract(char *s1, char *s2) {
char *p, *q;
q = s2;
for (p = s1 + 7; *p != 0; p++) {
if (*p == '/')
break;
else {
*q = *p;
q++;
}
}
*q = '\0';
*p = '\0';
}
void read_line(char *str, int n) {
int ch;
int i = 0;
while ((ch = getchar()) != '\n') {
if (i < n) {
*str++ = ch;
i++;
}
}
*str = '\0';
}
void pass_check(char *str) {
const char *fref = "www";
const char *lref = "edu";
int len = strlen(str);
printf("%d", len);
char *l = &str[len - 3];
char f[STR_LEN + 1];
strncpy(f, str, 3);
if ((strcmp(f, fref) == 0) && strcmp(l, lref) == 0) {
printf("Output: ");
puts(str);
printf("\n");
} else
printf("Please only insert a .edu URL.");
}
The function strncpy() does not do what you think it does: strncpy(f, str, 3); will not append a null byte to f, so strcmp(f, fref); will actually have undefined behavior as f is uninitialized beyond the first 3 bytes.
Do not use this function, learn why from these blogs:
https://randomascii.wordpress.com/2013/04/03/stop-using-strncpy-already/
https://blog.liw.fi/posts/strncpy/
Also note that your readline() function will run an infinite loop is the file is empty or not terminated by a newline.
Here is a corrected version:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define STR_LEN 1000
void read_line(char *str, size_t n);
int extract(const char *str, char *dest);
int main(void) {
char instr[STR_LEN + 1];
char outstr[STR_LEN + 1];
printf("Please enter a URL: ");
read_line(instr, sizeof(instr));
if (extract(instr, outstr)) {
puts(outstr);
} else {
printf("Web address starting with www. and ending with .edu not found\n");
}
return 0;
}
int read_line(char *str, size size) {
int ch;
size_t i = 0;
while ((ch = getchar()) != EOF && c != '\n') {
if (i + 1 < size) {
str[i++] = ch;
}
}
str[i] = '\0';
return (ch == EOF && i == 0) ? EOF : i;
}
int extact(const char *str, char *dest) {
const char *p;
*dest = '\0';
for (;;) {
if ((p = strstr(str, "https://www.")) != NULL) {
p += 8; // skip the https:// prefix
} else
if ((p = strstr(str, "http://www.")) != NULL) {
p += 7; // skip the http:// prefix
} else {
break;
}
// URL starts with www.
size_t len = strcspn(p, "/ \n"); // compute length of website name
if (len > 8 && !memcmp(p + len - 4, ".edu", 4)) {
// copy website name, assuming dest is at least as large as str
strncat(dest, p, len);
return 1;
}
str = p + len;
}
return 0;
}
I'm able to reverse the array fine, but I can't get the program to terminate when I do CTRL+D(EOF) in terminal.
The only way I can get the program to terminate is if the very first thing I do after compiling is doing CTRL+D. But if I type in one string, then CTRL+D will not work after that.
I'm not quite sure where my error is.
#include <stdio.h>
#define MAXLINE 1000 // Maximum input.
// ----------------- reverseLine -----------------
// This method reads in chars to be put into an
// array to make a string. EOF and \n are the
// delimiters on the chars, then \0 is the
// delimiter for the string itself. Then the
// array is swapped in place to give the reverse
// of the string.
//------------------------------------------------
int reverseLine(char s[], int lim)
{
int c, i, newL;
// c is the individual chars, and i is for indices of the array.
for (i = 0; i < lim - 1 && (c=getchar()) != EOF && c != '\n'; ++i)
{
s[i] = c;
}
if (c == '\n') // This lets me know if the text ended in a new line.
{
newL = 1;
}
// REVERSE
int toSwap;
int end = i-1;
int begin = 0;
while(begin <= end) // Swap the array in place starting from both ends.
{
toSwap = s[begin];
s[begin] = s[end];
s[end] = toSwap;
--end;
++begin;
}
if (newL == 1) // Add the new line if it's there.
{
s[i] = '\n';
++i;
}
s[i] = '\0'; // Terminate the string.
return i;
}
int main()
{
int len;
char line[MAXLINE];
while ((len = reverseLine(line, MAXLINE)) > 0) // If len is zero, then there is no line to recored.
{
printf("%s", line);
}
return 0;
}
The only thing I can think of is the while loop in main checks if len > 0, so if I type EOF, maybe it can't make a valid comparison? But that wouldn't make sense as to why it works when that's the first and only thing I type.
Your program will never read the EOF because of this condition:
(c=getchar()) != EOF && c != '\n';
As soon as c is equal to '\n' the loop terminates and all the following characters are ignored. I think you should separate input from line reversing and make the usual checks on the reverse function parameters.
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define SIZE_MAX (256U)
static bool linereverse(char *line);
static bool deletenewline(char *s);
int main(void)
{
char buff[SIZE_MAX];
bool success;
(void) fputs("Enter a string: ", stdout);
if( NULL == fgets(buff,(size_t) SIZE_MAX, stdin))
{
(void) fputs("Error: invalid input!\n",stderr);
return EXIT_FAILURE;
}
success = deletenewline(buff);
if(false == success)
{
(void) fputs("Error: cannot remove newline\n",stderr);
return EXIT_FAILURE;
}
success = linereverse(buff);
if(false == success)
{
(void) fputs("Error: cannot reverse the line");
return EXIT_FAILURE;
}
(void) fputs("The line reversed is: ", stdout);
(void) fputs(buff, stdout);
(void) puchar('\n');
return EXIT_SUCCESS;
}
static bool linereverse(char *line)
{
size_t i;
size_t j;
char tmp;
if(NULL == line)
{
return false;
}
i = 0;
j = strlen(line) - 1;
while(i < j)
{
tmp = line[i];
line[i] = line[j];
line[j] tmp;
++i;
--j;
}
return true;
}
static bool deletenewline(char *s)
{
char *p;
if(NULL == s)
{
return false;
}
p = strrchr(s,'\n');
if(NULL != p)
{
*p = '\0';
}
return true;
}
I want to input a multiple-line string using:
fgets(str,100,stdin)
and then output the same string.
For example:
Input:
my name is sandy
i am learning C
and the output should be:
my name is sandy
i am learning C
#include <stdio.h>
#include <string.h>
char *mfgets(char * restrict s, int n, FILE * restrict stream){
int ch, i=0;
if(n<1)return NULL;
if(n==1){
*s = '\0';
return s;
}
while(EOF!=(ch=fgetc(stream))){
s[i++] = ch;
if(i == n - 1) break;
if(ch == '\n'){
char next = fgetc(stream);
if(next == '\n')
break;
else
ungetc(next, stream);
}
}
s[i] = '\0';
return i == 0 ? NULL : s;
}
int main(int argc, char *argv[]){
char str[100];
printf("input (only newline is end)\n");
mfgets(str, 100, stdin);
printf("%s", str);
return 0;
}
Just a quick one: in C I have a buffer full of data like below:
char buffer[255]="CODE=12345-MODE-12453-CODE1-12355"
My question is how to search through this. For example for the CODE=12345, section bear in mind that the numbers change, so I would like to search like this CODE=***** using wildcard or preset amount of spaces after the CODE= part.
This method wont compile last one left to try
#include <stdio.h>
#include <string.h>
#include <windows.h>
int main ()
{
char buf[255]="CODE=12345-MODE-12453-CODE1-12355";
#define TRIMSPACES(p) while(*p != '\0' && isspace((unsigned char)*p) != 0) ++p
#define NSTRIP(p, n) p += n
#define STRIP(p) ++p
char* getcode(const char *input)
{
char *p = (char*) input, *buf, *pbuf;
if((buf = malloc(256)) == NULL)
return NULL;
pbuf = buf;
while(*p != '\0') {
if(strncmp(p, "CODE", 3) == 0) {
NSTRIP(p, 4); //remove 'code'
TRIMSPACES(p);//trim white-space after 'code'
if(*p != '=')
return NULL;
STRIP(p); // remove '='
TRIMSPACES(p); //trim white-spaces after '='
/* copy the value until found a '-'
note: you must be control the size of it,
for avoid overflow. we allocated size, that's 256
or do subsequent calls to realloc()
*/
while(*p != '\0' && *p != '-')
*pbuf ++ = *p++;
// break;
}
p ++;
}
//put 0-terminator.
*pbuf ++ = '\0';
return buf;
}
//
}
You could use the sscanf() function:
int number;
sscanf(buffer, "CODE = %i", &number);
for that to work well your buffer has to be null terminated.
Another way to do it instead of sscanf():
char *input, *code;
input = strstr(buf, "CODE");
if(input == NULL) {
printf("Not found CODE=\n");
return -1;
}
code = strtok(strdup(input), "=");
if(code != NULL) {
code = strtok(NULL, "-");
printf("%s\n", code); // code = atoi(code);
} else {
//not found '='
}
Or more robust way.. a bit more complex:
#define TRIMSPACES(p) while(*p != '\0' && isspace((unsigned char)*p) != 0) ++p
#define NSTRIP(p, n) p += n
#define STRIP(p) ++p
char* getcode(const char *input, size_t limit)
{
char *p = (char*) input, *buf, *pbuf;
size_t i = 0;
while(*p != '\0') {
if(strncmp(p, "CODE", 3) == 0) {
NSTRIP(p, 4); //remove 'code'
TRIMSPACES(p);//trim all white-spaces after 'code'
/* check we have a '=' after CODE (without spaces).
if there is not, returns NULL
*/
if(*p != '=')
return NULL;
/* ok. We have.. now we don't need of it
just remove it from we output string.
*/
STRIP(p);
/* remove again all white-spaces after '=' */
TRIMSPACES(p);
/* the rest of string is not valid,
because are white-spaces values.
*/
if(*p == '\0')
return NULL;
/* allocate space for store the value
between code= and -.
this limit is set into second parameter.
*/
if((buf = malloc(limit)) == NULL)
return NULL;
/* copy the value until found a '-'
note: you must be control the size of it,
for don't overflow. we allocated 256 bytes.
if the string is greater it, do implementation with
subjecents call to realloc()
*/
pbuf = buf;
while(*p != '\0' && *p != '-' && i < limit) {
*pbuf ++ = *p++;
i ++;
}
*pbuf ++ = '\0';
return buf;
}
p ++;
}
return NULL;
}
And then:
char buf[255] = "foo baa CODE = 12345-MODE-12453-CODE-12355";
char *code = getcode(buf,256);
if(code != NULL) {
printf("code = %s\n", code);
free(code);
} else {
printf("Not found code.\n");
}
output:
code = 12345
Check out this online.
if you want to don't differentiate case, you can use the strncasecmp() that's POSIX function.
Assuming the CODE= part always comes at the beginning of the string, it's pretty easy:
sscanf(buffer, "CODE = %d", &number);
...but you want buffer to be char[255], not unsigned long.
Edit: If the CODE= part isn't necessarily at the beginning of the string, you can use strstr to find CODE in the buffer, do your sscanf starting from that point, then look immediately following that:
int codes[256];
char *pos = buffer;
size_t current = 0;
while ((pos=strstr(pos, "CODE")) != NULL) {
if (sscanf(pos, "CODE = %d", codes+current))
++current;
pos += 4;
}
Edit2:
For example, you'd use this something like this:
#include <stdio.h>
#include <string.h>
#include <windows.h>
int main ()
{
// This is full of other junk as well
char buffer[255]="CODE=12345 MODE-12453 CODE=12355" ;
int i;
int codes[256];
char *pos = buffer;
size_t current = 0;
while ((pos=strstr(pos, "CODE")) != NULL) {
if (sscanf(pos, "CODE = %d", codes+current))
++current;
pos += 4;
}
for (i=0; i<current; i++)
printf("%d\n", codes[i]);
return 0;
}
For me, this produces the following output:
12345
12355
...correctly reading the two "CODE=xxx" sections, but skipings over the "MODE=yyy" section.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *getcode(const char *str, const char *pattern){
//pattern: char is match, space is skip, * is collect
static const char *p=NULL;
char *retbuf, *pat;
int i, match, skip, patlen;
if(str != NULL) p=str;
if(p==NULL || *p=='\0') return NULL;
if(NULL==(retbuf=(char*)malloc((strlen(p)+1)*sizeof(char))))
return NULL;
pat = (char*)pattern;
patlen = strlen(pat);
i = match = skip = 0;
while(*p){
if(isspace(*p)){
++p;
++skip;
continue;
}
if(*pat){
if(*p == *pat){
++match;
++p;
++pat;
} else if(*pat == '*'){
++match;
retbuf[i++]=*p++;
++pat;
} else {
if(match){//reset
pat=(char*)pattern;
p -= match + skip -1;
i = match = skip = 0;
} else //next
++p;
}
} else {
break;
}
}
if(i){//has match
retbuf[i++]='\0';
retbuf=realloc(retbuf, i);
return retbuf;
} else {
free(retbuf);
return NULL;
}
}
int main (){
char *code;
code=getcode("CODE=12345-MODE-12453-CODE1-12355", "CODE=*****");
printf("\"%s\"\n",code);//"12345"
free(code);
code=getcode(" CODE = 12345-MODE-12453-CODE1-12355", "CODE=*****");
printf("\"%s\"\n",code);//"12345"
free(code);
code=getcode("CODE-12345-MODE-12453-CODE1-12355", "CODE=*****");
if(code==NULL)printf("not match\n");//not match
code=getcode("CODE=12345-MODE-12453-CODE=12355", "CODE=*****");
printf("\"%s\"\n",code);//"12345"
free(code);
code=getcode(NULL, "CODE=*****");
printf("\"%s\"\n",code);//"12355"
free(code);
code=getcode("CODE=12345-MODE-12453-CODE1-12355", "CODE=*****");
printf("\"%s\"\n",code);//"12345"
free(code);
code=getcode(NULL, "CODE1-*****");
printf("\"%s\"\n",code);//"12355"
free(code);
return 0;
}