String replace in C? - c

Write a program that takes nouns and
forms their plurals on the basis of
these rules: a. If noun ends in “y”
remove the “y” and add “ies” b. If
noun ends in “s” , “ch”, or “sh”, add
“es” c. In all other cases, just add
“s” Print each noun and its plural.
Try the following data: chair
dairy boss circus fly dog
church clue dish
This is what I've got so far but it just isn't quite functioning like it's supposed to:
#include<stdlib.h>
#include <Windows.h>
#include <stdio.h>
#include <string.h>
#define SIZE 8
char *replace_str(char *str, char *orig, char *rep)
{
static char buffer[4096];
char *p;
if(!(p = strstr(str, orig)))
return str;
strncpy(buffer, str, p-str);
buffer[p-str] = '\0';
sprintf(buffer+(p-str), "%s%s", rep, p+strlen(orig));
return buffer;
}
int main(void)
{
char plural[SIZE];
printf("Enter a noun: ");
scanf("%c",&plural);
bool noreplace = false;
puts(replace_str(plural, "s","es"));
puts(replace_str(plural, "sh","es"));
puts(replace_str(plural, "ch","es"));
puts(replace_str(plural, "y", "ies"));
if(noreplace) {
puts(replace_str(plural, "","s"));
}
system("pause");
return 0;
}
I haven't taken a C class in a while can anyone help me out?
Thanks.

For a start, scanf("%c") gets a single character, not a string. You should use fgets for that, along the lines of:
fgets (buffer, SIZE, stdin);
// Remove newline if there.
size_t sz = strlen(buffer);
if (sz > 0 && buffer[sz-1] == '\n') buffer[sz-1] = '\0';
Once you've fixed that, we can turn to the function which pluralises the words along with a decent test harness. Make sure you keep your own main (with a fixed input method) since there's a couple of things in this harness which will probably make your educator suspect it's not your code. I'm just including it for our testing purposes here.
Start with something like:
#include <stdio.h>
#include <string.h>
char *pluralise(char *str) {
static char buffer[4096];
strcpy (buffer, str);
return buffer;
}
int main(void) {
char *test[] = {
"chair", "dairy", "boss", "circus", "fly",
"dog", "church", "clue", "dish"
};
for (size_t i = 0; i < sizeof(test)/sizeof(*test); i++)
printf ("%-8s -> %s\n", test[i], pluralise(test[i]));
return 0;
}
This basically just gives you back exactly what you passed in but it's a good start:
chair -> chair
dairy -> dairy
boss -> boss
circus -> circus
fly -> fly
dog -> dog
church -> church
clue -> clue
dish -> dish
The next step is to understand how to detect a specific ending and how to copy and modify the string to suit. The string is an array of characters of the form:
0 1 2 3 4 5
+---+---+---+---+---+---+
| c | h | a | i | r | $ |
+---+---+---+---+---+---+
where $ represents the null terminator \0. The numbers above give the offset from the start or the index that you can use to get a character from a particular position in that array. So str[3] will give you i.
Using that and the length of the string (strlen(str) will give you 5), you can check specific characters. You can also copy the characters to your target buffer and use a similar method to modify the end.
Like any good drug pusher, I'm going to give you the first hit for free :-)
char *pluralise(char *str) {
static char buffer[4096]; // Risky, see below.
size_t sz = strlen(str); // Get length.
if (sz >= 1 && str[sz-1] == 'y') { // Ends with 'y'?
strcpy(buffer, str); // Yes, copy whole buffer,
strcpy(&(buffer[sz-1]), "ies"); // overwrite final bit,
return buffer; // and return it.
}
strcpy(buffer, str); // If no rules matched,
strcat(buffer, "s"); // just add "s",
return buffer; // and return it.
}
Of particular interest there is the sequence:
strcpy(buffer, str);
strcpy(&(buffer[sz-1]), "ies");
The first line makes an exact copy of the string like:
0 1 2 3 4 5
+---+---+---+---+---+---+
| d | a | i | r | y | $ |
+---+---+---+---+---+---+
The second line copies the "ies" string into the memory location of buffer[sz-1]. Since sz is 5, that would be offset 4, resulting in the following change:
0 1 2 3 4 5
+---+---+---+---+---+---+
| d | a | i | r | y | $ |
+---+---+---+---+---+---+---+---+
| i | e | s | $ |
+---+---+---+---+
so that you end up with dairies.
From that, you should be able to use the same methods to detect the other string endings, and do similar copy/modify operations to correctly pluralise the strings.
Keep in mind that this is basic code meant to illustrate the concept, not necessarily hardened code that I would use in a production environment. For example, the declaration static char buffer[4096] has at least two problems that will occur under certain circumstances:
If your words are longer than about 4K in length, you'll get buffer overflow. However, even German, with its penchant for stringing basic words together in long sequences(a), doesn't have this problem :-) Still, it's something that should be catered for, if only to handle "invalid" input data.
Being static, the buffer will be shared amongst all threads calling this function if used in a multi-threaded environment. That's unlikely to end well as threads may corrupt the data of each other.
A relatively easy fix would be for the caller to also provide a buffer for the result, at least long enough to handle the largest possible expansion of a word to its plural form. But I've left that as a separate exercise since it's not really relevant to the question.
(a) Such as Donaudampfschiffahrtselektrizitätenhauptbetriebswerkbauunterbeamtengesellschaft :-)

You are reading a word as:
scanf("%c",&plural);
which is incorrect as it only reads one character.
Change it to:
scanf("%s",plural);
or even better use fgets as:
fgets (plural,SIZE, stdin);
But note that fgets might add a newline at the end of the string. If it does you need to remove it before you do the replacement as your replacement depends on the last character in the word.
Also your replacement part is incorrect. You are replacing any s with es (same with other replacements). You need to replace only the last s.

puts(replace_str(plural, "ch","es"));
Consider the input: church
strstr(3) will find the first ch, not the last ch. Ooops.
Furthermore, once you modify replace_str() to find the the last ch, you're still ripping it off and not putting it back on: chures. (Assuming your replace_str() functions as I think it does; that's some hairy code. :) So add the ch back on:
puts(replace_str(plural, "ch","ches"));

first of all u need to find last position of occurance and then call replace_str() function
and secondly scanf("%s",&plural);or use fgets()

Maybe this might help you:
str_replace
it's nicely done!

Related

copying an substring to string

i'm trying to get a 2 strings from the user and the second one will be the "needle" to copy to the first string
for example:
string 1 (user input): eight height freight
string 2 (user input): eight
output: EIGHT hEIGHT frEIGHT
for example i want to print: toDAY is a good DAY
having trouble copying multiple needles in stack
i have tried using while (*str) {rest of the function with str++}
i would love some explanation
#define _CRT_SECURE_NO_WARNINGS
#define N 101
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <conio.h>
void replaceSubstring(char* str, char* substr);
void main() {
int flag = 1;
char str[N], substr[N];
//char* str_ptr = &str, * substr_ptr = &substr; //creating pointer for the sake of while
while (flag) {
printf("\nEnter main text: ");
gets_s(str,N);
if (!str)
flag = 0;
printf("\nEnter sub-text: ");
gets_s(substr,N);
if (!str)
flag = 0;
replaceSubstring(str, substr);
printf("%s",str);
}
printf("\nExited. (press any key to exit)");
}
void replaceSubstring(char* str, char* substr) {
int lensbstr;
str = strstr(str, substr);
_strupr(substr); //cnvrt to UPPERCASE
lensbstr = strlen(substr); //length of the mutual string
if (str)
strncpy(str, substr, lensbstr);
}
This looks like a programming exercise, so I’m not going to just give you the answer. However, I’ll give you a few hints.
Two big problems:
You don’t have a loop that would replace the second and later instances.
You are upper-casing the substring... not a copy of the substring. A second pass through replaceSubstring would only match the upper-case version of the substring.
A couple of small problems / style comments:
str is an array, so its value is always non-zero, so “if(!str)” is never true.
strncpy is almost never the right answer. It will work here, but you shouldn’t get in the habit of using it. Its behavior is subtle and is rarely what you want. Here it would be faster and more obvious to use memcpy.
You are upper-casing the substring and measuring its length even if you didn’t find it and so won’t need those results.
Although using int for flags works and is the traditional way, newer versions of the language have stdbool.h, the “bool” type, and the “true” and “false” constants. Using those is almost always better.
You appear to intend to stop when the user enters an empty string for the first string. So why do you ask for the second string in that case? It seems like you want an infinite loop and a “break” in the middle.

count the total no. of keywords in the file

I want to count the total no. of keywords in the file but the code counts those keywords that are used to declare the variable.
void main()
{
//2d array used to store the keywords but few of them are used.
char key[32][12]={"int","char","while","for","if","else"};
//cnt is used to count the occurrence of the keyword in the file.
int cnt=0,i;
//used to store the string that is read line by line.
char ch[100];
FILE *fp=fopen("key.c","r");
//to check whether file exists or not
if(fp=='\0')
{
printf("file not found..\n");
exit(0);
}
//to extract the word till it don't reach the end of file
while((fscanf(fp,"%s",ch))!=EOF)
{
//compare the keyword with the word present in the file.
for(i=0;i<32;i++)
{
// compare the keyword with the string in ch.
if(strcmp(key[i],ch)==0) {
//just to check which keyword is printed.
printf("\nkeyword is : %s",ch);
cnt++;
}
}
}
printf("\n Total no. of keywords are : %d", cnt);
fclose(fp);
}
Expected output should be:
Total no. of keywords are : 7
Actual output is coming :
Total no. of keywords are : 3
fscanf(fp,"%s",ch) will match a sequence of non-whitespace characters (see cpp reference), so in your case for, while and if won't be matched as single words - because there's no space after them.
In my opinion, but diverting a little from your intention, you had better to use flex(1) for that purpose, as it will scan the file more efficiently than comparing each sequence with the set of words you may have. This approach will require more processing, as several keywords can be in the same line, and it only filters which lines have keywords on them.
Also, using flex(1) will give you a more efficient C source code, a sample input for flex(1) would be:
%{
unsigned long count = 0;
%}
%%
int |
char |
unsigned |
signed |
static |
auto |
do |
while |
if |
else |
/* ... add more keywords as you want here */
return |
break |
continue |
volatile { printf("keyword is = %s\n", yytext);
count++;
}
\n |
. ;
%%
int yywrap()
{
return 1;
}
int main()
{
yylex();
printf("count = %lu\n", count);
}
The efficiency comes basically from the fact that flex(1) uses a special algorithm that gets the right match with only scanning once the source file (one decision per char, all the patterns are scanned in parallel). The problem in your code comes from the fact that %s format has a special interpretation of what it considers is a word, different as the one defined by the C language (for scanf() a word si something surrounded by spaces, where spaces means \n, \t or only --- it will match as a word something like while(a==b) if you don't put spaces around your keywords). Also, If you need to compare each input pattern with each of the words your algorithm will end doing N passes through each input file character (with each letter meaning N = nw * awl (being N the number of times you compare each character and nw the number of words, awl the average of the list of word lengths in your set) By the way, keywords should not be recognised inside comments, or string literals, It is easy to adapt the code you see above to reject those and do a right scanning. For example, the next flex file will do this:
%{
unsigned long count = 0;
%}
%x COMM1
%x COMM2
%x STRLIT
%x CHRLIT
%%
int |
char |
unsigned |
signed |
static |
auto |
do |
while |
if |
else |
/* ... */
return |
break |
continue |
volatile { printf("kw is %s\n", yytext);
count++;
}
[a-zA-Z_][a-zA-Z0-9_]* |
^[\ \t]*#.* |
"/*"([^*]|\*[^/])*"*/" |
"//".* |
\"([^"\n]|\\")*\" |
\'([^'\n]|\\')*\' |
. |
\n ;
%%
int yywrap()
{
return 1;
}
int main()
{
yylex();
printf("count = %lu\n", count);
}
It allows different regular expressions to be recognised as language tokens, so provision is given to match also C language constructs like identifiers ([a-zA-Z_][a-zA-Z0-9_]*), preprocessor directives (^[\ \t]*#.*), old style C comments ("/*"([^*]|\*[^/])*"*/"), new C++ style comments ("//".*), string literals (\"([^"\n]|\\")*\"), character literals (\'([^'\n]|\\')*\'), where keywords cannot be identified as such.
Flex(1) is worth learning, as it simplifies a lot the input of structured data into a program. I suggest you to study it.
note
you had better to write if (fp == NULL), or even if (!fp)... (You are not doing anything incorrect in your statement if (fp == '\0'), but as \0 is the char representation of the nul character, it's somewhat inconvenient, strange or imprecise to compare a pointer value with a character literal, and suggests you are interpreting the FILE * not as a pointer, but more as an integer (or char) value.) But I repeat, it's something perfectly legal in C language.
note 2
The flex sample code posted above doesn't consider the possibility of running out of buffer space due to input very long tokens (like several line comments overflowing internal buffer space) This is done on purpose, to simplify description and to make the code simpler. Of course, in a professional scanner, all of these must be acquainted for.

Issue With Comparing Strings In C

I'm trying to compare a string with another string and if they match I want the text "That is correct" to output but I can't seem to get it working.
Here is the code:
int main ()
{
char * password = "Torroc";
char * userInput;
printf("Please enter your password: ");
scanf("%s", userInput);
if (strcmp(password, userInput) == 0) {
printf("That is correct!");
}
}
In your code, userInput pointer does not have provision to hold the string that you are about to pass using the scanf call. You need to allocate space for the cstring userInput in your stack, before you try to save/assign any string to it. So...
You need to change the following code:
char * userInput;
to:
char userInput[200];
Here, 200 is just an arbitrary value. In your case, please select the max. length of the string + 1 for the (\0).
When you enter characters you need to store the characters somewhere.
char* userInput;
is an uninitialized pointer.
So first you declare an array for your input
char userInput[128];
Now when reading from the keyboard you need to make sure the user does not enter more characters than 127 + one for \0 because it would overwrite the stack so best way to read from the keyboard is to use fgets, it also good to check the return value, if the user simply pressed ENTER without writing anything fgets returns NULL.
if (fgets(userInput, sizeof(userInput), stdin) != NULL) {
Now you have the string that the user entered plus the end of line character. To remove it you can do something like
char* p = strchr(userInput,'\n');
if ( p != NULL ) *p = '\0';
Now you can compare the strings
if (strcmp(password, userInput) == 0) {
puts("That is correct!");
}
When you think about "a string" in C, you should see it as an array of char's.
Let me use the identifier s instead of userInput for brevity:
0 1 2 3 4 5 9
+---+---+---+---+---+---+-- --+---+
s -> | p | i | p | p | o | \0| ... | |
+---+---+---+---+---+---+-- --+---+
is what
char s[10] = "pippo";
would create.
In other words, it's a block of memory where the first 6 bytes have been initialized as shown. There is no s variable anywhere.
Instead, declaring a char * like in
char *s;
would create a variable that can hold a pointer to char:
+------------+
s| 0xCF024408 | <-- represent an address
+------------+
If you think this way, you notice immediately that doing:
scanf("%s",s);
only make sense in the first case, where there is (hopefully) enough memory to hold the string.
In the second case, the variable s points to some random address and you will end up writing something into an unknown memory area.
For completeness, in cases like:
char *s = "pippo";
you have the following situation in memory:
0 1 2 3 4 5
+---+---+---+---+---+---+ Somewhere in the
0x0B320080 | p | i | p | p | o | \0| <-- readonly portion
+---+---+---+---+---+---+ of memory
+------------+ a variable pointing
s| 0x0B320080 | <-- to the address where
+------------+ the string is
You can make s pointing somewhere else but you can't change the content of the string pointed by s.

C working with strings and SEGFAULT

Hello and sorry for my bad english.
I am starting with C language, but I didnt get pointers well...
I searched for similar topics, but I didnt get it from them, so I created own topic.
I have got main function, where I call function newSpeak.
There is my code of newSpeak, but there isnt everything...
char * newSpeak ( const char * text, const char * (*replace)[2] )
{
int i;
char * alpha;
for(i=0;i<4;i++)
{
alpha=strstr(text, replace[0][4]);
if(alpha[0])
strncpy (alpha,replace[1][0],10);
}
return 0;
}
Thanks for answering
EDIT: I have found source of the problem.
It works, when I dont use for cycle and run it once. But it doesnt work even when the condition in for cycle is i<1, which should make it run only once...This is strange for me...
alpha=strstr(text, replace[0][4]);
if(alpha[0])
// looks crashy
man strstr:
These functions return a pointer to the beginning of the substring,
or NULL if the substring is not found.
EDIT:
It is difficult to tell what you are trying to do, but below find an arbitrary adaptation of your code. If it were my program, I would write it very differently. I mention that because I do not want someone to read this and think it is the way it should be done.
#include <stdio.h>
#include <string.h>
void newSpeak (char *text, const char *replace[4][2])
{
int i, j;
char *alpha;
for (i = 0; i < 4; i++) {
if (alpha = strstr(text, replace[i][0])) {
for (j = 0; alpha[j] && replace[i][1][j]; j++)
alpha[j] = replace[i][1][j];
}
}
}
int main ()
{
char buf[100] = "abc";
const char *replace[4][2] = {
{ "a", "e" },
{ "b", "f" },
{ "c", "g" },
{ "d", "h" },
};
newSpeak(buf, replace);
puts(buf);
}
The line
strncpy (alpha,replace[1][0],10);
should have generated a compiler warning (and NEVER ignore compiler warnings). The function prototype is
char *strncpy( char *dest, char *source, int n);
But you are passing it replace[1][0] which is a character. It might work if you passed
strncpy( alpha, &replace[1][0], 10);
Even then I still worry. It could be that since alpha is pointing to a block of memory in the block pointed to by text which is a const char*, that you are not allowed to modify that memory.
EDIT I think my first point is wrong - I misread your prototype. But I'm pretty sure the second point is valid (and probably the reason for the segfault).
second edit
It is possible that text does not have sufficient memory allocated to have 10 characters copied into it from replace. Realize that the thing you are matching against (replace[0][4]) and the thing you are copying (replace[1][0]]) are not the same thing; also, you are looping over i but not using that value ... makes me wonder if there is a typo (I am not clairvoyant and cannot figure out what you wanted to change from loop to loop).
You need to check the size of the thing you are copying into:
strncpy(alpha, replace[1][0], (strlen(alpha)<10)?strlen(alpha):10);
would ensure you are copying no more than 10 characters, and no more than there's space in alpha.
This is "on top of" everything else already pointed out (of which using if (alpha!=NULL) instead of if(alpha[0]) is a big one.)
EDIT 3 - I think I figured out the majority of the problems with your code now... see http://codepad.org/YK5VyGAn for a small "working" sample.
Issues with your code included:
You declare text as const char*, then proceed to modify it
You declare replace as const char* (*replace)[2], then address element replace[0][4] (4 > 2...)
You assign the return value of strstr to alpha; this could be NULL (no match), yet you test for alpha[0] (which will fail if alpha == NULL).
When you copied the replacement string, you copied "up to 10 characters" - regardless of whether (a) the target string could accommodate this, and (b) the source string had this many characters. The result might be that you copy the full source string (including the terminating '\0') so that you will not find another match afterwards (you have "deleted" the rest of the string). And then you will run into the "strstr returns NULL" error...
Not sure (without seeing your input string or "replace" strings) which of these actually caused your code to fail - I have written a small program that addresses all of these mistakes. You can find it at http://codepad.org/4jSOnmPy - reproduced here:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MIN(a,b) (a>b)?(b):(a)
char * newSpeak (const char *text, const char *(*replace)[5] ){
int ii=0, n;
char *alpha, *beta;
printf("length of input string is %d\n", strlen(text));
beta = malloc(strlen(text)+1);
printf("allocated %d bytes\n", strlen(text)+1);
fflush(stdout);
strcpy(beta, text);
printf("copy OK: beta now %s\n", beta);
fflush(stdout);
for(ii = 0; ii < 4; ii++) {
// alpha=strstr(beta, replace[0][0]);
alpha=strstr(beta, "a");
printf("alpha is '%s'\n", alpha);
fflush(stdout);
if(alpha!=NULL) {
char *rs;
rs = replace[1][ii];
printf("ii = %d; alpha now: '%s'\n", ii, alpha);
fflush(stdout);
n = MIN(strlen(alpha), strlen(rs));
printf("n is now %d\n", n);
fflush(stdout);
printf("going to copy at most %d characters from '%s' into '%s'\n", n, rs, alpha);
fflush(stdout);
strncpy (alpha,rs,n);
printf("beta is now '%s'\n", beta);
fflush(stdin);
}
else printf("no match found\n");
}
return beta;
}
int main(void) {
char* r[2][5]={{"a","b","c","d", "e"}, {"o","e","i","u","s"}};
char* myText = "this is a vary sally strang";
printf("NewSpeak: %s\n", "hello world");
printf("converted: %s\n", newSpeak(myText, r));
return 0;
}
Output:
NewSpeak: hello world
length of input string is 27
allocated 28 bytes
copy OK: beta now this is a vary sally strang
alpha is 'a vary sally strang'
ii = 0; alpha now: 'a vary sally strang'
n is now 1
going to copy at most 1 characters from 'o' into 'a vary sally strang'
beta is now 'this is o vary sally strang'
alpha is 'ary sally strang'
ii = 1; alpha now: 'ary sally strang'
n is now 1
going to copy at most 1 characters from 'e' into 'ary sally strang'
beta is now 'this is o very sally strang'
alpha is 'ally strang'
ii = 2; alpha now: 'ally strang'
n is now 1
going to copy at most 1 characters from 'i' into 'ally strang'
beta is now 'this is o very silly strang'
alpha is 'ang'
ii = 3; alpha now: 'ang'
n is now 1
going to copy at most 1 characters from 'u' into 'ang'
beta is now 'this is o very silly strung'
converted: this is o very silly strung
Note - I added lots of "useless" output, including fflush(stdout); statements. This is a good way to ensure that debug printout shows you exactly how far into a program you got, and what was going on before it crashed - without the fflush it's possible you are missing many lines of output (because they never "made it to the screen").
It's obvious from the above that if your replacement strings are a different length than the string they replace, you will get some strange overwriting (I left both search and replace string length at 1 but there is no reason why that should be so).
I hope this helps!

Reading file in C

I'm reading a file in my C program and comparing every word in it with my word, which is entered via command line argument. But I get crashes, and I can't understand what's wrong. How do I track such errors? What is wrong in my case?
My compiler is clang. The code compiles fine. When running it says 'segmentation fault'.
Here is the code.
#include <stdio.h>
#include <string.h>
int main(int argc, char* argv[])
{
char* temp = argv[1];
char* word = strcat(temp, "\n");
char* c = "abc";
FILE *input = fopen("/usr/share/dict/words", "r");
while (strcmp(word, c))
{
char* duh = fgets(c, 20, input);
printf("%s", duh);
}
if (!strcmp (word, c))
{
printf("FOUND IT!\n");
printf("%s\n%s", word, c);
}
fclose(input);
}
The issue here is that you are trying to treat strings in C as you might in another language (like C++ or Java), in which they are resizable vectors that you can easily append or read an arbitrary amount of data into.
C strings are much lower level. They are simply an array of characters (or a pointer to such an array; arrays can be treated like pointers to their first element in C anyhow), and the string is treated as all of the characters within that array up to the first null character. These arrays are fixed size; if you want a string of an arbitrary size, you need to allocate it yourself using malloc(), or allocate it on the stack with the size that you would like.
One thing here that is a little confusing is you are using a non-standard type string. Given the context, I'm assuming that's coming from your cs50.h, and is just a typedef to char *. It will probably reduce confusion if you actually use char * instead of string; using a typedef obscures what's really going on.
Let's start with the first problem.
string word = strcat(argv[1], "\n");
strcat() appends the second string onto the first; it starts from the null terminator of the first string, and replaces that with the first character of the second string, and so on, until it reaches a null in the second string. In order for this to work, the buffer containing the first string needs to have enough room to fit the second one. If it does not, you may overwrite arbitrary other memory, which could cause your program to crash or have all kinds of other unexpected behavior.
Here's an illustration. Let's say that argv[1] contains the word hello, and the buffer has exactly as much space as it needs for this. After it is some other data; I've filled in other for the sake of example, though it won't actually be that, it could be anything, and it may or may not be important:
+---+---+---+---+---+---+---+---+---+---+---+---+
| h | e | l | l | o | \0| o | t | h | e | r | \0|
+---+---+---+---+---+---+---+---+---+---+---+---+
Now if you use strcat() to append "\n", you will get:
+---+---+---+---+---+---+---+---+---+---+---+---+
| h | e | l | l | o | \n| \0| t | h | e | r | \0|
+---+---+---+---+---+---+---+---+---+---+---+---+
You can see that we've overwritten the other data that was after hello. This may cause all kinds of problems. To fix this, you need to copy your argv[1] into a new string, that has enough room for it plus one more character (and don't forget the trailing null). You can call strlen() to get the length of the string, then add 1 for the \n, and one for the trailing null, to get the length that you need.
Actually, instead of trying to add a \n to the word you get in from the command line, I would recommend stripping off the \n from your input words, or using strncmp() to compare all but the last character (the \n). In general, it's best in C to avoid appending strings, as appending strings means you need to allocate memory and copy things around, and it can be easy to make mistakes doing so, as well as being inefficient. Higher level languages usually take care of the details for you, making it easier to append strings, though still just as inefficient.
After your edit, you changed this to:
char* temp = argv[1];
char* word = strcat(temp, "\n");
However, this has the same problem. A char * is a pointer to a character array. Your temp variable is just copying the pointer, not the actual value; it is still pointing to the same buffer. Here's an illustration; I'm making up addresses for the purposes of demonstration, in the real machine there will be more objects in between these things, but this should suffice for the purpose of demonstration.
+------------+---------+-------+
| name | address | value |
+------------+---------+-------+
| argv | 1000 | 1004 |-------+
| argv[0] | 1004 | 1008 | --+ <-+
| argv[1] | 1006 | 1016 | --|---+
| argv[0][0] | 1008 | 'm' | <-+ |
| argv[0][1] | 1009 | 'y' | |
| argv[0][2] | 1010 | 'p' | |
| argv[0][3] | 1011 | 'r' | |
| argv[0][4] | 1012 | 'o' | |
| argv[0][5] | 1013 | 'g' | |
| argv[0][6] | 1014 | 0 | |
| argv[1][0] | 1016 | 'w' | <-+ <-+
| argv[1][1] | 1017 | 'o' | |
| argv[1][2] | 1018 | 'r' | |
| argv[1][3] | 1019 | 'd' | |
| argv[1][4] | 1020 | 0 | |
+------------+---------+-------+ |
Now when you create your temp variable, all you are doing is copying argv[1] into a new char *:
+------------+---------+-------+ |
| name | address | value | |
+------------+---------+-------+ |
| temp | 1024 | 1016 | --+
+------------+---------+-------+
As a side note, you also shouldn't ever try to access argv[1] without checking that argc is greater than 1. If someone doesn't pass any arguments in, then argv[1] itself is invalid to access.
I'll move on to the next problem.
string c = "abc";
// ...
char* duh = fgets(c, 20, input);
Here, you are referring to the static string "abc". A string that appears literally in the source, like "abc", goes into a special, read-only part of the memory of the program. Remember what I said; string here is just a way of saying char *. So c is actually just a pointer into this read-only section of memory; and it has only enough room to store the characters that you provided in the text (4, for abc and the null character terminating the string). fgets() takes as its first argument a place to store the string that it is reading, and its second the amount of space that it has. So you are trying to read up to 20 bytes, into a read-only buffer that only has room for 4.
You need to either allocate space for reading on the stack, using, for example:
char c[20];
Or dynamically, using malloc():
char *c = malloc(20);
First problem I see is this:
string word = strcat(argv[1], "\n");
You are adding characters to the end of a buffer here.
A buffer allocated for you by the runtime enviroment, that you should consider read only.
EDIT
I'm afraid your change to the code still has the same effect.
char* temp = argv[1];
Has temp pointing to the same buffer as argv[1].
You need to allocate a buffer the proper size, and use it.
char* temp = (char*)malloc(sizeof(char) * (strlen(argv[1]) + 2));
The +2 is for the adding \n and \0 at the end.
Than you do this:
strcpy(temp, argv[1]);
strcat(temp,"\n");
The code is rather flawed. Another one:
char* duh = fgets(c, 20, input);
Here you define a pointer to char, do not initialize it (hence it contains a random value) and then you write up to 20 bytes to the address pointed to by the random data. If you're lucky you just get a cash. If not, you overwrite some other important data. Fortunately most of the systems in use today won't let you access address space of another program, so the code wreaks havoc only on itself.
The line in question could look like:
#define BUFFERSIZE 1024
...
while (reasonable condition) {
char *duh = malloc(BUFERSIZE);
if (NULL == duh) { /* not enough memory - handle error, and exit */
}
duh = fgets(duh, BUFFERSIZE, input);
if (NULL == duh) { /* handle error or EOF condition */
} else { /* check that the line is read completely,
i.e. including end-of-line mark,
then do your stuff with the data */
}
free (duh);
}
Of course, you can allocate the buffer only once (outside of the loop) and reuse it. The #define makes it easy to adjust the maximum buffer size.
Alternatively, on recent systems, you can use getline(), which is able to allocate a buffer of appropriate size for you. That you must free() at the end of the loop.
If you are on Linux/BSD, use man (e.g. man fgets) to get information on the functions, otherwise resort to internet or a decent book on C for documentation.
First, My C knowledge is old, so I'm not sure what a string is. Either way, it's helpful, but not absolutely required to have a nice pre-zeroed buffer in which to read contents of the file. So whether you zero word or do something like the following, zero the input first.
#define IN_BUF_LEN 120
char in_buf[IN_BUF_LEN] = {0};
120 characters is a safe size, assuming most of your text lines are around 80 characters or less long.
Second, you're basing your loop of the value of a strcmp rather than actually reading the file. It might accomplish the same thing, but I'd base my while on reaching end of file.
Finally, you've declared duh a pointer, not a place to store what fgets returns. That's a problem, too. So, duh should be declared similarly to in_buf above.
Finally, you're assigning the value of argv[1] at compile time, not run-time. I can't see where that's getting you what you want. If you declare temp as a pointer and then assign argv[1] to it, you'll just have another pointer to argv[1], but not actually have copied the value of argv[1] to a local variable. Why not just use argv[1]?

Resources