Pointers in C resulting in unknown random char - c

I have some C code to print a string char array twice.
Code:
char* twice(char *s) {
int size=strlen(s),i=0;
int length=size*2;
char check = s[size-1];
char* s2 = malloc(length * sizeof(char));
char* reset = malloc(size * sizeof(char));
memcpy(reset, s, size * sizeof(char));
while (i<length) {
printf("%s\n", s);
s2[i] = *s;
if(s2[i] == check && i == size-1){
s = reset;
}else s++;
i++;
}
return s2;
}
int main(){
char s[] = "hello1234";
printf("%s\n", twice(s));
return 0;
}
Output:
hello1234
ello1234
llo1234
lo1234
o1234
1234
234
34
4
hello1234
ello1234
llo1234
lo1234
o1234
1234
234
34
4
hello1234hello1234Ms?
The inputted string is hello1234 and i am printing out each pointer to show that it correctly runs through the string twice. But for some reason the answer includes Ms? resulting in hello1234hello1234Ms? why is that?

In C, strings are terminated with a special character with the value '\0'.
memcpy() works with memory, it is not specific to strings. And so it does not copy the terminator since you didn't give it a length that includes the terminator. (strlen() does not include the terminator.)
When printf() doesn't find the terminator, it just keeps printing whatever is in memory. The additional characters are just random and will be different on different set ups.

Related

printing the multiple string values in a single line in c

I am reading a data from a method which returns 4 string values
printf(%s,%s,%s,%s \n",modValuex.A,modValuex.B,modValuex.C,modValuex.D)
it gives values like below but not in a single line like(12,-12,45 )
12
,-12
,45
1
,-23
119
how can i fix this/
I tried adding a \r and \t as well, same result.
This trimming of strings is best avoided, as commmented.
In C one possibility here would be to replace the first \n with a \0 in-place.
char* chop(char *s) {
char *p = s;
while (*p++)
if (*p == '\n') {
*p = '\0';
break;
}
return s;
}
called like this:
char s1[] = "12\n";
char s2[] = "13\n133\n1333\n";
char s3[] = "14\n";
printf("%s,%s,%s", chop(s1), chop(s2), s3);
it prints 12,13,14 and a newline.
The characters of s2 don't get printed. strlen(s2) is 2, but sizeof s2 is 13.
But that method (from which you read the data) should be a help, not a source of complication. (In C you rather assign a return value of a function)
modValuex.A and others contain a '\n'.
To print modValuex.A without a '\n' either remove it before printing or stop printing before the '\n'.
If possible, simply lop off the '\n':
modValuex.A[strcspn(modValuex.A, "\n")] = '\0';
If modValuex.A and friends unchangeable, to stop before the '\n', use a width limit:
// printf(%s,%s,%s,%s n",modValuex.A,modValuex.B,modValuex.C,modValuex.D)
printf(%.*s,%.*s,%.*s,%.*s\n",
(int) strcspn(modValuex.A, "\n"), modValuex.A,
(int) strcspn(modValuex.B, "\n"), modValuex.B,
(int) strcspn(modValuex.C, "\n"), modValuex.C,
(int) strcspn(modValuex.D, "\n"), modValuex.D);
size_t strcspn( const char *dest, const char *src )
returns the number of initial bytes in a string that are not in a second string.

How to copy a sentence from a longer string into a new array while including period?

I want to save part of a string into a new char array while including the period. For example, the string is:
My name is John. I have 1 dog.
I want to copy each char up to and including the first period, so the new char array will contain:
My name is John.
The code I have written below copies only "My name is John" but omits the period.
ptrBeg and ptrEnd point to the char at the beginning and end, respectively, of the portion I want to copy. My intention was to copy ptrBeg into array newBuf through a pointer to newBuf and then increment both ptrBeg and the pointer to the array until ptrBeg and ptrEnd point to the same char, which should always be a period.
At this point, the text of the string should be copied, so I increment the pointer to char array once more and copy the period to the new space using
++ptrnewBuf;
*ptrnewBuf = *ptrEnd";
Finally, I print the contents of newBuf.
Here's the total code:
int main()
{
char buf[] = "My name is John. I have 1 dog.";
char * ptrBuf;
char * ptrBeg;
char * ptrEnd;
ptrBeg = buf;
ptrBuf = ptrBeg;
while (*ptrBuf != '.'){
ptrBuf++;
}
ptrEnd = ptrBuf;
char newBuf[100];
char * ptrnewBuf = newBuf;
while(*ptrBeg != *ptrEnd){
*ptrnewBuf = *ptrBeg;
ptrnewBuf++;
ptrBeg++;
}
++ptrnewBuf;
*ptrnewBuf = *ptrEnd;
printf("%s", newBuf);
}
How would I modify this code to include a period?
You are on the right track, but you may be making things a bit more complicated than needed and overlooking a few critical checks. The key to iterating by pointers or using pointer arithmetic is to always validate and protect your array or memory bounds during each iteration or arithmetic operation.
Another tip is to always map out your pointer positions on a piece of paper before coding everything up so you have a clear picture of what your iteration limits and any adjustments need to be. (you don't have to use full long strings and many boxes, just use a representation of what needs to be done with a handful of characters) In your case where you wish to copy the substing up through the first '.', something simple like the following will do, e.g.
+---+---+---+---+---+---+
| A | . | | B | . |\0 |
+---+---+---+---+---+---+
^ ^
| pointer (when *p == '.')
buf
So to copy "A." from buf to a new buffer you can't simply iterate while (*p != '.') or you will not copy '.'. By drawing it out, you can clearly see you need to also copy the character when p == '.', e.g.
+---+---+---+---+---+---+
| A | . | | B | . |\0 |
+---+---+---+---+---+---+
^ ^
| |-->| pointer (p + 1)
buf
Now regardless of the actual length of the string before '.', you now know you need p + 1 as the final address to include the last character in the copy.
You also know how many characters your new buffer can store. Say the size of new is MAXC characters (maximum number of characters). So you can store a string of at most MAXC-1 characters (plus the nul-character). When you are filling new you need to always validate you are within MAXC-1 characters.
You also need to insure you new string is nul-terminated (or it isn't a string, it's simply an array of characters). One effective way to insure nul-termination is by initializing all characters in new to 0 when it is declared, e.g.
char new[MAXC] = "";
which initializes the 1st character to 0 (e.g. '\0' empty-string) and all remaining characters 0 by default. Now if you fill no more than MAXC-1 characters, you are guaranteed the array will be a nul-terminated string.
Putting it altogether, you could do something like the following:
#include <stdio.h>
#define MAXC 128 /* if you need a constant, #define one (or more) */
int main (void) {
char buf[] = "My name is John. I have 1 dog.",
*p = buf, /* pointer to buf */
new[MAXC] = "", /* buffer for substring */
*n = new; /* pointer to new */
size_t ndx = 0; /* index for new */
/* loop copying each char until new full, '.' copied, or end of buf */
for (; ndx + 1 < MAXC && *p; p++, n++, ndx++) {
*n = *p; /* copy char from buf to new */
if (*n == '.') /* if char was '.' break */
break;
}
printf ("buf: %s\nnew: %s\n", buf, new);
return 0;
}
(note: ndx is incremented as part of the for loop to track the number of characters copied with the pointers)
Example Use/Output
$ ./bin/str_cpy_substr
buf: My name is John. I have 1 dog.
new: My name is John.
If you do not have the luxury of initializing the string to insure nul-termination, you can always affirmatively nul-terminate after your copy is done. For example, you could add the following after the for loop exit to insure an array of unknown initialization is properly terminated:
*++n = 0; /* nul-terminate (if not already done by initialization) and
* note ++n applied before * due to C operator precedence.
*/
Look things over and let me know if you have further questions.
Just breaking it out into a helper function that "extracts" the first sentence from a line. Just copies the characters over one at a time until either an end of string condition is hit on the source, the period is found, or a max length of the destination buffer is encountered.
void ExtractFirstSentence(const char* line, char* dst, int size)
{
int count = 0;
char c ='\0';
if ((line == NULL) || (dst == NULL) || (size <= 0))
{
return;
}
while ((*line) && ((count+1) < size) && (c != '.'))
{
c = *line++;
*dst++ = c;
count++;
}
*dst = '\0';
}
int main()
{
char buf[] = "My name is John. I have 1 dog.";
char newBuf[100];
ExtractFirstSentence(buf, newBuf, 100);
printf("%s", newBuf);
}
if you want something a bit easier without dealing with all those pointers, try :
int main()
{
char buf[] = "My name is John. I have 1 dog.";
int i = 0;
int j = 0;
while(buf[i] != '.' && buf[i] != '\0') {
i++;
}
char newbuf[i+1];
while (j <= i) {
newbuf[j] = buf[j];
j++;
}
newbuf[j] = '\0';
printf("%s\n",newbuf);
return 0;
}
though the i+1 when making newbuf and the newbuff[j] = '\0' im not 100% certain need to be that way. my thoughts are the i+1 is needed to make room for the \0 ending which is then added after the while loop copying buf to newbuf. but i could be mistaken.
You can use strtok() to split string. Just type man strtok, You will see:
Program source
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int
main(int argc, char *argv[])
{
char *str1, *str2, *token, *subtoken;
char *saveptr1, *saveptr2;
int j;
if (argc != 4) {
fprintf(stderr, "Usage: %s string delim subdelim\n",
argv[0]);
exit(EXIT_FAILURE);
}
for (j = 1, str1 = argv[1]; ; j++, str1 = NULL) {
token = strtok_r(str1, argv[2], &saveptr1);
if (token == NULL)
break;
printf("%d: %s\n", j, token);
for (str2 = token; ; str2 = NULL) {
subtoken = strtok_r(str2, argv[3], &saveptr2);
if (subtoken == NULL)
break;
printf(" --> %s\n", subtoken);
}
}
exit(EXIT_SUCCESS);
}
An example of the output produced by this program is the following:
$ ./a.out 'a/bbb///cc;xxx:yyy:' ':;' '/'
1: a/bbb///cc
--> a
--> bbb
--> cc
2: xxx
--> xxx
3: yyy
--> yyy

Invert 2 Strings in C

I have the following program that is supposed to invert 2 strings.
Ex:
Str1=a
Str2=b
Result: ba
However I have some Bug in the code that I can't find and it doesn't allow the program to invert the strings. Can someone take a look on this?
#include<stdio.h>
#include<string.h>
/*
Return the result of appending the characters in s2 to s1.
Assumption: enough space has been allocated for s1 to store the extra
characters.
*/
char* append (char s1[ ], char s2[ ]) {
int s1len = strlen (s1);
int s2len = strlen (s2);
int k;
for (k=0; k<s2len; k++) {
s1[k+s1len] = s2[k];
}
s1[k+s1len]='\0';
return s1;
}
int main ( ) {
char str1[10];
char str2[10];
while (1) {
printf ("str1 = ");
if (!gets (str1)) {
return 0;
};
printf ("str2 = ");
if (!gets (str2)) {
return 0;
};
printf ("The result of appending str2 to str1 is %s.\n",
append (str1, str2));
}
return 0;
}
One problem you have is buffer overflow as your strings are very short; if the result string is longer than 10 bytes, your string arrays will overflow. Make them at least 80 bytes or something like that.
(Also, you shouldn't use gets(), since gets() doesn't check for string length, but as you're still learning, that is an issue for later).
Your append function appends s2 to s1, and you're calling append (str1, str2), so you won't invert the strings. Try append (str2, str1) instead.

How to know if a char array has a null element in C?

Say if I have :
unsigned char* str = "k0kg"
And 0 is the null element. When I loop through it using a for loop, how do I check if the array has a null?
I tried:
if (str[1]==0):
I also tried:
if (str[1]=="0"):
And they didn't work. :(
The loop:
for (i=0;i<num_bytes;i++){
if (str[i]!=0){
printf("null spotted\n");
}
In C, strings, by definition, are terminated by '\0', the NUL character. So all (valid) strings have a '\0' in them, at the end.
To find the position of the '\0', simply use strlen():
const char * const end = str + strlen(str);
It's odd that you are using "unsigned char" if you are dealing with normal, printable strings. If you mean that you have a memory block with bytes it in and you want to find the first 0x00 byte, then you'll need a pointer to the start of the memory and the size of the memory area, in bytes. Then, you'd use memchr():
// Where strSize is the number of bytes that str points to.
const unsigned char * const end = memchr(str, 0, strSize);
If you are actually looking for the null element then you should do the following condition :
if(str[i]=='\0')
Say if I have : unsigned char* str = "k0kg"
And 0 is the null element. When I loop through it using a for loop, how do I check if the array has a null?
You're terminology is going to confuse any C programmer. You're confusing character representations with values. You're not looking for a null character ("null element", which would be '\0'), you're looking for the character '0'. So...
int len = strlen(str);
for(int i = 0; i < len; ++i) {
if(str[i] == '0')
printf("found it");
}
use strchr
#include <stdio.h>
#include <string.h>
int main(){
char *str = "k0kg";
char *p = strchr(str, '0');
if(p){
printf("find at %d\n", (int)(p - str));//find at 1
}
if(p=strchr(str, 0)){
printf("find at %d\n", (int)(p - str));//find at 4
}
str = "k\0kg";
if(p=strchr(str, 0)){
printf("find at %d\n", (int)(p - str));//find at 1
}
return 0;
}

How to remove a character from a string using baskspace in C?

can you give me an example of deleting characters from an array of characters in c?
I tried too much, but i didn't reach to what i want
That is what i did:
int i;
if(c<max && c>start) // c is the current index, start == 0 as the index of the start,
//max is the size of the array
{
i = c;
if(c == start)
break;
arr[c-1] = arr[c];
}
printf("%c",arr[c]);
A character array in C does not easily permit deleting entries. All you can do is move the data (for instance using memmove). Example:
char string[20] = "strring";
/* delete the duplicate r*/
int duppos=3;
memmove(string+duppos, string+duppos+1, strlen(string)-duppos);
You have an array of characters c:
char c[] = "abcDELETEdefg";
You want a different array that contains only "abcdefg" (plus the null terminator). You can do this:
#define PUT_INTO 3
#define TAKE_FROM 9
int put, take;
for (put = START_CUT, take = END_CUT; c[take] != '\0'; put++, take++)
{
c[put] = c[take];
}
c[put] = '\0';
There are more efficient ways to do this using memcpy or memmove, and it could be made more general, but this is the essence. If you really care about speed, you should probably make a new array that doesn't contain the characters you don't want.
Here's one approach. Instead of removing characters in place and shuffling the remaining characters (which is a pain), you copy the characters you want to keep to another array:
#include <string.h>
...
void removeSubstr(const char *src, const char *substr, char *target)
{
/**
* Use the strstr() library function to find the beginning of
* the substring in src; if the substring is not present,
* strstr returns NULL.
*/
char *start = strstr(src, substr);
if (start)
{
/**
* Copy characters from src up to the location of the substring
*/
while (src != start) *target++ = *src++;
/**
* Skip over the substring
*/
src += strlen(substr);
}
/**
* Copy the remaining characters to the target, including 0 terminator
*/
while ((*target++ = *src++))
; // empty loop body;
}
int main(void)
{
char *src = "This is NOT a test";
char *sub = "NOT ";
char result[20];
removeSubstr(src, sub, result);
printf("Src: \"%s\", Substr: \"%s\", Result: \"%s\"\n", src, sub, result);
return 0;
}
string = H E L L O \0
string_length = 5 (or just use strlen inside if you don't want to cache it outside this call
remove_char_at_index = 1 if you want to delete the 'E'
copy to the 'E' position (string + 1)
from the first 'L' position (string + 1 + 1)
4 bytes (want to get the NULL), so 5 - 1 = 4
remove_character_at_location(char * string, int string_length, int remove_char_at_index) {
/* Use memmove because the locations overlap */.
memmove(string+remove_char_at_index,
string+remove_char_at_index+1,
string_length - remove_char_at_position);
}

Resources