Why following code snippets assignment gives confusing output? - c

I'm studying C. I came across with string arrays. I'm bit confused about the following codes. I was anticipating one kind of output; however, getting completely different kind of output or program crush due to read access violation.
I've run this code on visual studio 2017, with _CRT_SECURE_NO_WARNINGS
// case 1
char* name[2];
//name[0] = (char*)malloc(sizeof(char*) * 10);
//name[1] = (char*)malloc(sizeof(char*) * 10);
name[0] = "john";
name[1] = 'doe';
printf("%s\n", name[0]); // prints john
//printf("%s\n", name[1]); // gives read access violation exception, why??? even with dynamically allocated memory
// case 2
char* name2[2] = { "emma", "olsson" };
printf("%s\n", name2[0]); // prints emma
printf("%s\n", name2[1]); // prints olsson, why no error???
// case 3
for (int i = 0; i < 2; i++)
{
name[i] = name2[i];
}
printf("%s\n", name[0]); // prints emma
printf("%s\n", name[1]); // prints olsson, why no error???
// case 4
char inputName[10];
int i = 0;
while (i < 2)
{
fgets(inputName, sizeof(inputName), stdin); // first input: Max second input: Payne
char* pos = strchr(inputName, '\n');
if (pos != NULL)
*pos = '\0';
name[i++] = inputName;
}
printf("%s\n", name[0]); // prints Payne, why not Max???
printf("%s\n", name[1]); // prints Payne

For case 1, 'doe' is not a string.
Case 2 works because you are initializing you pointers with string literals.
Case 3 works too because you assign the same initialized pointer in case 2 to case 1 pointers. Your name array pointers are basically set to point to where name2 ones are pointing.
In case 4, you declared inputName which points to a set of 10 chars. Then each time you get a new input you are writing it to the same memory section. And by doing this:name[i++] = inputName;
you are not copying a new char array to name[i] as you might think. Instead, you are telling name[i] char pointer to point to inputName. So it is normal that name prints last input twice, because that's what inputName points to, as well as both name char pointers.

It is unclear whether OP's code runs within main() or a user-defined function and what kind of value returns. That said, after removing superfluous variable redeclarations, here's how I achieved working code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void) {
char * name[2];
char * name2[2]={ "emma", "olsson" };
char inputName[10];
char names[BUFSIZ];
int i = 0;
// case 1
name[0] = "john";
name[1] = "doe";
printf("%s %s\n", name[0],name[1]); //john doe
// case 2
printf("%s %s\n", name2[0],name2[1]);//emma olsson
// case 3
for (i = 0; i < 2; i++){
name[i] = name2[i];
}
printf("%s %s\n", name[0],name[1]);//emma olsson
// case 4
i=0;
while (fgets(inputName, sizeof(inputName), stdin) != NULL && (i < 2) ){
strcat(names,inputName);
i++;
}
printf("\n%s\n",names);
return 0;
}
See live code here
OP should replace the single quotes around doe with double quotes which denote a null-terminated string. Single quotes are meant for a single character, i.e. 'a' refers to a byte value while "a" signifies a string containing two characters, an 'a' and a '\0'.
Also, OP should include two other libraries to facilitate execution. In particular, string.h is needed for the built-in string functions to execute properly.
Case 2 and Case 3 work because strings are encompassed by double quotes instead of single quotes. Note that in each case the "%s" format specifier for the printf() indicates that a string needs to be displayed.
In last case, fgets() with respect to stdin, upon success returns user input as a string. But that input will be overridden in the while loop, unless in each iteration you concatenate the old input with the new. Otherwise, when the inputName element values change because its address remains constant, only the latest input string displays. Here's some code that illustrates this point:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void) {
char * name[2];
char inputName[10];
int i = 0;
while (fgets(inputName, sizeof(inputName), stdin) != NULL && (i < 2) ){
printf("inputName: %p points to: %s",inputName,inputName);
name[i++] = inputName;
}
printf("\n name[0]: %p points to: %s\n name[1]: %p points to: %s",name[0],name[0],name[1],name[1]);
return 0;
}
Output:
inputName: 0x7fff8a511a50 points to: Maxine
inputName: 0x7fff8a511a50 points to: Pauline
name[0]: 0x7fff8a511a50 points to: Pauline
name[1]: 0x7fff8a511a50 points to: Pauline
See live code.
Incidentally, you don't need an array to display the names and indeed one may display the names outside of the loop as long as within the loop the code concatenates user input.

Related

Appending chars into a String in C with a for loop

I'm still a newbie to C so please forgive me if anything below is wrong. I've searched this up online but nothing really helped.
Right now, I have the following code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void appendStr (char *str, char c)
{
for (;*str;str++); // note the terminating semicolon here.
*str++ = c;
*str++ = 0;
}
int main(){
char string[] = "imtryingmybest";
char result[] = "";
for(int i = 0; i < strlen(string); i++){
if(i >= 0 && i <= 3){
appendStr(result, string[i]);
}
}
printf("%s", result);
}
Basically, I'm trying to add the first 4 characters of the String named string to result with a for loop. My code above did not work. I've already tried to use strcat and strncat and neither of them worked for me either. When I used
strcat(result, string[i]);
It returns an error saying that the memory cannot be read.
I know that in this example it might have been easier if I just did
appendStr(result, string[0]);
appendStr(result, string[1]);
appendStr(result, string[2]);
appendStr(result, string[3]);
But there is a reason behind why I'm using a for loop that couldn't be explained in this example.
All in all, I'd appreciate it if someone could explain to me how to append individual characters to a string in a for loop.
The following code doesnt use your methods but successfully appends the first 4 chars to result
#include <stdio.h>
#include <string.h>
int main()
{
// declare and initialize strings
char str[] = "imtryingmybest";
char result[5]; // the 5th slot is for \0 as all strings are null terminated
// append chars to result
strncat(result, str, 4);
// ^ ^ ^
// | | |- number of chars to be appended
// | | - string to be appended from
// | - string to append to
// print string
printf("result: %s\n", result);
return (0);
}
The result of the above is as wanted:
>> gcc -o test test.c
>> ./test
result: imtr
Let me know if anything is not clear so i can elaborate further
string was ruined by the overflow of result buffer.
appendStr can be executed only once. next time strlen(string) will return 0. because *str++ = 0; has been written to the space of string.
result buffer has only 1 byte space, but you write 2 byte to it in appendStr call.
the second byte will ruin string space.
I suggest debug with gdb.
try to get rid of Magic numbers
#define BUFF_SIZE 10 // define some bytes to allocate in result char array
#define COPY_COUNT 4 // count of chars that will be copied
int main(){
char string[] = "imtryingmybest";
char result[BUFF_SIZE] {}; // allocate some chunk of memory
for(size_t i = 0; i < strlen(string); i++){
if(i < COPY_COUNT){
appendStr(result, string[i]);
}
}
printf("%s", result);
}
I showed the solution code Paul Yang showed the problem
As others have pointed out the code has a simple mistake in the allocation of the destination string.
When declaring an array without specifying its size, the compiler deduces it by its initializer, which in your case means a 0 + the NULL character.
char result[] = ""; // means { '\0' };
However, I think that the bigger issue here is that you're effectively coding a Schlemiel.
C strings have the serious drawback that they don't store their length, making functions that have to reach the end of the string linear in time complexity O(n).
You already know this, as shown by your function appendStr()
This isn't a serious issue until start you appending characters or strings in a loop.
In each iteration of your loop appendStr() reaches the last character of the string, and extends the string, making the next iteration a little slower.
In fact its time complexity is O(n²)
Of course this is not noticeable for small strings or loops with few iterations, but it'll become a problem if the data scales.
To avoid this you have to take into account the growing size of the string.
I modified appendStr() to show that now it starts from the last element of result
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void appendStr (char *str, char c, char *orig)
{
printf("i: %ld\n", str - orig);
for (; *str; str++); // note the terminating semicolon here.
*str++ = c;
*str++ = 0;
}
int main()
{
char string[32] = "imtryingmybest";
char result[32] = "";
for(int i = 0; i < strlen(string); i++) {
if(i >= 0 && i <= 3) {
// I'm passing a pointer to the last element of the string
appendStr(&result[i], string[i], result);
}
}
printf("%s", result);
}
You can run it here https://onlinegdb.com/HkogMxbG_
More on Schlemiel the painter
https://www.joelonsoftware.com/2001/12/11/back-to-basics/
https://codepen.io/JoshuaVB/pen/JzRoyp

How to return empty string from a function in C?

How should I return an empty string from a function? I tried using lcp[i] = ' ' but it creates an error. Then I used lcp[i] = 0 and it returned an empty string. However, I do not know if it's right.
Also, is it necessary to use free(lcp) in the caller function? Since I could not free and return at the same time.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_LEN 50
char *find_LCP(char str1[], char str2[]);
char *find_LCP(char str1[], char str2[]){
char * lcp = malloc(MAX_LEN * sizeof(char));
int a = strlen(str1);
int b = strlen(str2);
int min = a < b ? a : b;
for(int i = 0; i < min; i++){
if(str1[i] == str2[i])
lcp[i] = str1[i];
else
lcp[i] = 0;
}
return lcp;
}
int main()
{
char str1[MAX_LEN], str2[MAX_LEN];
char * lcp;
printf("Enter first word > ");
scanf("%s", str1);
printf("Enter second word > ");
scanf("%s", str2);
lcp = find_LCP(str1, str2);
printf("\nLongest common prefix: '%s'\n", lcp);
free(lcp);
return 0;
}
An "empty" string is just a string with the first byte zero, so you can write:
s[0] = 0;
However, it is not clear what you are trying to do. The LCP of "foo" and "fob" is "fo", not the empty string.
You can also return as soon as you find the first non-matching character, no need to go until the end.
Further, you can simply pass the output string as a parameter and have lcp be an array. That way you avoid both malloc and free:
char lcp[MAX_LEN];
...
find_LCP(lcp, str1, str2);
If you want to empty a string without using a for loop then you can do
lcp[0] = 0
but for emptying a string it was right the way you did using a for loop.
There are plenty other ways of emptying the string word by word using for loop:
lcp[i] = '\0';
and it's the right way to make string empty as letter by letter you trying to do using for loop
But if you are not using some loops and simply empty a string then you can do this.
memset(buffer,0,strlen(buffer));
but this will only work for zeroing up to the first NULL character.
If the string is a static array, you can use:
memset(buffer,0,sizeof(buffer));
Your program has a bug: If you supply two identical strings, lcp[i] = 0; never executes which means that your function will return a string which is not NUL-terminated. This will cause undefined behvaior when you use that string in your printf in main.
The fix for this is easy, NUL-terminate the string after the loop:
int i;
for (i = 0; i < min; i++){
if(str1[i] == str2[i])
lcp[i] = str1[i];
else
break;
}
lcp[i] = 0;
As for the answer to the question, an empty string is one which has the NUL-terminator right at the start. We've already handled that as we've NUL-terminated the string outside the loop.
Also, is it necessary to use free(lcp) in the caller function?
In this case, it is not required as the allocated memory will get freed when the program exits, but I'd recommend keeping it because it is good practice.
As the comments say, you can use calloc instead of malloc which fills the allocated memory with zeros so you don't have to worry about NUL-terminating.
In the spirit of code golf. No need to calculate string lengths. Pick any string and iterate through it until the current character either null or differs from the corresponding character in the other string. Store the index, then copy appropriate number of bytes.
char *getlcp(const char *s1, const char *s2) {
int i = 0;
while (s1[i] == s2[i] && s1[i] != '\0') ++i;
char *lcp = calloc((i + 1), sizeof(*lcp));
memcpy(lcp, s1, i);
return lcp;
}
P.S. If you don't care about preserving one of input strings then you can simplify the code even further and just return the index (the position of the last character of the common prefix) from the function, then put '\0' at that index into one of the strings.

Assigning value to pointer correctly in C using strcpy()

I need to take only the odd values from a char array and copy them into correctly sized dynamic memory using a pointer.
However when running my program it works correctly with certain input strings and not with others. Is there something that I'm doing wrong? I can't seem to figure out what's going on.
/* A.) Include the necessary headers in our program */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_STRING_LENGTH 32
int main() {
/* B.) Declare char array with inital size of 32 */
char input_string[MAX_STRING_LENGTH];
/* C.) Recieve user input.
Can save the first 31 characters in the array with 32nd reserved for '\0' */
printf("Enter a string of characters: ");
/* D.) Using the technique we discussed to limit the string to 31 charaters */
scanf("%31s", input_string);
printf("\n");
/* Will be used to determine the exact amount of dynamic memory that will be allocated later */
int odd_value_count = 0;
printf("Odd Characters: ");
for(int i = 0; i < strlen(input_string); i++) {
if(i % 2 != 0) {
printf("%c ", input_string[i]);
odd_value_count++;
}
}
printf("\n");
printf("Odd value count: %d\n", odd_value_count);
/* E.) Delecaring the pointer that will hold some part of the input_string
Pointer will be a char type */
char *string_pointer;
/* G.) Allocating the space before the copy using our odd value count */
/* H.) The exact amount of space needed is the sizeof(char) * the odd value count + 1 */
string_pointer = (char *)malloc(sizeof(char) * (odd_value_count + 1));
if (string_pointer == NULL) {
printf("Error! Did not allocte memory on heap.");
exit(0);
}
/* F.) Copying all charcters that are on the odd index of the input_string[] array
to the memory space pointed by the pointer we delcared */
printf("COPIED: ");
for (int i = 0; i < strlen(input_string); ++i) {
if(i % 2 != 0) {
strcpy(string_pointer++, &input_string[i]);
printf("%c ", input_string[i]);
}
}
/* Printing out the string uses the pointer, however we must subtract odd_value_count to
position the pointer back at the original start address */
printf("\n%s\n", string_pointer - odd_value_count);
return 0;
}
This input string: 01030507
works fine and copies & prints: 1357
The input string: testing
Copies etn but prints etng.
I cant figure out why for some strings it prints out the extra character at the end when I never even copy the value over.
You need to Null Terminate your string, like this *string_pointer = '\0';, just after you are done copying the odd characters in your string pointer - after that loop, null terminate your string.
Read more in How to add null terminator to char pointer, when using strcpy?
In the end of your routine you will need to null terminate the string, otherwise you don't have a string you just have a char array, you can use string_pointer which is already pointing to one past the end of the string you want to save:
//...
for (int i = 0; i < strlen(input_string); ++i) {
if(i % 2 != 0) {
strcpy(string_pointer++, &input_string[i]);
//as you are copying characters, you can do this:
//*string_pointer++ = input_string[i];
//instead of strcpy
printf("%c ", input_string[i]);
}
}
*string_pointer = '\0'; // <-- here
//...

I/O - Manipulation of C Strings

I'd like to iterate through a string (entered by the user), returning the inputted string with an added space after each character (i.e. "Hello" --> "H e l l o ".
If I preset the value for str (i.e. char str[] = "Hello";) then the desired result is printed ("H e l l o "), but not so with user input (i.e. If the user inputs "Hello" the output is "H"). How does one successfully extract and manipulate a C string based on user input?
#include <stdio.h>
#include <string.h>
int main()
{
char str[] = "";
printf("\nEnter a string: ");
scanf("%s", &str);
printf("\nYou typed: %s \n", str);
int i = 0;
char newstr[150] = "";
for (i = 0; i < strlen(str); i++)
{
newstr[2*i] = str[i];
newstr[2*i+1] = ' ';
}
newstr[2 * strlen(str)] = '\0';
printf("\nExpanded String: ");
printf("%s", newstr);
return 0;
}
Here:
char str[] = "";
the size of str is inferred from the initializer, which is in this case one byte large. Thus str cannot hold a string larger than one byte, and since the zero-terminator is one byte large, there is no more space for a payload. A fix is to specify a size:
char str[1024] = "";
Now str has enough space for a kilobyte of data, or 1023 characters in addition to the terminator. The size is deliberately chosen to be much larger than the input you expect.
In addition to this, it would be a good idea to prevent scanf from writing past the end of the buffer by including the size in the format string. That is
scanf("%1023s", str); // now scanf will not read more than 1023 bytes plus sentinel.
...and in turn, it would be a good idea to increase the size of newstr accordingly (to twice that of str), i.e.
char newstr[2047]; // 2 * 1023 + terminator
...or, you know, make str smaller, depending on how long a string you want to support.
Thanks to Cool Guy for catching the superfluous & and newstr size implications.
"How does one successfully extract and manipulate a C string based on user input?"
You can use getchar() instead.
For example, you can store the user input in an array first. Then the problem becomes the same as if you did your 'char str[] = "Hello":
int index = 0
while((temp1 = getchar())!= '\n'){
str[index++] = temp1;
}
the following code
-complies cleanly
-checks and handles errors
-does the job
-doesn't use unneeded memory
(well actually) the logic could be a loop
that reads one char, outputs char, outputs space
or something similar if a trailing space is a problem
then the input buffer could be a single character
#include <stdio.h>
#include <stdlib.h> // exit, EXIT_FAILURE
#include <string.h>
int main()
{
// char str[] = "";
// there actually has to be room for the string
char str[100] = {'\0'};
printf("\nEnter a string: ");
if( 1 != scanf("%s", str) ) // arrays degenerate to pointer so no extra '&' needed
{ // then scanf failed
perror( "scanf failed" );
exit( EXIT_FAILURE );
}
// implied else, scanf successful
printf("\nYou typed: %s \n", str);
// there is no need to keep the modified string in memory
// when all that will be done is print it
int i = 0; // loop counter
printf("\nExpanded String: ");
for (i = 0; i < strlen(str); i++)
{
printf("%c", str[i]);
if( i < (strlen(str)-1) )
{ // then another char will follow
printf( " " );
}
else
{
printf( "\n" );
} // end if
} // end for
return 0;
} // end function: main

How to extract a substring from a string in C?

I tried using strncmp but it only works if I give it a specific number of bytes I want to extract.
char line[256] = This "is" an example. //I want to extract "is"
char line[256] = This is "also" an example. // I want to extract "also"
char line[256] = This is the final "example". // I want to extract "example"
char substring[256]
How would I extract all the elements in between the ""? and put it in the variable substring?
Note: I edited this answer after I realized that as written the code would cause a problem as strtok doesn't like to operate on const char* variables. This was more an artifact of how I wrote the example than a problem with the underlying principle - but apparently it deserved a double downvote. So I fixed it.
The following works (tested on Mac OS 10.7 using gcc):
#include <stdio.h>
#include <string.h>
int main(void) {
const char* lineConst = "This \"is\" an example"; // the "input string"
char line[256]; // where we will put a copy of the input
char *subString; // the "result"
strcpy(line, lineConst);
subString = strtok(line,"\""); // find the first double quote
subString=strtok(NULL,"\""); // find the second double quote
printf("the thing in between quotes is '%s'\n", subString);
}
Here is how it works: strtok looks for "delimiters" (second argument) - in this case, the first ". Internally, it knows "how far it got", and if you call it again with NULL as the first argument (instead of a char*), it will start again from there. Thus, on the second call it returns "exactly the string between the first and second double quote". Which is what you wanted.
Warning: strtok typically replaces delimiters with '\0' as it "eats" the input. You must therefore count on your input string getting modified by this approach. If that is not acceptable you have to make a local copy first. In essence I do that in the above when I copy the string constant to a variable. It would be cleaner to do this with a call to line=malloc(strlen(lineConst)+1); and a free(line); afterwards - but if you intend to wrap this inside a function you have to consider that the return value has to remain valid after the function returns... Because strtok returns a pointer to the right place inside the string, it doesn't make a copy of the token. Passing a pointer to the space where you want the result to end up, and creating that space inside the function (with the correct size), then copying the result into it, would be the right thing to do. All this is quite subtle. Let me know if this is not clear!
if you want to do it with no library support...
void extract_between_quotes(char* s, char* dest)
{
int in_quotes = 0;
*dest = 0;
while(*s != 0)
{
if(in_quotes)
{
if(*s == '"') return;
dest[0]=*s;
dest[1]=0;
dest++;
}
else if(*s == '"') in_quotes=1;
s++;
}
}
then call it
extract_between_quotes(line, substring);
#include <string.h>
...
substring[0] = '\0';
const char *start = strchr(line, '"') + 1;
strncat(substring, start, strcspn(start, "\""));
Bounds and error checking omitted. Avoid strtok because it has side effects.
Here is a long way to do this: Assuming string to be extracted will be in quotation marks
(Fixed for error check suggested by kieth in comments below)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(){
char input[100];
char extract[100];
int i=0,j=0,k=0,endFlag=0;
printf("Input string: ");
fgets(input,sizeof(input),stdin);
input[strlen(input)-1] = '\0';
for(i=0;i<strlen(input);i++){
if(input[i] == '"'){
j =i+1;
while(input[j]!='"'){
if(input[j] == '\0'){
endFlag++;
break;
}
extract[k] = input[j];
k++;
j++;
}
}
}
extract[k] = '\0';
if(endFlag==1){
printf("1.Your code only had one quotation mark.\n");
printf("2.So the code extracted everything after that quotation mark\n");
printf("3.To make sure buffer overflow doesn't happen in this case:\n");
printf("4.Modify the extract buffer size to be the same as input buffer size\n");
printf("\nextracted string: %s\n",extract);
}else{
printf("Extract = %s\n",extract);
}
return 0;
}
Output(1):
$ ./test
Input string: extract "this" from this string
Extract = this
Output(2):
$ ./test
Input string: Another example to extract "this gibberish" from this string
Extract = this gibberish
Output(3):(Error check suggested by Kieth)
$ ./test
Input string: are you "happy now Kieth ?
1.Your code only had one quotation mark.
2.So the code extracted everything after that quotation mark
3.To make sure buffer overflow doesn't happen in this case:
4.Modify the extract buffer size to be the same as input buffer size
extracted string: happy now Kieth ?
--------------------------------------------------------------------------------------------------------------------------------
Although not asked for it -- The following code extracts multiple words from input string as long as they are in quotation marks:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(){
char input[100];
char extract[50];
int i=0,j=0,k=0,endFlag=0;
printf("Input string: ");
fgets(input,sizeof(input),stdin);
input[strlen(input)-1] = '\0';
for(i=0;i<strlen(input);i++){
if(input[i] == '"'){
if(endFlag==0){
j =i+1;
while(input[j]!='"'){
extract[k] = input[j];
k++;
j++;
}
endFlag = 1;
}else{
endFlag =0;
}
//break;
}
}
extract[k] = '\0';
printf("Extract = %s\n",extract);
return 0;
}
Output:
$ ./test
Input string: extract "multiple" words "from" this "string"
Extract = multiplefromstring
Have you tried looking at the strchr function? You should be able to call that function twice to get pointers to the first and second instances of the " character and use a combination of memcpy and pointer arithmetic to get what you want.

Resources