I am trying to make a function in C which will swap two string variables but something went wrong and the program crashes.
Please have a look at my code and tell me where I made a mistake:
#include <string.h>
void strswap(char name1[], char name2[]) // to swap two strings
{
int lengthname1, lengthname2;
lengthname1 = strlen(name1);
lengthname2 = strlen(name2);
char temporaryname1[100];
char temporaryname2[100];
int x;
int y;
// till just the declaration
for (int x = 0; x < lengthname1; lengthname1++) {
temporaryname1[x] = name1[x];
name1[x] = ' ';
}
// copying the value of name1 in temporaryname1
for (int y = 0; y < lengthname2; lengthname2++) {
temporaryname2[x] = name2[x];
name2[x] = ' ';
}
// copying the value of name2 in temporaryname2
for (int x = 0; x < lengthname1; lengthname1++) {
name1[x] = temporaryname2[x];
}
for (int y = 0; y < lengthname2; lengthname2++) {
name2[x] = temporaryname1[x];
}
}
#include <stdio.h>
int main()
{
char name[] = "hello";
char name2[] = "hi";
printf("before swapping: %s %s\n", name, name2);
strswap(name, name2);
printf("after swapping: %s %s\n", name, name2);
}
EDIT:- I have corrected the program and it is working properly. Soon my header file is going to work with some other modules. Thank you all for your help and especially to #Micheal
There are many issues:
First issue
The x variable is not initialized:
int x; int y; // first declaration of x
// till just the declaration
for(int x=0;x<lengthname1;lengthname1++)
{// ^ second declaration of x , local to the loop
temporaryname1[x]=name1[x];
name1[x]=' ';
}
// if you use x here it's the first x that has never been initialized
Second issue
This:
for (x = 0; x<lengthname1; lengthname1++)
should be:
for (x = 0; x<lengthname1 + 1; x++)
Why lengthname1 + 1 ? Because you need to copy the NUL char that terminates the string.
There are similar problems in your other for loops as well.
For example here you use y as loop variable, but in the loop you use x:
for (int y = 0; y<lengthname2 + 1; lengthname2++)
{
name2[x] = temporaryname1[x];
Third issue
In main you declare this:
char name[] = "hello";
char name2[] = "hi";
That is actually the same as
char name[6] = "hello"; // 5 chars for "hello" + 1 char for the terminating NUL
char name2[3] = "hi"; // 2 chars for "hi" + 1 char for the terminating NUL
Now even if your strswap is correct, you are trying to stuff the 6 bytes from the name array ("hello") into the 3 bytes array name2, there is not enough space in the name2 array. This is undefined behaviour.
And last but not least:
This is simply useless:
name1[x] = ' ';
And finally
You should ask yourself why you need two temporary strings (temporaryname1 and temporaryname2) in strswap() - one is enough.
void strswap(char ** name1, char ** name2)
{
char * name1_1 = malloc(strlen(*name2) + 1);
char * name2_1 = malloc(strlen(*name1) + 1);
strncpy(name1_1, *name2, strlen(*name2) + 1);
strncpy(name2_1, *name1, strlen(*name1) + 1);
*name1 = name1_1;
*name2 = name2_1;
}
int main()
{
char * name="hello";
char * name2="hi";
printf("before swapping %s %s\n",name,name2);
strswap(&name, &name2);
printf("after swapping %s %s\n",name,name2);
return 0;
}
Actually following is the safest way to swap two strings. In your cases, you were statically using strings of size 100 in size, which is not good and work in all case. Moreover, You tried to use ' ' instead of '\0' to mark end of string. String APIs uses '\0' to indicate that string has ended.
Related
First function changes big letter to small. In main I need to have five strings and with function konvertuj I have to go through that array and check for each letter if it's big and convert it to small. The point is that I don't know how to access each character of string in the function. (It's study example so it has to be done with these predefined functions.
char v2m(char z){
char m = z + 0x20;
return m;
}
void konvertuj(char **niz, int n){
for (int i = 0; i < n; i++)
if(*niz[i] > 'A' && *niz[i] < 'Z')
*niz[i] = v2m(*niz[i]);
}
int main(){
char **niz;
niz[0] = "Voda";
niz[1] = "KraISSa";
niz[2] = "somsssR";
niz[3] = "aaaaa";
niz[4] = "WeWeWeW";
for (int i = 0; i < 5; i++)
{
int d = -1;
while(niz[i][++d]);
konvertuj(&niz[i], d);
printf("%s ", niz[i]);
}
}
v2m - no need of the variable m
konvertuj no need to iterate through the same letters all over again. You want to convert 1 letter as you iterate in main. Your condition is wrong as you will ignore 'A' and 'Z'
Pointer to pointer does not have allocated space to accommodate 5 pointers. You need to allocate this space. In your code is it UB.
3.a You assign the pointers to the string literals. Attempt to modify the string literal invokes Undefined Behaviour. In my code, I use compound literals which are modifiable.
3.b use correct type for indexes (size_t).
char v2m(char z){
return z + 0x20;
}
void konvertuj(char *niz, size_t n){
if(niz[n] >= 'A' && niz[n] <= 'Z')
niz[n] = v2m(niz[n]);
}
int main(void){
char **niz = malloc(5 * sizeof((*niz)));
niz[0] = (char[]){"Voda"};
niz[1] = (char[]){"KraISSa"};
niz[2] = (char[]){"somsssR"};
niz[3] = (char[]){"aaaaa"};
niz[4] = (char[]){"WeWeWeW"};
for (size_t i = 0; i < 5; i++)
{
size_t d = 0;
while(niz[i][d])
konvertuj(niz[i], d++);
printf("%s ", niz[i]);
}
}
As I( understand you need to keep the function names types and parameters
Sure, it is possible to write it the way you did, but you have to build things accordingly and you did not.
And there some errors, anyway. I will try to show you some points. Please be patient.
niz[0] = "Voda";
niz[1] = "KraISSa";
niz[2] = "somsssR";
niz[3] = "aaaaa";
niz[4] = "WeWeWeW";
In C in general you can not just assign a value to a string. You use something like
strcpy( niz[0], "ANewValue");
v2m()
Instead of
char v2m(char z){
char m = z + 0x20;
return m;
}
You can just write
char v2m(char z) { return z + 0x20; }
There is no need to declare a char just for holding the return value.
IIUC you can not change the function prototypes...
konvertuj()
void konvertuj(char **niz, int n){
for (int i = 0; i < n; i++)
if(*niz[i] > 'A' && *niz[i] < 'Z')
*niz[i] = v2m(*niz[i]);
}
here I believe you missed the point that the function will receive just a string each time is called, not the whole vector of strings.
The int n is just the length of the string, and even if you could not use strlen() to compute it, it should probably be done inside the function.
but I believe you can not change this prototype also.
note that you are not including 'A' and 'Z' in your test. Maybe you should use '>=' and '<=' in the tests.
since the function gets a single string each call, you must remove many of the '*'
note that you had the strings declared as literals, CONSTANTS that you can not change. The first time you try to change a letter your program will abort
This one below should work and you can compare:
void konvertuj(char *niz, int n)
{
for (int i = 0; i < n; i++)
if(niz[i] >= 'A' && niz[i] <= 'Z')
niz[i] = v2m(niz[i]);
}
main()
Instead of
char **niz;
niz[0] = "Voda";
niz[1] = "KraISSa";
niz[2] = "somsssR";
niz[3] = "aaaaa";
niz[4] = "WeWeWeW";
You could write just
char niz[][15] =
{
"Voda",
"KraISSa",
"somsssR",
"aaaaa",
"WeWeWeW"
};
In C just the last dimension must be declared, e.g. the '15' above, since the compiler can determine here the other dimension. And this way you can initialize all of them directly. But in order to change one in the code you need to use a loop and replace letter by letter, or call
strcpy( niz[0], "ANewValue");
Also you can initialize just a few of them, and even out of order, as in
char niz[8][15] =
{
[2] = "somsssR",
[3] = "aaaaa",
[5] = "AomsssZ",
[6] = "A",
[0] = "Voda",
[1] = "KraISSa",
[4] = "WeWeWeW",
[7] = ""
};
and this is really handy.
Computing the number of strings
Note that you can compute the number of strings and even assign "TheLastValue" to the last one, by writing
int n = sizeof(niz)/sizeof(niz[0]); // total of strings
strcpy( niz[n-1], "TheLastValue"); // changes the last string
printf("Total of %llu values\n", sizeof(niz)/sizeof(niz[0]));
What if char** niz is needed?
This is a really common paradigm in C and C++, and it is very useful. You may recall that the prototype for main() is
int main( int argc, char** argc)
for every C program, so you can see how common it is.
Fact is that when you declare niz as char** you are declaring a single variable. What is niz? Well, it is a pointer to a pointer to a char.
niz is char**
*niz is char*
**niz is a single char
But niz is a pointer and it is pointing to nowhere when declared. In your case you want niz pointing to not one but FIVE strings. And if you do nothing the program will abort the first time you try to use it...
You need to build this:
A string is a pointer to the first char, char*
so niz needs to point to an area capable of holding 5 pointers to char
What about the size of a pointer to char? That is easy: sizeof(char*)
Then you need to make each niz[x] point to the required string.
It will not happen by itself. You must build each and every one.
An example: building char** sample from niz as declared above
The code below builds sample as an array of pointers, pointing to the same strings declared and allocated for niz[][] above, and them prints them all
// building an array of pointers to the strings in niz
char** sample = NULL; // ok, points to nothing
unsigned area = n * sizeof(char*); // n pointers to strings
sample = (char**) malloc(area);
for( int i=0; i<n; i+=1)
sample[i] = niz[i];
printf("\n=>\tPrinting the %d strings using the pointers\n", n );
for( int i=0; i<n; i+=1)
printf("%2d: '%s'\n", i, sample[i]);
Note that the strings already exists and we are just pointing to them. A new reference only.
A new example: building char** copy as a full copy of niz
It is very very important to see the difference here: copy points to an array of pointers, but each pointer points to a copy of the corresponding string declared in niz and referenced in the sample array.
// building 'copy' as an array of pointers to the strings once in niz
char** copy = NULL; // ok, points to nothing
copy = (char**) malloc(area);
for( int i=0; i<n; i+=1)
{
copy[i] = (char*) malloc( (1 + sizeof(niz[i])) * sizeof(char) );
// large enough to hold it
int j = 0; // copy each letter
for ( ; niz[i][j] != 0; j+=1 ) copy[i][j] = niz[i][j];
copy[i][j] = 0; // this terminates the string
}
printf("\n=>\tPrinting the %d copies using the pointers\n", n );
for( int i=0; i<n; i+=1)
printf("%2d: '%s'\n", i, copy[i]);
Note: it is in general not recommended to cast the pointers return by malloc() in C, as in the lines
copy = (char**) malloc(area);
// or
copy[i] = (char*) malloc( (1 + sizeof(niz[i])) * sizeof(char) );
I just do not care and prefer to write all them down explicitly, as a reminder to myself of what is what. Sure, in C++ you must declare this, but is is rare to allocate memory this way in C++ since C++11. Fell free to use whatever rule you see fit
A complete example
This is the output
PS C:\src\ifdef> gcc -o teste -Wall -Wextra -Wpedantic -std=c17 so210126.c
PS C:\src\ifdef> ./teste
Total of 8 values
Before: Voda (4)
After: voda
Before: KraISSa (7)
After: kraissa
Before: somsssR (7)
After: somsssr
Before: aaaaa (5)
After: aaaaa
Before: WeWeWeW (7)
After: wewewew
Before: AomsssZ (7)
After: aomsssz
Before: A (1)
After: a
Before: TheLastValue (12)
After: thelastvalue
=> Printing the 8 strings using the pointers
0: 'voda'
1: 'kraissa'
2: 'somsssr'
3: 'aaaaa'
4: 'wewewew'
5: 'aomsssz'
6: 'a'
7: 'thelastvalue'
=> Printing the 8 copies using the pointers
0: 'voda'
1: 'kraissa'
2: 'somsssr'
3: 'aaaaa'
4: 'wewewew'
5: 'aomsssz'
6: 'a'
7: 'thelastvalue'
PS C:\src\ifdef>
I compiled just on gcc 10.2 on Windows.
This is the example code
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char v2m(char z) { return z + 0x20; }
void konvertuj(char *niz, int n)
{
for (int i = 0; i < n; i++)
if(niz[i] >= 'A' && niz[i] <= 'Z')
niz[i] = v2m(niz[i]);
}
int main(void)
{
char niz[8][15] =
{
[2] = "somsssR",
[3] = "aaaaa",
[5] = "AomsssZ",
[6] = "A",
[0] = "Voda",
[1] = "KraISSa",
[4] = "WeWeWeW",
[7] = ""
};
int n = sizeof(niz)/sizeof(niz[0]); // total of strings
strcpy( niz[n-1], "TheLastValue"); // changes the last string
printf("Total of %llu values\n", sizeof(niz)/sizeof(niz[0]));
for (int i = 0; i < n; i++)
{
int d = 0;
while ( niz[i][d] != 0) d+=1;
printf("Before: %s (%d)\n", niz[i], d);
konvertuj( niz[i], d );
printf("After: %s\n", niz[i]);
}
// building an array of pointers to the strings in niz
char** sample = NULL; // ok, points to nothing
unsigned area = n * sizeof(char*); // n pointers to strings
sample = (char**) malloc(area);
for( int i=0; i<n; i+=1)
sample[i] = niz[i];
printf("\n=>\tPrinting the %d strings using the pointers\n", n );
for( int i=0; i<n; i+=1)
printf("%2d: '%s'\n", i, sample[i]);
// building 'copy' as an array of pointers to the strings once in niz
char** copy = NULL; // ok, points to nothing
copy = (char**) malloc(area);
for( int i=0; i<n; i+=1)
{
copy[i] = (char*) malloc( (1 + sizeof(niz[i])) * sizeof(char) ); // large enough to hold it
int j = 0; // copy each letter
for ( ; niz[i][j] != 0; j+=1 ) copy[i][j] = niz[i][j];
copy[i][j] = 0; // this terminates the string
}
printf("\n=>\tPrinting the %d copies using the pointers\n", n );
for( int i=0; i<n; i+=1)
printf("%2d: '%s'\n", i, copy[i]);
for( int i=0; i<n; i+=1) free(copy[i]); // destroy each string
free(copy); // destroy the array;
free(sample); // sample points to static memory...
return 0;
}
As for the very very long post: I wanted to leave an example of the
solution plus an example of the steps involved in order to build a char** vector from
existing strings and as an independend copy.
"Return a pointer to an array of two strings. The first is the characters
of string s that are at even indices and the second is the characters from
s that are at odd indices"
char **parity_strings(const char *s) {
char** parity = malloc(sizeof(char*) * 2);
char even_strings[] = "";
char odd_strings[] = "";
int x = 0;
int y = 0;
for (int i = 0; i < strlen(s); i++) {
if ((i % 2) == 0) {
even_strings[x] = s[i];
x++;
}
else {
odd_strings[y] = s[i];
y++;
}
}
parity[0] = even_strings;
parity[1] = odd_strings;
return parity;
}
int main(int argc, char **argv) {
char **r = parity_strings(argv[1]);
printf("%s %s %s", r[0], r[1], argv[1]);
return 0;
}
My logic makes sense but the output is always incorrect. For example, with input ababab I get back ababab while the expected output is aaa bbb ababab. What did I do wrong?
The string named even_strings is a local variable, so its memory will be freed after your function returns, so it is not valid to try to return a pointer to it to the caller.
Try changing this line:
char even_strings[] = "";
to something like this:
char * even_strings = malloc(some_size);
The same goes for your odd_strings string.
Also, be sure to pick a good value for some_size so that your program allocates enough memory for each string so that it can hold all the data you are writing to it.
even_strings and odd_strings are arrays of size 1 each. Your code writes out of bounds (even_strings[x] = s[i], odd_strings[y] = s[i]). Furthermore, they're local variables that cease to exist once parity_strings returns, so the returned pointers are garbage.
I try to put value of two integers into char array.
If I have:
x = 3;
y = 5;
then I want to have
links[0][0] = "3,5";
I have this code now, but I don't know how can I continue.
char** links = (char**) calloc(SRTM_SIZE, sizeof(char*));
if(links)
{
for(int i = 0; i < SRTM_SIZE; i++)
{
links[i] = (char*)calloc(SRTM_SIZE, sizeof(char));
//memset(links[i], 0, sizeof(*links[i] * SRTM_SIZE));
}
}
x = strtok(temp, ",");
y = strtok(NULL, ",");
int xx = atoi(x);
int yy = atoi(y);
//Some calculation with x and y and if it's okay, then I need to put value of x and y to array, but I don't know how
printf("%s\n", links[0][0]);
edited:
What exactly I need is matrix (propably 1201x1201) of strings. Into cells (not into all, but propably into most of them) I need put string values. This values can be from "0,0" to "1200, 1200". And later in program I need to acces to all cells with strings values, because each value is position of one of adjacent cells.
use sprintf
sprintf(links[0][0],"%d,%d",x,y);
but before change links[0][0] to string(char*)
"3,5" is string not a character.
more info http://www.cplusplus.com/reference/cstdio/sprintf/
links[0][0] is of single byte. You can store only 1 byte to it ,i.e, a single character. These two characters would store into the two different memory location, say, link[0][0] and link[0][1]. Then you also need a \0 character to use %s to print them.
The statement
printf("%s\n", links[0][0]);
is wrong %s is used for strings but links[0][0] is a char.
You can do this as
sprintf(links[0], "%d,%d", xx,yy);
printf("%s\n", links[0]);
Test code after changes:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define SRTM_SIZE 5
int main(void){
char** links = (char**) calloc(SRTM_SIZE, sizeof(char*));
if(links)
{
for(int i = 0; i < SRTM_SIZE; i++)
{
links[i] = (char*)calloc(SRTM_SIZE, sizeof(char));
//memset(links[i], 0, sizeof(*links[i] * SRTM_SIZE));
}
}
char temp[5]="2,3";
char *x = strtok(temp, ","); //strtok() returns pointer to char.
char *y = strtok(NULL, ",");
int xx = atoi(x);
int yy = atoi(y);
sprintf(links[0], "%d,%d", xx,yy);
//Some calculation with x and y and if it's okay, then I need to put value of x and y to array, but I don't know how
printf("%s\n", links[0]);
}
#include <stdio.h>
#include <stdlib.h>
int main(void){
int len;
int x = 3, y = 5;
len = snprintf(NULL, 0, "%d,%d", x, y);
char *link = malloc(len + 1);
sprintf(link, "%d,%d", x, y);
printf("%s\n", link);
free(link);
return 0;
}
You can't assign a value to a 2D array the way you do it. This is how it works:
arr[0][0]= x;
arr[0][0] refers to a single location, that is row 0, and column 0.
If you have arr[2][2], you will have to specify where you want to put your value in the 2D array. If you want it in the first row, at the last column:
arr[0][2]= x;
You may visualize a 2D array as follows:
int arr[3][2]:
column 0 column 1
row 0 |arr[0][0]| |arr[0][1]|
row 1 |arr[1][0]| |arr[0][1]|
row 2 |arr[2][0]| |arr[0][1]|
I wanted to try and copy parts of strings which are already stored in one array of strings to another empty array. (I think called array of pointers to char arrays )
I would like to copy the first 3 characters of each string and store them in the second array and then print them out - like so
AAA
BBB
CCC
DDD
EEE
FFF
Here is my code.
void main()
{
/*ARRAY 1*/
char *line1 = "AAAAA";
char *line2 = "BBBBB";
char *line3 = "CCCCC";
char *line4 = "DDDDD";
char *line5 = "EEEEE";
char *line6 = "FFFFF";
char *array1[6];
array1[0] = line1;
array1[1] = line2;
array1[2] = line3;
array1[3] = line4;
array1[4] = line5;
array1[5] = line6;
int i;
char *array_main[6];
for(i = 0; i<6 ; i++ ) {
array_main[i] = ("%*.*s\n",1,3,array1[i]);
printf("%s", array_main[i]);
printf("\n");
}
}
do i need to do a malloc here ? (for array_main[i]) from what i understand, I am basically just copying the address of the particular characters to array_main's elements.
EDIT - Sorry, I should have made this clearer, I want to collect the strings in array_main and then print them in order outside of the loop which actually copies the data.
You are copying pointers to statically declared strings to an array. That's theoretically fine. Howevery, you want to cut off the remainder of the strings, so you need to prepare memory for the target strings, because if you write to the strings you will invoke undefined behaviour.
This line:
array_main[i] = ("%*.*s\n",1,3,array1[i]);
definitely doesn't do what you want though. I think this shouldn't even compile.
You loop over the array and malloc the appropriate size of bytes (3+1), then copy over the parts of the string that you want (don't forget the 0-byte at the end).
So it should look like this:
for(i = 0; i < 6; i++)
{
array_main[i] = malloc(4);
snprintf(array_main[i], 4, "%.3s", array[i]);
printf("%s\n", array_main[i]);
free(array_main[i]);
}
A simpler version (with unneccessary memeory overhead) would be this:
for(i = 0; i < 6; i++)
{
array_main[i] = strdup(array[i]);
array_main[i][3] = 0;
printf("%s\n", array_main[i]);
free(array_main[i]);
}
#include <stdio.h>
#include <string.h>
int main(void){
const char *array1[6] = {"AAAAA", "BBBBB", "CCCCC", "DDDDD", "EEEEE", "FFFFF" };
char array_main[6][4] = {{0}};//4 : 3 + 1 (+1 for End of string('\0'))
int i;
for(i = 0; i<6 ; i++ ) {
strncpy(array_main[i], array1[i], 3);
printf("%s\n", array_main[i]);
}
return 0;
}
AFunc changes what was sent to it, and the printf() outputs the changes:
void AFunc ( char *myStr, int *myNum )
{
*myStr = 's';
*myNum = 9;
}
int main ( int argc, char *argv[] )
{
char someString = 'm';
int n = 6;
AFunc(&someString, &n);
printf("%c" "%d", someString, n);
}
But what if the string was more than one char? How would the code look differently? Thanks for any help.
If it were a "string" instead of a char, you would do something like this:
#include <stdio.h>
void AFunc (char *myStr, int *myNum) {
myStr[0] = 'p'; // or replace the lot with strcpy(myStr, "pax");
myStr[1] = 'a';
myStr[2] = 'x';
myStr[3] = '\0';
*myNum = 9;
}
int main (void) {
char someString[4];
int n = 6;
AFunc(someString, &n);
printf("%s %d", someString, n);
return 0;
}
which outputs:
pax 9
A "string" in C is really an array of characters terminated by the \0 (NUL) character.
What the above code does is to pass in the address of the first character in that array and the function populates the four characters starting from there.
In C, a pointer to char isn't necessarily a string. In other words, just because you have char *x;, it doesn't mean that x is a string.
To be a string, x must point to a suitably allocated region which has a 0 in it somewhere. The data from the first character that x points to and up to the 0 is a string. Here are some examples of strings in C:
char x[5] = {0}; /* string of length 0 */
char x[] = "hello"; /* string of length 5, the array length being 6 */
char *x = "hello"; /* string of length 5. x is a pointer to a read-only buffer of 6 chars */
char *x = malloc(10);
if (x != NULL) {
strcpy(x, "hello"); /* x is now a string of length 5. x points
to 10 chars of useful memory */
}
The following are not strings:
char x[5] = "hello"; /* no terminating 0 */
char y = 1;
char *x = &y; /* no terminating 0 */
So now in your code, AFunc's first parameter, even though is a char * isn't necessarily a string. In fact, in your example, it isn't, since it only points to a memory that has one useful element, and that's not zero.
Depending upon how you want to change the string, and how the string was created, there are several options.
For example, if the myStr points to a writable memory, you could do something like this:
/* modify the data pointed to by 'data' of length 'len' */
void modify_in_place(char *data, size_t len)
{
size_t i;
for (i=0; i < len; ++i)
data[i] = 42 + i;
}
Another slightly different way would be for the function to modify data until it sees the terminating 0:
void modify_in_place2(char *data)
{
size_t i;
for (i=0; data[i]; ++i)
data[i] = 42 + i;
}
You are only dealing with chars and char pointers. None of the char pointers are valid strings as they are not null terminated.
Try defining a string and see what it looks like.
But what if the string was more than one char? How would the code look
differently? Thanks for any help
Ofcourse, you would modify the other characters as well, but in the exact same way you did the first time.
Declare a char array and pass its address
Modify values at those address
A char array would be a more clear term for a string.