I wanted to copy string with the following code and it didn't copy the '\0'.
void copyString(char *to, char *from)
{
do{
*to++ = *from++;
}while(*from);
}
int main(void)
{
char to[50];
char from[] = "text2copy";
copyString(to, from);
printf("%s", to);
}
This is output to the code:
text2copyÇ■ ║kvu¡lvu
And every time I rerun the code the code, the character after text2copy changes, so while(*from) works fine but something random is copied instead of '\0'.
text2copyÖ■ ║kvu¡lvu
text2copy╨■ ║kvu¡lvu
text2copy╡■ ║kvu¡lvu
//etc
Why is this happenning?
The problem is that you never copy the '\0' character at the end of the string. To see why consider this:
The string passed in is a constant string sized exactly to fit the data:
char from[] = "text2copy";
It looks like this in memory:
----+----+----+----+----+----+----+----+----+----+----+----
other memory | t | e | x | t | 2 | c | o | p | y | \0 | other memory
----+----+----+----+----+----+----+----+----+----+----+----
^
from
Now let's imagine that you have done the loop several times already and you are at the top of the loop and from is pointing to the 'y' character in text2copy:
----+----+----+----+----+----+----+----+----+----+----+----
other memory | t | e | x | t | 2 | c | o | p | y | \0 | other memory
----+----+----+----+----+----+----+----+----+----+----+----
^
from
The computer executes *to++ = *from++; which copies the 'y' character to to and then increments both to and from. Now the memory looks like this:
----+----+----+----+----+----+----+----+----+----+----+----
other memory | t | e | x | t | 2 | c | o | p | y | \0 | other memory
----+----+----+----+----+----+----+----+----+----+----+----
^
from
The computer executes } while(*from); and realizes that *from is false because it points to the '\0' character at the end of the string so the loop ends and the '\0' character is never copied.
Now you might think this would fix it:
void copyString(char *to, char *from)
{
do{
*to++ = *from++;
} while(*from);
*to = *from; // copy the \0 character
}
And it does copy the '\0' character but there are still problems. The code even more fundamentally flawed because, as #JonathanLeffler said in the comments, for the empty string you peek at the contents of memory that is after the end of the string and because it was not allocated to you accessing it causes undefined behaviour:
----+----+----
other memory | \0 | other memory
----+----+----
^
from
The computer executes *to++ = *from++; which copies the '\0' character to to and then increments both to and from which makes from point to memory you don't own:
----+----+----
other memory | \0 | other memory
----+----+----
^
from
Now the computer executes }while(*from); and accesses memory that isn't yours. You can point from anywhere with no problem, but dereferencing from when it points to memory that isn't yours is undefined behaviour.
The example I made in the comments suggests saving the value copied into a temporary variable:
void copyString(char *to, char *from)
{
int test;
do{
test = (*to++ = *from++); // save the value copied
} while(test);
}
The reason I suggested that particular way was to show you that the problem was WHAT you were testing and not about testing the loop condition afterwards. If you save the value copied and then test that saved value later the character gets copied before it is tested (so the \0 gets copied) and you don't read from the incremented pointer (so there is no undefined behaviour)
But the example #JonathanLeffler had in his comments is shorter, easier to understand, and more idiomatic. It exact does the same thing without declaring a named temporary variable:
void copyString(char *to, char *from)
{
while ((*to++ = *from++) != '\0')
;
}
The code first copies the character and then tests the value that was copied (so the '\0' will be copied) but the incremented pointer is never dereferenced (so there is no undefined behaviour).
the posted code stops looping when it encounters the NUL byte, rather than afterwards.
Regarding:
}while(*from);
Suggest following that line with:
*to = '\0';
Related
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
void print_reverse(char *s)
{
size_t len=strlen(s);
char *t=s+len-1;
printf("%s %s\n",t,s);
while(t>=s){
printf("%c",*t);
t=t-1;
}
puts("");
}
int main(){
print_reverse("Hello");
}
Can anyone tell how char *t=s+len-1; and while(t>=s) works. I cant understand how a number can be added to pointer and how the pointers are compared in while loop. This program is for reversing a string in c.
Lets do this line by line:
print_reverse("Hello");
void print_reverse(char *s)
Now s points to a string that contains:
- - ----+----+----+----+----+----+----+---- - -
| H | e | l | l | o | \0 |
- - ----+----+----+----+----+----+----+---- - -
^
s
That last character is called the string "NUL" terminator because "NUL" is the name of the character with ASCII value zero (all ASCII values that are not printable have three letter names).
size_t len=strlen(s);
Now len has a value of five. Notice it does not include the "NUL" terminator so even though the string takes 6 bytes the length is five.
char *t=s+len-1;
Now t has a value of s+4. If you count the memory locations this is what you get:
- - ----+----+----+----+----+----+----+---- - -
| H | e | l | l | o | \0 |
- - ----+----+----+----+----+----+----+---- - -
^ ^
s t
Note that s+strlen(s) would point to the "NUL" terminator.
printf("%s %s\n",t,s);
That printf should print Hello o
while(t>=s)
This while loop will continue as long as t>=s which means it will do the body of the loop for every character, including the one where s is pointing.
printf("%c",*t);
This prints the contents of the memory that t is pointing at. It starts with the o and continues backwards towards the H.
t=t-1;
That the part that moves t backwards. Eventually t will be past s and then the loop will end. When the loop finishes it will look like this:
- - ----+----+----+----+----+----+----+---- - -
| H | e | l | l | o | \0 |
- - ----+----+----+----+----+----+----+---- - -
^ ^
t s
Then there is this one final line:
puts("");
That prints an empty string and a final linefeed - there wasn't a linefeed in the string but we needed one so this is a way to do that.
Pointer Arithmetic
When a pointer points into an array, adding integers to the pointer or subtracting integers from the pointer moves the pointer back and forth within the array.
This function should be passed a char *s that points to a string, which is an array of characters ending in a null character ('\0'). Then size_t len = strlen(s); sets len to the size of this string, and char *t = s+len-1; sets t to point to the last character before the null character.
Then, in the loop t=t-1; moves t backward.
Unfortunately, this loop uses t>=s as its control condition. This is intended to stop when t has been moved to the character before s, meaning it has gone back before the start point. However, the C standard only defines pointer arithmetic for elements within the array plus a special position at the end of the array. If this function is passed an s that points to the beginning of an array, then the loop will eventually make t point before the array, and the C standard does not define the resulting behavior.
Other Things to Know About Pointer Arithmetic
Any object may be treated as an array of one element. If you have some type T and some object T x;, you may set a pointer T *p = &x;, and then it is allowed to advance the pointer by one element, p = p+1;. Dereferencing that pointer with *p is not defined, but you can compare it, as in &x == p, or you can subtract one from it.
If print_reverse were passed a pointer into an array beyond the beginning, then its loop would be okay. However, that is now how it is used in the example code; print_reverse("Hello"); is not good code.
Any object may be treated as an array of characters. You can convert a pointer to any object to a pointer to unsigned char and then examine the bytes that make up an object. This is used for special purposes. You should not use it in general code while you are learning C, but you should be aware it exists.
#include <stdio.h>
#include <string.h>
int main()
{
int i;
char a[10];
for(i=0;i<10;i++)
{
scanf("%s",a);// >how this line is working in memory.
}
return 0;
}
In the above code, I would like to know how the string is saved in memory, since I have initialised it as a 1D character array, but does the array work as a list of strings, or a single string? Why?
In C, a string is a sequence of character values terminated by a 0-valued character - IOW, the string "Hello" is represented as the character sequence 'H', 'e', 'l', 'l', 'o', 0. Strings are stored in arrays of char (or wchar_t for wide strings):
char str[] = "Hello";
In memory, str would look something like this:
+---+
str: |'H'| str[0]
+---+
|'e'| str[1]
+---+
|'l'| str[2]
+---+
|'l'| str[3]
+---+
|'o'| str[4]
+---+
| 0 | str[5]
+---+
It is possible to store multiple strings in a single 1D array, although almost nobody does this:
char strs[] = "foo\0bar";
In memory:
+---+
strs: |'f'| strs[0]
+---+
|'o'| strs[1]
+---+
|'o'| strs[2]
+---+
| 0 | strs[3]
+---+
|'b'| strs[4]
+---+
|'a'| strs[5]
+---+
|'r'| strs[6]
+---+
| 0 | strs[7]
+---+
The string "foo" is stored starting at strs[0], while the string "bar" is stored starting at strs[4].
Normally, to store an array of strings, you'd either use a 2D array of char:
char strs[][MAX_STR_LEN] = { "foo", "bar", "bletch" };
or a 1D array of pointers to char:
char *strs[] = { "foo", "bar", "bletch" };
In the first case, the contents of the string are stored within the strs array:
+---+---+---+---+---+---+---+
strs: |'f'|'o'|'o'| 0 | ? | ? | ? |
+---+---+---+---+---+---+---+
|'b'|'a'|'r'| 0 | ? | ? | ? |
+---+---+---+---+---+---+---+
|'b'|'l'|'e'|'t'|'c'|'h'| 0 |
+---+---+---+---+---+---+---+
In the second, each strs[i] points to a different, 1D array of char:
+---+ +---+---+---+---+
strs: | | strs[0] ------> |'f'|'o'|'o'| 0 |
+---+ +---+---+---+---+
| | strs[1] ----+
+---+ | +---+---+---+---+
| | strs[2] -+ +-> |'b'|'a'|'r'| 0 |
+---+ | +---+---+---+---+
|
| +---+---+---+---+---+---+---+
+----> |'b'|'l'|'e'|'t'|'c'|'h'| 0 |
+---+---+---+---+---+---+---+
In your code, a can (and is usually intended to) store a single string that's 9 characters long (not counting the 0 terminator). Like I said, almost nobody stores multiple strings in a single 1D array, but it is possible (in this case, a can store 2 4-character strings).
char a[10];
You've allocated 10 bytes of the stack for a. But right now, it contains garbage because you never gave it a value.
Scanf doesn't know any of this. All it does is copy bytes from the standard input into a, ignorant of its size.
And why are you doing a loop 10 times? You will overwrite a each loop iteration, so you'll only have the value from the final time.
A string is per definition a null-terminated character array. So every character array becomes a string as soon as it contains a \0 somewhere, defining the end of that string.
In memory the string is just a bunch of bytes laying (for simplicity but not necessarily) in sequence. Take the string "Hello" for example
+---+---+---+---+---+---+
| H | e | l | l | o | \0|
+---+---+---+---+---+---+
Your array char a[10] is pointing to the beginning of such a memory location ('H' in the example) with enough space to store 10 characters.
By using scanf you are storing an string (character sequence + terminating \0) in that buffer (over and over again). scanf stores the characters in there and adds a terminating \0 to the element after the last one written to. This allows you to safely store any character sequence that is at most 9 characters long, since the 10th character needs to be the \0
Does a 1D array work as a list of strings, or a single string?
quite broad question.
char a[10]; declared table a which has a size of 10 the char elements
char *a[10]; declared table a which has a size of 10 char * elements which can possible point to the string (when you allocate memory for it and copy the valid C string)
In your code:
'scanf("%s",a);' a means the address of the first element of the array. So scanf writes data there, every time overwriting the previous content. If your scanf-ed input will need more 10 elements (including trailing 0) to be stored, you will get an UB and very possible SEGFAUT
You are over-writing same buffer in loop 10 times, which means buffer will contain data entered in last reading and previous 9 strings will be lost.
Also entering more than 9 characters would cause buffer overflow which would invoke undefined behavior.
You should limit number of characters scanned from input buffer and then clear the rest of the buffer. (Not fflush(stdin);)
scanf("%9s",a);
Does a 1D array work as a list of strings, or a single string?
If its terminated with null character then yes, its string, like this. And a is the address of first element.
+---+---+---+---+---+---+----+
| S | t | r | i | n | g | \0 |
+---+---+---+---+---+---+----+
a a+1 a+2
And if you pass this array ie. to printf(), he will print all characters until he reach \0.
If you would like to read list of strings, you have to declare 2D array or pointer-to-pointer-to-char and allocate enough memory for pointers.
int c;
char a[10][10];
for(i=0;i<10;i++)
{
scanf("%9s",a[i]);
while ((c = getchar()) != '\n' && c != EOF) ;
}
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.
I have a piece of code that has the following lines:
char* someString = "Blah"
char* someOtherString = someString;
if (someString) {
while (*someOtherString) {
printf("%d\n",someOtherString);
++someOtherString;
}
--someOtherString;
}
This prints out:
4206692
4206693
4206694
4206695
How does it even work? I get that it goes through the if statement as true because someString can be interpreted as a true condition, but how does it exit the while loop?
When I type the while loop by itself like so, I the loop goes infinitely:
while (*someOtherString) {
printf("%d\n",someOtherString);
++someOtherString;
}
Thanks for help in advanced!
The while loop exits when it finds the NUL character at the end of the "string".
Working :
In C, declaring and assigning constant strings inside double-quotes declares a null-terminated string. Memory equal to the
number of characters in side the double-quotes + 1 (for the trailing NUL character) is allocated. Each of the characters is stored sequentially in the memory block and a NUL character is automatically assigned to the end of the memory block.
Thus "Blah" is stored in memory as
B L A H \0
Intially someOtherString and someString both point to B.
someOtherString is incremented to point to the next character in each iteration of the while loop. So after 4 iterations it ends up pointing to the null character.
A while loop running on un-initialised data could run for a large
number of iterations as there is no guarantee that it will encounter a
NUL character (byte = 0x00).
Finally a list of popular functions and extensions for processing strings in C.
This is just a technique to scan through a string.
When you just tell char *string1 = "hello" the starting address of the string will be stored inside the variable char *string1 and not the string. One practice is to assign a pointer to NULL when it is not used, instead allowing the old address values in it, which now is not valid. Therefore if at some point we did string1 = NULL, then the if (string1) will be false, becaues NULL evaluates to 0.
a1 a2 a3 a4 a5 a6
+-----+-----+-----+-----+-----+-----+
string1 = | h | e | l | l | o | \0 |
+-----+-----+-----+-----+-----+-----+
Whereas when we do *string1 it is basically in the form *(string + x). Depending on the type of the pointer string1 , x elements will be skipped first, then * will do the dereferencing at the location, x elements away from the address what is stored in string1.
a1 a2 a3 a4 a5 a6
+-----+-----+-----+-----+-----+-----+
string1 = | h | e | l | l | o | \0 |
+-----+-----+-----+-----+-----+-----+
^
|
+-------------+
|
*(string1 + 3) same as string1[3]
Therefore doing *string1 will fetch the value pointed by the address stored in string1.
Therefore
if (string1)
{
while (*string1)
{
count++;
string1++;
}
}
This will enter the if iff the address stored in the string is not NULL, ie some valid address is assigned (if we follow the convention to assign NULL to unused). *string will be true until the address stored in string1 in a specific iteration points to a non-zero value. C strings are terminated with a NUL character which is '\0' and has an ASCII value 0. In each iteration we do string1++, this will increment the address value stored, and after each increment the value of string1 will point to the next element adjacent (first a1 then a2 etc). When it points to the address where '\0' is stored, *string1 will be 0 and while (*string1) is false thus breaks out of the loop.
Your string literal is stored in memory like:
{'B', 'l', 'a', 'h', '\0'}
...where '\0' is the null character (i.e. a character with a value of 0 when interpreted as an integer).
So eventually (after 4 increments), *someOtherString will evaluate to 0, which will be interpreted as false and end the loop.
I'm not sure how you're getting the infinite loop. Your cut-down versions works just fine in ideone: http://ideone.com/4fTDJb
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]?