Pointers and Strings? - c

I want to write a program that erases all characters in string 1 that appear in string 2 , using pointers .
This is what I did , but it did not work .
#include<stdlib.h>
#include<stdio.h>
#include<string.h>
main()
{
char ch1[100] , ch2[100] ;
char *p1 , *p2;
printf("first chaine ");
gets(ch1);
printf("sd chaine");
gets(ch2);
for(p1=ch1;p1<ch1+100;p1++)
{
for(p2=ch2;p2<ch2;p2++)
{
if(*p1==*p2)
{
strcpy(p1,p1+1);
}
}
}
puts(ch1);
return 0 ;
}

strcpy() expects that its source and destination arguments don't overlap in memory — in other words, writing to the destination string shouldn't overwrite parts of the source string. So you can't use it to "shift" a string by an amount that's less than its length. Instead, you can use memmove(), which supports overlapping ranges.
You can replace your strcpy line with:
memmove(p1, p1+1, strlen(p1+1));
which will correctly do what you had expected the strcpy() call to do.
Also, your termination condition for the inner loop is p2<ch2, which is always false since they start out equal. You probably meant to write p2<ch2+100.
Your loop conditions have another problem, though: they go past the end of the actual string that's stored in the array. If the user types fewer than 99 characters of input for either string, the corresponding array will contain garbage characters after the null terminator. In the ch1 array, scanning past the end of the string may cause strlen() to go past the end of the whole array looking for another null terminator, and in ch2, going past the end of the string will cause the program to filter out characters that the user didn't specify.
You should change the two loop conditions to *p1 != '\0' and *p2 != '\0'. This will make the loops stop when they reach the end of the two strings.

NEVER USE GETS()
It's unsafe to use gets() under any circumstances, because it doesn't check the length of its input against the length of the array. Use fgets() instead.
Now that you understand that, take a look at your inner loop:
for(p2=ch2;p2<ch2;p2++)
You set p2=ch2, then check if p2<ch2. This will always be false. Perhaps you mean to check if p2<ch2+100?

First of all, you need bounds checking. gets() does not provide bounds checking.
As for for your loops, you will never enter the nested loops:
for(p2=ch2;p2<ch2;p2++)
Your initialization will always make your condition false, and you will never enter the loop.

Here is one solution to the problem. This code eliminates the inner loop of the question code by implementing strchr() to determine if a specific character of string1 is present in string2:
#include <stdio.h>
#include <string.h>
int main(void)
{
char ch1[100] , ch2[100];
char *p1, *p2;
/* Get string1 from stdin. */
printf("first chaine ");
fgets(ch1, sizeof(ch1), stdin);
/* Get string2 from stdin. */
printf("sd chaine ");
fgets(ch2, sizeof(ch2), stdin);
/* Eliminate all chars from string1 that appear in string2. */
for(p1=ch1, p2=ch1; *p1; p1++)
{
if(strchr(ch2, *p1))
continue;
*p2++ = *p1;
}
*p2 = '\0';
/* Print modified string1. */
puts(ch1);
return(0);
}
Execution example of the above code:
SLES11SP2:~/SO> ./test
first chaine Now is the time for all good men to come to the aid of their country.
sd chaine aeiou
Nw s th tm fr ll gd mn t cm t th d f thr cntry.
SLES11SP2:~/SO>

Related

string gets filled with garbage

i got a string and a scanf that reads from input until it finds a *, which is the character i picked for the end of the text. After the * all the remaining cells get filled with random characters.
I know that a string after the \0 character if not filled completly until the last cell will fill all the remaining empty ones with \0, why is this not the case and how can i make it so that after the last letter given in input all the remaining cells are the same value?
char string1 [100];
scanf("%[^*]s", string1);
for (int i = 0; i < 100; ++i) {
printf("\n %d=%d",i,string1[i]);
}
if i try to input something like hello*, here's the output:
0=104
1=101
2=108
3=108
4=111
5=0
6=0
7=0
8=92
9=0
10=68
You have an uninitialized array:
char string1 [100];
that has indeterminate values. You could initialize the array like
char string1 [100] = { 0 };
or
char string1 [100] = "";
In this call
scanf("%[^*]s", string1);
you need to remove the trailing character s, because %[] and %s are distinct format specifiers. There is no %[]s format specifier. It should look like this:
scanf("%[^*]", string1);
The array contains a string terminated by the zero character '\0'.
So to output the string you should write for example
for ( int i = 0; string1[i] != '\0'; ++i) {
printf( "%c", string1[i] ); // or putchar( string1[i] );
putchar( '\n' );
or like
for ( int i = 0; string1[i] != '\0'; ++i) {
printf("\n %d=%c",i,string1[i]);
putchar( '\n' );
or just
puts( string1 );
As for your statement
printf("\n %d=%d",i,string1[i]);
then it outputs each character (including non-initialized characters) as integers due to using the conversion specifier d instead of c. That is the function outputs internal ASCII representations of characters.
I know that a string after the \0 character if not filled completly
until the last cell will fill all the remaining empty ones with \0
No, that's not true.
It couldn't be true: there is no length to a string. No where neither the compiler nor any function can even know what is the size of the string. Only you do. So, no, string don't autofill with '\0'
Keep in minds that there aren't any string types in C. Just pointer to chars (sometimes those pointers are constant pointers to an array, but still, they are just pointers. We know where they start, but there is no way (other than deciding it and being consistent while coding) to know where they stop.
Sure, most of the time, there is an obvious answer, that make obvious for any reader of the code what is the size of the allocated memory.
For example, when you code
char string1[20];
sprintf(string1, "hello");
it is quite obvious for a reader of that code that the allocated memory is 20 bytes. So you may think that the compiler should know, when sprinting in it of sscaning to it, that it should fill the unused part of the 20 bytes with 0. But, first of all, the compiler is not there anymore when you will sscanf or sprintf. That occurs at runtime, and compiler is at compilation time. At run time, there is not trace of that 20.
Plus, it can be more complicated than that
void fillString(char *p){
sprintf(p, "hello");
}
int main(){
char string1[20];
string1[0]='O';
string1[1]='t';
fillString(&(string1[2]));
}
How in this case does sprintf is supposed to know that it must fill 18 bytes with the string then '\0'?
And that is for normal usage. I haven't started yet with convoluted but legal usages. Such as using char buffer[1000]; as an array of 50 length-20 strings (buffer, buffer+20, buffer+40, ...) or things like
union {
char str[40];
struct {
char substr1[20];
char substr2[20];
} s;
}
So, no, strings are not filled up with '\0'. That is not the case. It is not the habit in C to have implicit thing happening under the hood. And that could not be the case, even if we wanted to.
Your "star-terminated string" behaves exactly as a "null-terminated string" does. Sometimes the rest of the allocated memory is full of 0, sometimes it is not. The scanf won't touch anything else that what is strictly needed. The rest of the allocated memory remains untouched. If that memory happened to be full of '\0' before the call to scanf, then it remains so. Otherwise not. Which leads me to my last remark: you seem to believe that it is scanf that fills the memory with non-null chars. It is not. Those chars were already there before. If you had the feeling that some other methods fill the rest of memory with '\0', that was just an impression (a natural one, since most of the time, newly allocated memory are 0. Not because a rule says so. But because that is the most frequent byte to be found in random area of memory. That is why uninitialized variables bugs are so painful: they occur only from times to times, because very often uninitialized variables are 0, just by chance, but still they are)
The easiest way to create a zeroed array is to use calloc.
Try replacing
char string1 [100];
with
char *string1=calloc(1,100);

Problem reading two strings with getchar() and then printing those strings in C

This is my code for two functions in C:
// Begin
void readTrain(Train_t *train){
printf("Name des Zugs:");
char name[STR];
getlinee(name, STR);
strcpy(train->name, name);
printf("Name des Drivers:");
char namedriver[STR];
getlinee(namedriver, STR);
strcpy(train->driver, namedriver);
}
void getlinee(char *str, long num){
char c;
int i = 0;
while(((c=getchar())!='\n') && (i<num)){
*str = c;
str++;
i++;
}
printf("i is %d\n", i);
*str = '\0';
fflush(stdin);
}
// End
So, with void getlinee(char *str, long num) function I want to get user input to first string char name[STR] and to second char namedriver[STR]. Maximal string size is STR (30 charachters) and if I have at the input more than 30 characters for first string ("Name des Zuges"), which will be stored in name[STR], after that I input second string, which will be stored in namedriver, and then printing FIRST string, I do not get the string from the user input (first 30 characters from input), but also the second string "attached" to this, I simply do not know why...otherwise it works good, if the limit of 30 characters is respected for the first string.
Here my output, when the input is larger than 30 characters for first string, problem is in the row 5 "Zugname", why I also have second string when I m printing just first one...:
Name des Zugs:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
i is 30
Name des Drivers:xxxxxxxx
i is 8
Zugname: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaxxxxxxxx
Drivername: xxxxxxxx
I think your issue is that your train->name is not properly terminated with '\0', as a consequence when you call printf("%s", train->name) the function keeps reading memory until it finds '\0'. In your case I guess your structure looks like:
struct Train_t {
//...
char name[STR];
char driver[STR];
//...
};
In getlinee() function, you write '\0' after the last character. In particular, if the input is more than 30 characters long, you copy the first 30 characters, then add '\0' at the 31-th character (name[30]). This is a first buffer overflow.
So where is this '\0' actually written? well, at name[30], even though your not supposed to write there. Then, if you have the structure above when you do strcpy(train->name, name); you will actually copy a 31-bytes long string: 30 chars into train->name, and the '\0' will overflow into train->driver[0]. This is the second buffer overflow.
After this, you override the train->driver buffer so the '\0' disappears and your data in memory basically looks like:
train->name = "aaa...aaa" // no '\0' at the end so printf won't stop reading here
train->driver = "xxx\0" // but there
You have an off-by-one error on your array sizes -- you have arrays of STR chars, and you read up to STR characters into them, but then you store a NUL terminator, requiring (up to) STR + 1 bytes total. So whenever you have a max size input, you run off the end of your array(s) and get undefined behavior.
Pass STR - 1 as the second argument to getlinee for the easiest fix.
Key issues
Size test in wrong order and off-by-one. ((c=getchar())!='\n') && (i<num) --> (i+1<num) && ((c=getchar())!='\n'). Else no room for the null character. Bad form to consume an excess character here.
getlinee() should be declared before first use. Tip: Enable all compiler warnings to save time.
Other
Use int c; not char c; to well distinguish the typical 257 different possible results from getchar().
fflush(stdin); is undefined behavior. Better code would consume excess characters in a line with other code.
void getlinee(char *str, long num) better with size_t num. size_t is the right size type for array sizing and indexing.
int i should be the same type as num.
Better code would also test for EOF.
while((i<num) && ((c=getchar())!='\n') && (c != EOF)){
A better design would return something from getlinee() to indicate success and identify troubles like end-of-file with nothing read, input error, too long a line and parameter trouble like str == NULL, num <= 0.
I believe you have a struct similar to this:
typedef struct train_s
{
//...
char name[STR];
char driver[STR];
//...
} Train_t;
When you attempt to write a '\0' to a string that is longer than STR (30 in this case), you actually write a '\0' to name[STR], which you don't have, since the last element of name with length STR has an index of STR-1 (29 in this case), so you are trying to write a '\0' outside your array.
And, since two strings in this struct are stored one after another, you are writing a '\0' to driver[0], which you immediately overwrite, hence when printing out name, printf doesn't find a '\0' until it reaches the end of driver, so it prints both.
Fixing this should be easy.
Just change:
while(((c=getchar())!='\n') && (i<num))
to:
while(((c=getchar())!='\n') && (i<num - 1))
Or, as I would do it, add 1 to array size:
char name[STR + 1];
char driver[STR + 1];

Why this code can't print characters in an array?

I compiled this code using gcc (tdm-1) 5.1.0 and please tell me why the output doesn't contain "hello"
#include<stdio.h>
void main()
{
int i;
char st[20];
printf("Enter a string ");
scanf("%s",st);
for(i=0;i<20;i++)
{
printf("%c",st[i]);
}
}
Input:hello
Output: # #
You print all 20 elements of the array, but if the user entered a string smaller than that not all elements would be initialized. They would be indeterminate and seemingly random.
Remember that char strings in C are really called null-terminated byte strings. That null-terminated bit is important, and mean you can easily find the end of the string by checking the current character agains '\0' (which is the terminator character).
Or you could just use the strlen function to get the length of the string instead:
for(i=0;i<strlen(st);i++) { ... }
Or use the "%s" format to print the string:
printf("%s", st);
Also note that without any protection the scanf function will allow you give longer input than is space for in the array, so you need to protect agains that, for example by limiting the amount of characters scanf will read:
scanf("%19s",st); // Write at most 19 character (*plus* terminator) to the string
Now for why your input doesn't seem to be printed, it's because the indeterminate contents of the uninitialized elements. While you're not going out of bounds of your array, you still go out of bounds of the actual string. Going out of bounds leads to undefined behavior.
What's probably is happening is that some of the "random" indeterminate contents happens to be a carriage return '\r', which moves the cursor to the start of the line and the output already written will be overwritten by the uninitialized elements in your array.
Here's a short example as Qubit already explained:
#include <stdio.h>
void main () {
char str1[20];
printf("Enter name: ");
scanf("%s", str1);
printf("Entered Name: %s", str1);
}
Here
char st[20];
st is a local variable & default array st contents are garbage not zero. So if you scan less than 20 characters into st, in that case remaining location of array st contains garbage, hence it's printing some junk data like # # in case of
char st[20];
printf("Enter a string ");
scanf("%s",st);
for(i=0;i<20;i++) {
printf("%c",st[i]);
}
& it's a bad practice as if user entered few char lets say 5 char, then your loop rotates 20 times, internally it will do more operations or consume more CPU cycle.
So if you want to print a char array char by char, then you should rotate a loop until \0 char encounters, for e.g
for(i=0;st[i];i++) { /* this fails when \0 encounters */
printf("%c",st[i]);
}
Or
as others suggested you can print char array st using single printf by using %s format specifier like
printf("%s\n",st); /*here printf starts printing from base address of st
and prints until \0 */
Also it's better to initialize char array st while declaring itself. for e.g
char st[20] ="";

Scanning and printing strings using pointers

I wrote a code for scanning a string from user using pointers and storing it in another string array and printing that string array. The output is coming quite strange. The first three characters are printed but next characters are coming as random garbage values. Please tell me the error in the code. Following is the code:
#include<stdio.h>
int main(void)
{
char str1[8];
char *p1=str1;
char str2[8];
char *p2=str2;
printf("Enter a string\n");
while(*p1)
scanf("%c",p1++);
*p1='\0';
p1=&str1[0];
while(*p1)
*p2++=*p1++;
*p2='\0';
printf("The copied string is :");
p2=&str2[0];
while(*p2)
printf("%c",*p2++);
}
You are not placing the terminating null character('\0') at the end of your strings str1[] and str2[]. And you are trying to dereference and check the value which is not initialized in your first while loop condition: while(*p1)
printf("Enter a string\n");
do{
scanf("%c",p1++);
}while(*(p1 - 1) != '\n'); //try the do while loop
*(p1 - 1) = '\0'; //placing terminating null character
p1 = &str1[0];
while(*p1){
*p2++ = *p1++;
}
*p2 = '\0'; //placing terminating null character
here's the demo code: https://ideone.com/dF2QsJ
Why have you checked the condition for the new line in the do while condition? And why p1-1?
This is because you end the input by entering a '\n' which gets stored at p1 and then p1 moves to p1 + 1 at the end of each iteration. So, I check whether a '\n' is present at p1 - 1.
okay,
Why arent you using %s and get the input directly. you can get the entire string rather than looping over each character.
This loop
while(*p1)
scanf("%c",p1++);
checks the contents of str1 (pointed at by p1) before ever storing anything there. That uninitialized memory might contain anything, so this loop might never execute (if the first char happens to be NUL), or might run off the end of the array (corrupting memory).

Hidden or special characters in strings or different statement codes

How can I make my input string S1 of the fgets (or similar statement) to be equal to my declared static string S2?
#include <stdio.h>
#include <string.h>
main() {
char s1[80];
char s2[] = "This is a test.";
int l1, l2;
system("clear");
printf("%s\n\n", s2);
printf("Please type exactly the above sentence: ");
fgets(s1,80,stdin);
l1=strlen(s1);
l2=strlen(s2);
printf("\n String entered for S1, have a length of %d:\n %s", l1, s1);
printf("\n String static for S2, have a legnth of %d:\n %s", l2, s2);
if(s1==s2)
printf("\n\nOk! they're with the same length!\n");
else
printf("\n\nNop! They are NOT the same.\n");
return(0);
}
You're doing a pointer comparison, not a string comparison. To compare the content of the strings, use strcmp (docs):
if (strcmp(s1, s2) == 0)
...
fgets reads a line of input (up to a specified length, in your case 80). It stores that line in the array pointed to by its first argument (s1) -- including the terminating '\n' newline character.
Which means that after your fgets call, assuming you typed exactly "This is a test." and then typed Enter, s1 will contain "This is a test.\n", not just "This is a test.".
You can remove that newline character before the comparison -- or rather you can replace it with a null character '\0', which marks the end of the string:
size_t len = strlen(s1);
if (s1[len-1] == '\n') {
s1[len-1] = '\0';
}
(You might need to move the declaration of len to the top of main if your compiler doesn't support mixed declarations and statements -- but the strlen call still has to be done after fgets.)
To test whether the s1 and s2 contain the same string value, use the strcmp function; your s1 == s2 does a pointer comparison. strcmp returns 0 if the strings are equal. (If they're not, it returns a negative or positive value to indicate whether the left string is lexicographically less than or greater than the right string.)
Some minor comments on your code:
main() should be int main(void). (Long story; for now, just take my word for it.)
There's probably no need to invoke system("clear"). Why do you want to clear the screen? There might be useful information on it. And it won't work on all systems. If I want to clear my screen before running your program, I can do it myself, thank you very much.
Your message "they're with the same length" isn't quite right. If you correct the test by using strcmp rather than ==, you're testing whether the strings have the same value, whether their lengths happen to be the same or not.
Usually when you print a message, it's best to put the newline \n at the end of the output. It's usually best to have just a single \n at the end of the message (unless you want to print multiple lines with one printf, or build up one line with multiple printfs, which you can do but it's not necessary here.)
Your question originally had gets and scanf tags. Never use the gets function; it's inherently unsafe and has been removed from the language. scanf is tricky, and not needed in this case.

Resources