I am trying to get just the phone number out of the string passed into getPhoneNumber(char[] str), but for some reason, i get some random character appended to it each time i run the code, please i need help.
source code
#include <stdio.h>
#include <string.h>
char* getPhoneNumber(char str[]);
int main(){
getPhoneNumber("AT+CMGR=5 \n+CMGR: \"REC READ\",\"+9349036332058\",\"samuel\",\"17/03/31,20:44:52+04\"\nHOW THINS fa OK");
return 0;
}
char* getPhoneNumber(char str[]){
char *temp = strchr(str, ',')+2;
const unsigned short len1 = strlen(temp);
printf("value in temp : %s\n\n",temp);
char *strPtr = strchr(temp, '\"');
const unsigned short len2 = strlen(strPtr);
printf("value in strPtr : %s\n\n",strPtr);
int phone_num_len = len1-len2;
char phone_num[phone_num_len];
strncpy(phone_num, temp,phone_num_len);
printf("Phone number : %s",phone_num);
}
I also printed out individual values of temp and strPtr for debugging purposes, but the returned values seems ok.
The output of the program is shown in the image below.
You're not setting aside enough space for phone_num. As a result, printf is reading past the end of the array. This invokes undefined behavior. That is why you see extra characters when running locally but it appears to work fine on ideone (it also appears to run fine for me).
You need one more byte for the null terminating character for the string. Also, you need to manually add that null terminator since the strncpy function won't do it for you since there's no null terminator within phone_num_len bytes of temp.
char phone_num[phone_num_len+1];
strncpy(phone_num, temp,phone_num_len);
phone_num[phone_num_len] = '\0';
From the man page for strncpy(char * dst, const char * src, size_t len):
If src is less than len characters long, the remainder of dst is filled with `\0' characters. Otherwise, dst is not terminated.
So it is not, as you seem to expect, terminating the "string" you are copying.
Related
I am trying to add integers to a string. When I debug my code everything works perfectly fine, but when i run it normally two unwanted characters are being printed at the beginning of the string. How do I avoid this?
int number_of_ints = 5;
char s[number_of_ints*2];
char suffix[4];
for(int i = 1; i <= number_of_ints; i++){
snprintf(suffix, number_of_ints, "%d*", i);
strncat(s, suffix, 2);
printf("%s\n", s);
}
This is the output when building and running the code normally.
`û1*
`û1*2*
`û1*2*3*
`û1*2*3*4*
`û1*2*3*4*5*
Strings in C are a sequence of nonzero bytes followed by a terminating byte with a value of zero (the null-terminating byte, '\0').
You must size your buffer to have an additional space, to guarantee room for this null-terminating byte.
You must additionally make sure the contents of the buffer contain a valid string. You can do this by setting the first element of the buffer to the null-terminating byte, creating a zero-length string.
Failing to initialize the contents of your buffer means it will contain indeterminate values, and passing such a buffer to a function expecting a valid string will invoke Undefined Behavior.
The second argument to snprintf should be, at most, the size of the destination buffer.
Finally, consider using size_t when applicable, as it is the appropriate type for dealing with memory sizes (e.g., sizing variable-length arrays; the sizeof operator resolves to this type; snprintf expects this type as its second argument).
#include <stdio.h>
#include <string.h>
int main(void) {
size_t number_of_ints = 5;
char s[number_of_ints * 2 + 1];
char suffix[4];
s[0] = '\0';
for (size_t i = 1; i <= number_of_ints; i++) {
snprintf(suffix, sizeof suffix, "%zu*", i);
strncat(s, suffix, 2);
printf("%s\n", s);
}
}
You have a few issues with initialization and size of your buffers.
The size of your buffer is too short by 1 byte that is needed for 0-termination. Adding the last number causes buffer overrun and undefined behaviour.
In addition the calculated size is only sufficient as long as number_of_ints<10 because it only allows for single digit numbers.
That buffer is not initialized and us very likely not holding an empty string. Accessing it (via strcat etc.) invokes undefined behaviour.
The size you provide to snprintf is not related to the size of the buffer.
You should apply these changes:
#include <stdio.h>
#include <string.h>
int main(void)
{
int number_of_ints = 5;
char s[number_of_ints*2+1];
char suffix[4];
s[0] = 0;
for (int i = 1; i <= number_of_ints; i++)
{
snprintf(suffix, sizeof(suffix), "%d*", i);
strncat(s, suffix, 2);
printf("%s\n", s);
}
}
This subprogram takes three user inputs: a text string, a path to a file, and a 1 digit flag. It loads the file into a buffer, then appends both the flag and the file buffer, in that order, to a char array that serves as a payload. It returns the payload and the original user string.
I received a bug where some of my string operations on the file buffer, flag, and payload appeared to corrupt the memory that the user_string was located in. I fixed the bug by swapping strcat(flag, buffer) to strcpy(payload, flag), (which is what I intended to write originally), but I'm still perplexed as to what caused this bug.
My guess from reading the documentation (https://www.gnu.org/software/libc/manual/html_node/Concatenating-Strings.html , https://www.gnu.org/software/libc/manual/html_node/Concatenating-Strings.html) is that strcat extends the to string strlen(to) bytes into unprotected memory, which the file contents loaded into the buffer copied over in a buffer overflow.
My questions are:
Is my guess correct?
Is there a way to reliably prevent this from occurring? Catching this sort of thing with an if(){} check is kind of unreliable, as it doesn't consistently return something obviously wrong; you expect a string of length filelength+1 and get a string of filelength+1.
bonus/unrelated: is there any computational cost/drawbacks/effects with calling a variable without operating on it?
/*
user inputs:
argv[0] = tendigitaa/four
argv[1] = ~/Desktop/helloworld.txt
argv[2] = 1
helloworld.txt is a text file containing (no quotes) : "Hello World"
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <string.h>
int main (int argc, char **argv) {
char user_string[100] = "0";
char file_path[100] = "0";
char flag[1] = "0";
strcpy(user_string, argv[1]);
strcpy(file_path, argv[2]);
strcpy(flag, argv[3]);
/*
at this point printfs of the three declared variables return the same as the user inputs.
======
======
a bunch of other stuff happens...
======
======
and then this point printfs of the three declared variables return the same as the user inputs.
*/
FILE *file;
char * buffer = 0;
long filelength;
file = fopen(file_path, "r");
if (file) {
fseek(file, 0, SEEK_END);
filelength = ftell(file);
fseek(file, 0, SEEK_SET);
buffer = malloc(filelength);
printf("stringcheck1: %s \n", user_string);
if (buffer) {
fread(buffer, 1, filelength, file);
}
}
long payloadlen = filelength + 1;
char payload[payloadlen];
printf("stringcheck2: %s \n", user_string);
strcpy(payload, flag);
printf("stringcheck3: %s \n", user_string);
strcat(flag, buffer);
printf("stringcheck4: %s \n", user_string); //bug here
free(buffer);
printf("stringcheck5: %s \n", user_string);
payload; user_string; //bonus question: does this line have any effect on the program or computational cost?
return 0;
}
/*
printf output:
stringcheck1: tendigitaa/four
stringcheck2: tendigitaa/four
stringcheck3: tendigitaa/four
stringcheck4: lo World
stringcheck5: lo World
*/
note: taking this section out of the main program caused stringcheck 4 to segfault instead of returning "lo World". The behavior was otherwise equivalent.
strcat does exactly what documentation says:
char *strcat(char *restrict s1, const char *restrict s2); The
strcat() function shall append a copy of the string pointed to by s2
(including the terminating null byte) to the end of the string pointed
to by s1. The initial byte of s2 overwrites the null byte at the end
of s1. If copying takes place between objects that overlap, the
behavior is undefined.
s1 has to have enough memory allocated to accommodate both strings plus the terminating nul
The linked article is about programming own string concatenating functions. How to write such a function depends on the application - which is stated there. There are many ways.
In your program the destination char array is not big enough and the result is an Undefined Behaviour and it is not even big enough to accommodate a single character string.
I strongly advice to learn some C strings basics.
If you want safer strcat you can write your own one for example:
char *mystrcat(const char *str1, const char *str2)
{
char *dest = NULL;
size_t str1_length, str2_length;
if(str1 && str2)
{
dest = malloc((str1_length = strlen(str1)) + (str2_length = strlen(str2)) + 1);
if(dest)
{
memcpy(dest, str1, str1_length);
memcpy(dest + str1_length, str2, str2_length);
}
}
return dest;
}
But for the safety we always pay the price - the code is longer and less efficient. C language was designed to be as efficient as possible sacrificing the safety and introducing the idea if the Undefined Behaviour.
You can't store a non-empty string in a 1-character array. A string needs room for the string contents and a null terminator.
So when you declare
char flag[1] = "1";
you've only allocated one byte, which contains the character 1. There's no null terminator.
Using this with any string functions will result in undefined behavior, because they look for the null terminator to find the end of the string.
strcat(flag, buffer) will search for the null terminator, which will be outside the array, and then append buffer after that. So this clearly causes a buffer overflow when writing.
strcpy(payload, flag) is also wrong. It will look for a null terminator after the flag bytes to know when to stop copying to payload, so it will copy more than just flag (unless there happens to be a null byte after it).
You can resolve the strcpy() problem by increasing the size:
char flag[2] = "1";
You can also leave the size empty, the compiler will make it large enough to hold the string that initializes it, including the null byte:
char flag[] = "1";
The line that causes the problem is because strcat() is trying to cram buffer into flag which is only one character long and you haven't allocated any more space to fit buffer.
If you want to put buffer into flag, I recommend using realloc() to increase the length of flag to include the length of buffer.
Also the only thing you ever print is user_string. I'm not sure if you're trying to print the other string you're working with.
int main(int argc, char** argv) {
char data[1024];
data[0] = '\0';
for(int i = 1; i < argc; i++){
strcpy(data+strlen(data), (argv[i] + 1));
}
strcpy(data+strlen(data), data+strlen(data)/2);
printf(data);
return 0;
}
As you can see this is my code so far. What I'm trying to do is: Remove first letter from every argument, concat them into data and after the loop take half of the resulting string and concat it again, then print it. Example:
Calling the program with the arguments hello, world and yes should print:
elloorldesrldes
it works until strcpy(data+strlen(data), data+strlen(data)/2);. Here I try to take half of the string (data) and concat it to the end of the same string. When I leave that part out I get the result elloorldes but when I put it in, instead of giving me the expected results I get the error RUN FAILED (exit value -1.073.741.819, total time: 4s), however I'm not sure why that's the case.
You cannot do this
strcpy(data+strlen(data), data+strlen(data)/2);
because strcpy cannot handle cases when memory overlaps.
man strcpy
char *strcpy(char *dest, const char *src);
DESCRIPTION
The strcpy() function copies the string pointed to by src, including the terminating null byte ('\0'),
to the buffer pointed to by dest. The strings may not overlap, and the destination string dest must be large enough to receive the copy.
You need to use memmove for this, which handles memory overlap:
size_t oldsize = strlen(data);
size_t size = oldsize/2;
memmove(data+oldsize, data+size, size);
data[oldsize + size] = 0;
Also don't do printf(data) with content provided by the user. Let's say the
passed arguments are hello, world%d, then data will contain %d and
printf would yield undefined behaviour, because there are arguments missing.
You should do this:
printf("%s\n", data);
or
puts(data);
Here's my code
#include <stdio.h>
#include <string.h>
int main(){
char pal[8] = "ciaooaic";
char pal1[7] = "ciaoaic";
int lenPal = strlen(pal);
int lenPal1 = strlen(pal1);
printf("strlen('%s'): %d\n", pal, lenPal);
printf("strlen('%s'): %d\n", pal1, lenPal1);
return 0;
}
The problem is that when I run this code the output is:
strlen('ciaooaicP#'): 11
strlen('ciaoaic'): 7
The first string has also another non-printable char between P and #. I'm a noob, so maybe I missed something obvious. Can someone help me?
edit:
just give one extra space like char pal[9] = "ciaooaic"; char pal1[8] = "ciaoaic";
It works, but why? I understand that there should be a space for \0, but "ciaoaic" works without it...
1. You don't leave room for a null terminator, as you pass them to strlen(), therefore your code exhibits undefined behaviour -
char pal[8] = "ciaooaic";
char pal1[7] = "ciaoaic";
Leave a space for '\0'. Declare and initialize like this -
char pal[9] = "ciaooaic";
char pal1[8] = "ciaoaic";
2. And strlen() returns size_t not int , so write like this -
size_t lenPal = strlen(pal);
size_t lenPal1 = strlen(pal1);
and use %zu specifier to print both these variables.
You have not kept space for the NULL terminating character \0.
Either increase the size of the array by 1
char pal[9] = "ciaooaic";
char pal1[8] = "ciaoaic";
OR
Do not specify the length at all
char pal[] = "ciaooaic";
char pal1[] = "ciaoaic";
Both the above answers are sufficient to solve your doubts.
Increase the the length of both pal and pal1 by one as there there is no space for the assignment of the null character( '\0') at the end.
However there is small trick to print the non null terminated character using printf
printf("strlen('%.*s'): %d\n",8, pal, lenPal);
printf("strlen('%.*s'): %d\n",7, pal1, lenPal1);
Link for the above trick:BRILLIANT
I have to compare few characters of string say from 2nd char till 4th character( counting starts from zero)
The string is stored in elements of structure say zoopla->real
for example zoopla ->real has '447889036' where real is of type char real[20];
Also please note I cant use function strnstr.
The code works as expected but just for curiousity, I have added printf statement and it shows me value till 4th cahr and then some garabe characters.
I want to know why the printf statment is showing 2 extra garabe values?
char * copyTemp;
char *strptr;
copyTemp = (char *)malloc(sizeof(char)*6);
strncpy(copyTemp, zoopla->real, 5);
printf("the string copied is %s", copyTemp); // debug statemnt
strptr = strstr(copyTemp, "666");
if(strptr != NULL)
{
//some other function
}
else
//some other function
free(copyTemp);
All criticism and suggestions are welcome
It seems to me that copyTemp is not null terminated. That's why printf shows you garbage characters after the characters you put in there. It doesn't know where to stop so it continues iterate through memory.
Add
copyTemp[5] = '\0';
after strncpy.
See this example from the documentation of strncpy:
/* strncpy example */
#include <stdio.h>
#include <string.h>
int main ()
{
char str1[]= "To be or not to be";
char str2[6];
strncpy (str2,str1,5);
str2[5]='\0';
puts (str2);
return 0;
}
see
http://www.cplusplus.com/reference/clibrary/cstring/strncpy/
No null-character is implicitly appended to the end of destination, so destination will only be null-terminated if the length of the C string in source is less than num.
you have to add null your self.
if you will be allocating memory of constant size then use array only.
#include <stdio.h>
#include <string.h>
int main ()
{
char * copyTemp;
char *strptr;
copyTemp = (char *)calloc(sizeof(char),6);
strncpy(copyTemp, "88666782921", 5);
printf("the string copied is %s", copyTemp); // debug statemnt
strptr = strstr(copyTemp, "666");
if(strptr != NULL)
{
//some other function
}
else
//some other function
free(copyTemp);
return 0;
}
According to my old K&R, strncpy will only implicitly add null bytes if the source string has fewer characters than the number to be copied.
In this case, zoopla->real has more than 5 characters, so the function is simply copying the first five characters. Since you haven't initialized the memory to zero, or explicitly added a null byte, the string is not terminated after the fifth character. So when you print the string, you get additional bytes with essentially random values, until one is hit that happens to be zero.