Why tolower() affecting other string? - c

Why output of this program is always:
example
example
If i change first line with second in for loop, then output will look like this:
EXAMPLE
EXAMPLE
What i am doing wrong?
string key = "EXAmple";
string ukey = key;
string lkey = key;
for (int i = 0; i < strlen(key); i++)
{
ukey[i] = toupper(key[i]);
lkey[i] = tolower(key[i]);
}
printf("%s\n", ukey);
printf("%s\n", lkey);

The definition of string is likely to be char*. Consequently, key, ukey and lkey are actually pointers pointing to exactly the same memory; they are just aliases for the same thing.

Here, ukey and lkey are likely both pointers to the same array in memory. In C, an array reference is just a pointer to the first item in the array, and using the [] operator just returns the values at each position of the array (dereferenced).
So, ukey and lkey both refer to the exact same characters.
Sounds like you want to use strcpy() instead of ordinary assignment, or the equivalent for your custom type string.
Or use C++ and its string type.

Related

Referencing a variable to an existing array

I'm pretty new to C and starting to play with pointers. I haven't found a way to assign an array to multiple variables.
What I want ideally is:
char myArray[10] = "test";
char (*p)[10] = &myArray;
char anotherArray[10];
anotherArray = *p;
This doesn't work and I don't know why.
I have found a way to "copy" the array by using a for loop,
for (int i = 0; i < 10; i++)
{
anotherArray[i] = myArray[i];
}
I don't know if it's good practice to do it and if there is an easier way.
The array content is not supposed to change so I just want to have a simple way to do this:
firstArr[size] = "content";
secondArr = firstArr;
You can't assign arrays in C, neither by itself nor by dereferencing pointers to arrays, the syntax simply doesn't allow it.
Arrays are normally copied with memcpy. In case they are strings, you can also use strcpy, which copies up until it finds the string null terminator.
In your example, this would be strcpy(anotherArray, *p);. But to use an array pointer of type char (*)[10] is a bit weird practice, it is far more common to use a pointer to the first element of the array. I would recommend that you change your code to this:
#include <stdio.h>
#include <string.h>
int main(void)
{
char input[10] = "test";
char* p = input;
char anotherArray[10];
strcpy(anotherArray, p);
puts(anotherArray);
}
You can't assign an array to multiple variables, but you can assign multiple variables to point to an array.
Pointers are all about memory and the memory that they point to.
Statements such as this assign a fixed amount of memory (10 char sized bytes of memory) to the variable myArray and initialises the contents to contain "test1".
char myArray[10] = "test1";
By definition myArray is actually a pointer to the first memory location, which in this case holds a char of value 't', but it is fixed to that memory.
You can define another pointer to type char and assign it the same value as the pointer to the memory that holds the data "test1" - thus:
char *secondPtr = myArray;
Now secondPtr and myArray both point to the same memory, which contains "test1". There aren't two copies of the data, but it may appear so if you did
printf("myArray %s", myArray);
printf("secondPtr %s", secondPtr);
Now you can use either myArray or secondPtr to alter the same data, which is why pointers should be treated with care.
Now as secondPtr is just a pointer to a char and as such it isn't fixed in the same way that myArray is, so you can do this:
char myArray2[10] = "test2";
secondPtr = myArray;
printf("secondPtr %s", secondPtr);
secondPtr = myArray2;
printf("secondPtr %s", secondPtr);
To copy data from one array to another you can use memcpy, which will copy a specified number of bytes(octets) of memory from one location to another.
The same process is performed by a loop (this is basic code, but not really the best way of performing it as there are no checks on the size of the arrays nor on the number of loop iterations)e.g.
for(int i=0; i<10; i++)
{
myArray2[i] = myArray[i];
}
this can also be:
secondPtr = myArray2;
for(int i=0; i<10; i++)
{
myArray2[i] = secondPtr +i;
}

How to put strings from a file into an array in c

So I have this code:
char inte[10];
while(j<noinput) {
fscanf(circuit,"%s",inte);
vararray[count]=inte;
count++;
j++;
}
However when I print the contents of the array like this:
for (h=0;h<noinput+2;h++){
printf("%dth variable: %s\n",h,vararray[h]);
}
The elements past the first two (which are reserved for special elements) are all equal to the LAST string that I had taken in from fscanf earlier. I have no idea how one of the strings from fscanf could be equal to multiple slots in the array when I am only setting
vararray[count]=inte;
Shouldn't this mean that each element of the array will be different since I am incrementing count every time? I am so confused. I also tried doing:
fscanf(circuit,"%s",vararray[count]);
But this also did not work and gave me null elements for certain indexes.
you are doing something too wrong. By "vararray[count]=inte;" you are doing pointer assignment so all of your vararray is getting filled by same string. I am guessing you are new to C so I will answer due to that. Correct way would look something like below
Fixed size solution:
char vararray[ROWCOUNT][BUFFERSIZE];
for(count=0; j<noinput; ++count, ++j) {
fscanf(circuit,"%s",(char*)vararray[count]);
}
With dynamic memory management
char * vararray[ROWCOUNT];
for(count=0; j<noinput; ++count, ++j) {
vararray[count] = (char*)malloc(BUFSIZE);
fscanf(circuit,"%s", vararray[count]);
}
I want to warn you in the way of becoming an expert on C nowadays is somewhat madness , i mean unless you have another choice. Examples below I put and the thing you wrote are completely unsafe and unsecure...
You're not copying the string. Here's what's happening:
char *vararray[462]; // declare an array of string pointers
char inte[10]; // declare a char array (to function as a string)
for (int i = 0; i < 462; i += 1) {
// do something
vararray[i] = inte;
}
This is causing all of the items of vararray to point to the memory also referred to as inte... but you're overwriting that each time! Instead, do something like this:
#include <string.h> // write me at the top, outside main()!
char vararray[462][10]; // declare an array of strings (max length 9)
char inte[10]; // declare a char array (to function as a string)
for (int i = 0; i < 462; i += 1) {
fscanf(circuit,"%10s",inte); // use buffer size to make xscanf safer
strncpy(vararray[i], inte, 9); // copy inte, making sure not to buffer overflow!
vararray[i][9] = '\0'; // if inte is too big, a null byte won't be added to the end of the string; make sure that it's there
}
This copies the string! Your problem should go away when you do this.

C string array, assigning and passing etc

I have been rethinking my way of asking. so i edited the question.
i know beforehand how many strings there will be in the array because it is menu text.
suppose i have an array of strings declared as so:char *menu_item[4];
this should give me an array that can hold 4 strings right?
i want to be able to pass the string array to other functions so is this the way to do it?
This array is not declared in main. but in a function that is called from main.
will i have to allocate memory to use fx strcpy(menu_item[1],"some text");
and if yes. what should i allocate??
or is menu_item[0] = "some text"okay??
i have a function in a function to print out the strings which takes a char *string as parameter. and the function itself takes a string array as so char *items[] it looks like this:
void scroll_menu(char *items[], int size){
for(int i = 0; i < size; i++){
print_out(items[i]);
}
}
is the parameter correct for a string array?
i have been looking through a lot of question online. and cant seem to find anything that solves my problem.
if any doubt i will recap what it is i want:
i want to declare an array of strings which holds a known number of strings. sometimes the strings can be initialized in the declaration of the array. and other times i have to look up somewhere and then "assign" or copy the result to the array.
i want to be able to copy or assign strings to it from functions returning a char *string like so strcpy(menu_item[0], some_function_returning_string());
my problem is that i have tried so many different things that i am left confused. and have misunderstood the string array operations.
i have also tried with char menu_items[4][20]; and then strcpy(menu_items[0], "some text"); without any luck. and then there is the issue with how to make the function accept an array declared like this.
any suggestions on how to accomplish what i want would be very nice.
EDIT
i took some time reading the c programming book and found what i was looking for.
if i declare an array of pointers to strings as so char *menu_items[4] i will have an array that can take 4 pointers to strings or char arrays char *string
if i want to assign a string from a function returning a char * i have a function as so:
char *function_returning_string(int x){
static char *strings[3] = {"this","is","strings"};
if(x <= 2){
return strings[0];
}
else if(x > 2){
return string[1];
}
else{
return strings[2];
}
}
the code from where i call this function i have the following:
static char *other_strings = {"yes", "no"};
char *menu_item[3];
menu_item[0] = "ok";
menu_item[1] = other_strings[0];
menu_item[2] = function_returning_string(3);
then i can just pass the entire string array to functions that takes a *string_array[] as parameter as so function_takin_string_array(menu_item); or any string inside to functions taking char *string as parameter as so function_taking_string(menu_item[2]);
the code compiles without errors and works. if anybody think there is something wrong about the code or if have have misunderstood something please let me know.
As MFisherKDX noted this part of a code is incorrect:
static char *addr;
sprintf(addr, "S %d", i + 1);
return addr;
How do you think what are you returning here? It should be failed on sprintf() call because you try to assign some value to unallocated memory. It should be like this:
static char addr[128];
sprintf(addr, "S %d", i + 1);
return addr;
And how PeterJ_01 mentioned above try to use gdb to figure out what is wrong and where you have other mistakes.

C : Lvalue required error when assigning to string

I made a simple structure with both integer and char types, I am facing an Lvalue required error when assigning "Structures" to my LE structure string. I don't understand why because that's normally how I would assign a string.
#include<stdio>
#include<conio>
struct Lesson{
int lessonNumber;
char lessonName[80];
}LE;
main(){
LE.lessonName = "Structures";
LE.lessonNumber = 1;
printf("%s",LE.lessonName);
printf("%d",LE.lessonNumber);
getch();
}
One easy way to go about is (If you don't want to call strcpy):
#include<stdio.h>
struct Lesson{
int lessonNumber;
char *lessonName;
}LE;
int main(void){
LE.lessonName = "Structures";
LE.lessonNumber = 1;
printf("%s",LE.lessonName);
printf("%d",LE.lessonNumber);
}
Here lessonName is a pointer and not an array. With the assignment operator here: LE.lessonName = "Structures", you are assigning the address of where the string "Structures" is stored to LE.lessonName.
i don't understand why. because thats normally how i would assign a
string
There are a couple of things to keep in mind here. If you declare lessonName as an array (as you have done), you should keep in mind that an array is not something you can assign to. What you can assign to is a specific place / index in an array using the = operator. Thus you could build your c-string character-by-character or, you could call the strcpy function to copy a string character-by-character (including the \0) to lessonName.
When you use a pointer (char *lessonName) and say something like LE.lessonName = "Structure", this piece of string can't be modified. You can't do LE.lessonName[0] = 'g'. Of course you could modify LE.lessonName to point to some other string later on like LE.lessonName = "cat";.

C: passing arrays to another method properly

/*
* PURPOSE
* Search if a string contains a string and print it out from there
*/
#include <stdio.h>
void searchHaystack(char cHaystack[], char cNeedle[]);
void showResult(int iOffset, char cHaystack[]);
int main() {
// Declarations
char cHaystack[50], cNeedle[50];
// Input
puts("Haystack:");
gets(cHaystack);
puts("Needle:");
gets(cNeedle);
// Call searcher
searchHaystack(cHaystack, cNeedle);
return 0;
}
void searchHaystack(char cHaystack[], char cNeedle[]) {
// Declarations
int iCntr, iCntr2, iFoundOffset;
// Search the haystack for the first letter of the needle
for (iCntr == 0; iCntr < 50 && cHaystack[iCntr] != '\0'; iCntr++) {
if (cHaystack[iCntr] == cNeedle[0]) {
iFoundOffset = iCntr;
for (iCntr2 == 1; iCntr2 < 50 && (cHaystack[iCntr+iCntr2] == cNeedle[iCntr2] || cNeedle[iCntr2] == '\0'); iCntr2++) {
if (cNeedle[iCntr2] == '\0') {
showResult(iFoundOffset, cHaystack);
}
}
}
}
}
void showResult(int iOffset, char cHaystack[]) {
int iCntr;
// Print the substring char by char
for (iCntr == iOffset; iCntr < 50 && cHaystack[iCntr] != '\0'; iCntr++) {
printf("%c", cHaystack[iCntr]);
}
printf("\n");
}
Looking at my debugger I noticed that cHaystack[] and cNeedle[] aren't passed to searchHaystack properly as only the first char is conserved. How do I fix this? I haven't learned about pointers yet.
Also, I'm getting this warning on all three for loops:
statement with no effect
What's up with that?
Actually, the entire array IS being passed, the debugger only shows the first char by default because in C, the system does not know the size of an array. It is something the program has to keep track of. Since you are using strings though, which are typically null terminated, try setting the watch variable "(char*)cHaystack" (without quotes) and see what the debugger shows then.
Also, assignment statements should have one = sign, not the double == sign. So:
for (iCntr = 0; ...
Should be used, NOT:
for (iCntr == 0; ...
Same with the other for loops.
You're starting the loop with iCntr == 0
This is a comparison, so it does not set iCntr to zero.
Use iCntr = 0 (a single equals sign)
The values are passed properly, but your expectation of how your debugger should display them is incorrect. As already mentioned, there is no string type in C. Instead, C uses char* variables -- pointers to characters; your char[] are equivalent to char*.
You know that the pointed-to character is the first character in a longer string, but the debugger doesn't. It displays the character that the pointer points to -- which you know to be the first of a longer string. The debugger, however, only knows it's a char*, and there must be a char to be pointed at, so it displays that char.
These are character arrays not strings. In C string are of type char * and you have to allocate the memory for them.
Of course when you say varname[5] that is the same as saying *(varname+5)
Basically you are going to have to learn about pointers to use strings in C.
EDIT
As pointed out below (and above by me) you can use character arrays like strings in C. HOWEVER, my point is that if you don't learn a little bit about pointers you are going to be in big trouble.
For example:
Not being able to view the string in the debugger.
Not putting a null as the last character in the array and having crazy random bugs
Forgetting that you only allocated X bytes for the array and going over the end
etc.
If you don't understand how pointers work in C, it is really hard -- if not impossible to work with the language.
I expect the prof will cover it next week.
Arrays are not first-class objects in C; when you pass an array as a function parameter, the type of the array expression is implicitly converted from "N-element array of T" to "pointer to T", and its value is set to point to the first element in the array[1].
In the context of a function parameter declaration, int a[] is the same as int *a (but this is true only in the context of a function parameter declaration); your searchHaystack function receives two pointers to char, which correspond to the first elements of the respective arrays. The debugger doesn't show you the whole array, because in the context of the function they are not arrays.
Also, NEVER, NEVER, NEVER USEgets(). Ever. It will introduce a point of failure in your code. Use fgets() instead. C does no bounds checking on arrays. If you call gets() for a buffer sized to hold 10 characters, and the user types in 100 characters, gets() will happily store those extra 90 characters in the memory following your buffer, potentially clobbering something important and leading to a crash or worse (buffer overruns are a common exploit for malware; the Morris worm exploited a call to gets() in sendmail).
The warning is coming from you using == instead of = to assign your loop counters.
The exceptions to this rule are when the array expression is an operand of either the sizeof or address-of (&) operators, or when the array is a string literal being used to initialize another array in a declaration.
The warning is probably caused by
iCntr == 0,iCntr2 == 1, iCntr == iOffset
I guess you were going, in fact, for:
iCntr = 0,iCntr2 = 1, iCntr = iOffset
As for passing the arrays, you could do something like ( using pointers ):
void searchHaystack(char* cHaystack, int cHaystackSize, char* cNeedle, int cNeedleSize )
...
for (iCntr = 0; iCntr < cHaystackSize && cHaystack[iCntr] != '\0'; ++iCntr )

Resources